bostrat-node 1.9.4 → 1.9.5

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.
Files changed (2) hide show
  1. package/dist/index.js +167 -167
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,52 +1,52 @@
1
- var IO=Object.defineProperty;var q=(e,t,n)=>()=>{if(n)throw n[0];try{return e&&(t=e(e=0)),t}catch(r){throw n=[r],r}};var Ap=(e,t)=>{for(var n in t)IO(e,n,{get:t[n],enumerable:!0})};import{createHash as $O,randomBytes as RO,timingSafeEqual as OO}from"node:crypto";function Zy(){return RO(32).toString("hex")}function La(e){let t=typeof e=="string"?e.trim():"";return t?$O("sha256").update(t).digest("hex"):null}function Qy(e,t){return typeof e!="string"||typeof t!="string"||e.length!==t.length||!e?!1:OO(Buffer.from(e),Buffer.from(t))}function Fa(e,t={},{now:n=Date.now(),log:r=console.warn}={}){if(Ep.set(e,(Ep.get(e)||0)+1),_p.has(e)&&n-_p.get(e)<CO)return!1;_p.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=${Ep.get(e)}${o?` ${o}`:""}`),!0}async function eb(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 Un,Hn,Ep,_p,CO,ds=q(()=>{Un="BOSTRAT_HOOK_TOKEN",Hn="x-bostrat-hook";Ep=new Map,_p=new Map,CO=6e4});import $t from"node:fs/promises";import tb from"node:os";import At from"node:path";import{execFile as MO}from"node:child_process";import{promisify as NO}from"node:util";function al(){return/^(1|true|yes|on)$/i.test(process.env.BOSTRAT_CLAUDE_USE_API_KEY||"")&&process.env.ANTHROPIC_API_KEY?.trim()||null}function PO(){return process.env.CLAUDE_CONFIG_DIR?At.join(process.env.CLAUDE_CONFIG_DIR,".claude.json"):At.join(tb.homedir(),".claude.json")}function DO(){return process.env.CLAUDE_CONFIG_DIR?At.join(process.env.CLAUDE_CONFIG_DIR,"settings.json"):At.join(tb.homedir(),".claude","settings.json")}async function yr(e){if(!e||typeof e!="string")return;let t=At.resolve(e),n=PO(),r=DO(),o={};try{o=JSON.parse(await $t.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 $t.mkdir(At.dirname(n),{recursive:!0}),await $t.writeFile(n,JSON.stringify(o,null,2));let i={};try{i=JSON.parse(await $t.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 "${Hn}: $${Un}" --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 $t.mkdir(At.dirname(r),{recursive:!0}),await $t.writeFile(r,JSON.stringify(i,null,2)),await jO(t)}async function jO(e){try{let t=At.resolve(e),n=At.join(t,".bostrat","memory","claude"),r=At.join(t,".claude","settings.local.json"),o={};try{o=JSON.parse(await $t.readFile(r,"utf8"))}catch{}let s=o.autoMemoryDirectory,a=typeof s=="string"&&s.includes(At.join(".bostrat","memory"));if(s&&!a||s===n)return;o.autoMemoryDirectory=n,await $t.mkdir(n,{recursive:!0}),await $t.mkdir(At.dirname(r),{recursive:!0}),await $t.writeFile(r,JSON.stringify(o,null,2)),await BO(t,["/.claude/settings.local.json"])}catch{}}async function BO(e,t){try{let{stdout:n}=await NO(MO)("git",["-C",e,"rev-parse","--git-path","info/exclude"]),r=At.resolve(e,n.trim()),o=await $t.readFile(r,"utf8").catch(()=>""),s=t.filter(a=>!o.split(`
1
+ var $O=Object.defineProperty;var q=(e,t,n)=>()=>{if(n)throw n[0];try{return e&&(t=e(e=0)),t}catch(r){throw n=[r],r}};var Ep=(e,t)=>{for(var n in t)$O(e,n,{get:t[n],enumerable:!0})};import{createHash as RO,randomBytes as OO,timingSafeEqual as CO}from"node:crypto";function Zy(){return OO(32).toString("hex")}function La(e){let t=typeof e=="string"?e.trim():"";return t?RO("sha256").update(t).digest("hex"):null}function Qy(e,t){return typeof e!="string"||typeof t!="string"||e.length!==t.length||!e?!1:CO(Buffer.from(e),Buffer.from(t))}function Fa(e,t={},{now:n=Date.now(),log:r=console.warn}={}){if(_p.set(e,(_p.get(e)||0)+1),Ip.has(e)&&n-Ip.get(e)<MO)return!1;Ip.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=${_p.get(e)}${o?` ${o}`:""}`),!0}async function eb(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 Un,Hn,_p,Ip,MO,ds=q(()=>{Un="BOSTRAT_HOOK_TOKEN",Hn="x-bostrat-hook";_p=new Map,Ip=new Map,MO=6e4});import $t from"node:fs/promises";import tb from"node:os";import At from"node:path";import{execFile as NO}from"node:child_process";import{promisify as PO}from"node:util";function al(){return/^(1|true|yes|on)$/i.test(process.env.BOSTRAT_CLAUDE_USE_API_KEY||"")&&process.env.ANTHROPIC_API_KEY?.trim()||null}function DO(){return process.env.CLAUDE_CONFIG_DIR?At.join(process.env.CLAUDE_CONFIG_DIR,".claude.json"):At.join(tb.homedir(),".claude.json")}function BO(){return process.env.CLAUDE_CONFIG_DIR?At.join(process.env.CLAUDE_CONFIG_DIR,"settings.json"):At.join(tb.homedir(),".claude","settings.json")}async function yr(e){if(!e||typeof e!="string")return;let t=At.resolve(e),n=DO(),r=BO(),o={};try{o=JSON.parse(await $t.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 $t.mkdir(At.dirname(n),{recursive:!0}),await $t.writeFile(n,JSON.stringify(o,null,2));let i={};try{i=JSON.parse(await $t.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 "${Hn}: $${Un}" --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 $t.mkdir(At.dirname(r),{recursive:!0}),await $t.writeFile(r,JSON.stringify(i,null,2)),await jO(t)}async function jO(e){try{let t=At.resolve(e),n=At.join(t,".bostrat","memory","claude"),r=At.join(t,".claude","settings.local.json"),o={};try{o=JSON.parse(await $t.readFile(r,"utf8"))}catch{}let s=o.autoMemoryDirectory,a=typeof s=="string"&&s.includes(At.join(".bostrat","memory"));if(s&&!a||s===n)return;o.autoMemoryDirectory=n,await $t.mkdir(n,{recursive:!0}),await $t.mkdir(At.dirname(r),{recursive:!0}),await $t.writeFile(r,JSON.stringify(o,null,2)),await LO(t,["/.claude/settings.local.json"])}catch{}}async function LO(e,t){try{let{stdout:n}=await PO(NO)("git",["-C",e,"rev-parse","--git-path","info/exclude"]),r=At.resolve(e,n.trim()),o=await $t.readFile(r,"utf8").catch(()=>""),s=t.filter(a=>!o.split(`
2
2
  `).includes(a));if(!s.length)return;await $t.mkdir(At.dirname(r),{recursive:!0}),await $t.appendFile(r,(o&&!o.endsWith(`
3
3
  `)?`
4
4
  `:"")+s.join(`
5
5
  `)+`
6
- `)}catch{}}var Ua=q(()=>{ds()});import Ip from"node:fs/promises";import LO from"node:os";import il from"node:path";function FO(){let e=process.env.CODEX_HOME||il.join(LO.homedir(),".codex");return il.join(e,"config.toml")}function nb(e){return`[projects."${e}"]`}function UO(e,t){let n=nb(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 ps(e){if(!e||typeof e!="string")return;let t=il.resolve(e),n=FO(),r="";try{r=await Ip.readFile(n,"utf8")}catch{}if(UO(r,t))return;let o=nb(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*$/,"")}
6
+ `)}catch{}}var Ua=q(()=>{ds()});import $p from"node:fs/promises";import FO from"node:os";import il from"node:path";function UO(){let e=process.env.CODEX_HOME||il.join(FO.homedir(),".codex");return il.join(e,"config.toml")}function nb(e){return`[projects."${e}"]`}function HO(e,t){let n=nb(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 ps(e){if(!e||typeof e!="string")return;let t=il.resolve(e),n=UO(),r="";try{r=await $p.readFile(n,"utf8")}catch{}if(HO(r,t))return;let o=nb(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 Ip.mkdir(il.dirname(n),{recursive:!0}),await Ip.writeFile(n,r)}catch(s){console.warn(`[codex-config] could not seed folder trust for ${t}: ${s?.message||s}`)}}var cl=q(()=>{});import rb from"node:fs/promises";import HO from"node:os";import Ha from"node:path";function WO(e){let n=Ha.resolve(e).slice(1).replace(/\//g,"-").replace(/\./g,""),r=process.env.CURSOR_CONFIG_DIR||Ha.join(HO.homedir(),".cursor");return Ha.join(r,"projects",n)}async function fs(e){if(!e||typeof e!="string")return;let t=Ha.resolve(e),n=WO(t),r=Ha.join(n,".workspace-trusted");await rb.mkdir(n,{recursive:!0}),await rb.writeFile(r,`${JSON.stringify({trustedAt:new Date().toISOString(),workspacePath:t},null,2)}
14
- `,"utf8")}var ll=q(()=>{});import Rp from"node:fs/promises";import br from"node:path";import{execFile as qO}from"node:child_process";import{promisify as KO}from"node:util";async function XO(e){try{return(await Rp.stat(br.join(e,".git"))).isDirectory()?"repo":"worktree"}catch{return null}}async function ZO(e){let t=i=>Rp.readFile(br.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 Wn(){let e=new Map;async function t(o,s){if(e.has(o))return;let a=await XO(o);if(a==="worktree")return;if(a==="repo"){e.set(o,{path:o,name:br.basename(o),branch:await ZO(o)});return}if(s>=JO)return;let i;try{i=await Rp.readdir(o,{withFileTypes:!0})}catch{return}for(let c of i)!c.isDirectory()||c.name.startsWith(".")||YO.has(c.name)||await t(br.join(o,c.name),s+1)}for(let o of VO)await t(br.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 QO(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($p.has(e))return $p.get(e);let t=null;try{let{stdout:n}=await GO("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});t=QO(n)}catch{t=null}return $p.set(e,t),t}async function ms(e){let t=String(e||"").toLowerCase();if(!t)return null;for(let n of await Wn())if((await _e(n.path))?.toLowerCase()===t)return n.path;return null}var GO,ob,zO,VO,JO,YO,$p,kr=q(()=>{GO=KO(qO),ob=process.env.HOME||"/home/globo",zO=br.join(process.env.BOSTRAT_STATE_DIR||br.join(ob,".bostrat"),"repos"),VO=[...(process.env.BOSTRAT_REPOS_ROOT||br.join(ob,"Documents")).split(","),zO].map(e=>e.trim()).filter(Boolean),JO=Number(process.env.BOSTRAT_REPOS_DEPTH)||3,YO=new Set(["node_modules",".git",".cache","dist","build",".next","vendor","__pycache__","venv",".venv","target"]);$p=new Map});import eC from"node:fs";import sb from"node:fs/promises";import Wa from"node:path";import tC from"node:os";import{fileURLToPath as nC}from"node:url";import{execFile as rC}from"node:child_process";import{promisify as oC}from"node:util";function $e(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 ul(e=process.env){return!!($e(e)&&e.BOSTRAT_PLANE_TOKEN)}async function dl(e,{env:t=process.env}={}){let n=String(e||"").toLowerCase();if(!ib.test(n))throw hs("repo must be owner/name",400);let r=Op.get(n);if(r&&r.expiresAt-Date.now()>iC)return r;if(!ul(t))throw hs("node is not plane-linked \u2014 GitHub auth unavailable",503);let o;try{o=await cb(`${$e(t)}/v1/github/token?repo=${encodeURIComponent(e)}`,{headers:lb(t)})}catch(i){if(r&&r.expiresAt>Date.now())return r;throw hs(`plane unreachable \u2014 GitHub auth unavailable (${i?.message||i})`,503)}let s=await o.json().catch(()=>({}));if(!o.ok){if(o.status>=500&&r&&r.expiresAt>Date.now())return r;throw hs(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 Op.set(n,a),a}async function qa({env:e=process.env,force:t=!1}={}){if(!ul(e))return{configured:!1,repos:[],username:null};if(!t&&ho&&Date.now()-ho.at<cC)return ho.data;try{let n=await cb(`${$e(e)}/v1/github/repos`,{headers:lb(e)});if(!n.ok)throw new Error(`plane replied ${n.status}`);let r=await n.json();return ho={at:Date.now(),data:r},r}catch(n){return ho?ho.data:{configured:!0,repos:[],username:null,error:n?.message||String(n)}}}function ub(){Op.clear(),ho=null}async function yn({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 dl(r,{env:n});return o?{GH_TOKEN:o}:{}}catch{return{}}}async function Cp({env:e=process.env}={}){return(await qa({env:e})).username??null}function pC(e){let[t,n]=String(e).split("/");return Wa.join(aC,t,n)}async function Mp(e,{env:t=process.env}={}){let n=(...r)=>ab("git",["-C",e,...r],{timeout:1e4});await n("config","--replace-all","credential.helper",""),await n("config","--add","credential.helper",`!"${uC()}" ${dC(t)}`),await n("config","credential.useHttpPath","true")}async function pl(e,{env:t=process.env,baseUrl:n="https://github.com"}={}){if(!ib.test(String(e||"")))throw hs(`bad repo slug "${e}"`,400);let r=pC(e);if(eC.existsSync(Wa.join(r,".git")))return r;let{token:o}=await dl(e,{env:t});await sb.mkdir(Wa.dirname(r),{recursive:!0});let s="!f() { echo username=x-access-token; echo password=$BOSTRAT_GIT_TOKEN; }; f";try{await ab("git",["-c","credential.helper=","-c",`credential.helper=${s}`,"clone","--no-tags","-q",`${n}/${e}.git`,r],{timeout:lC,env:{...t,BOSTRAT_GIT_TOKEN:o,GIT_TERMINAL_PROMPT:"0"}})}catch(a){throw await sb.rm(r,{recursive:!0,force:!0}).catch(()=>{}),hs(`clone of ${e} failed: ${a?.stderr?.trim?.()||a?.message||a}`,502)}return await Mp(r,{env:t}),r}var ab,sC,aC,ib,iC,cC,lC,cb,Op,ho,lb,hs,uC,dC,pt=q(()=>{kr();ab=oC(rC),sC=process.env.BOSTRAT_STATE_DIR||Wa.join(process.env.HOME||tC.tmpdir(),".bostrat"),aC=Wa.join(sC,"repos"),ib=/^[^/\s]+\/[^/\s]+$/,iC=5*6e4,cC=6e4,lC=10*6e4,cb=fetch,Op=new Map,ho=null;lb=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),hs=(e,t)=>Object.assign(new Error(e),{status:t});uC=()=>nC(new URL("../bin/bostrat-git-credential",import.meta.url)),dC=(e=process.env)=>`http://127.0.0.1:${Number(e.PORT)||3362}`});function pb(e=process.env){return!!($e(e)&&e.BOSTRAT_PLANE_TOKEN)}async function mb(e,t,n,r=db){let o=$e(n),s=new AbortController,a=setTimeout(()=>s.abort(),r);try{return await mC(`${o}${e}`,{...t,signal:s.signal})}finally{clearTimeout(a)}}async function hb(e,{env:t=process.env,force:n=!1,timeoutMs:r=db}={}){if(!pb(t))return{facts:[],source:"unconfigured"};let o=Np.get(e);if(!n&&o&&Date.now()-o.at<fC)return{facts:o.facts,source:"cache"};try{let s=await mb(`/v1/memory/${encodeURIComponent(e)}`,{headers:fb(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 Np.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 fl(e,t,{env:n=process.env}={}){if(!pb(n))return{pushed:0,source:"unconfigured"};if(!t?.length)return{pushed:0,source:"empty"};try{let r=await mb(`/v1/memory/${encodeURIComponent(e)}`,{method:"POST",headers:{...fb(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 Np.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 fC,db,Np,mC,fb,wb=q(()=>{pt();fC=6e4,db=5e3,Np=new Map,mC=(...e)=>fetch(...e);fb=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});import Pp from"node:fs/promises";import ws from"node:path";import hC from"node:os";import{EventEmitter as wC}from"node:events";import{randomUUID as gC}from"node:crypto";function gs(e){return e?.cwd?ws.join(e.cwd,".bostrat","events"):ws.join(Dp,"events")}async function xC(e,t){if(!ml.has(t)){let o=(await K(e,t)).reduce((s,a)=>a.seq>s?a.seq:s,0);ml.set(t,o)}let n=ml.get(t)+1;return ml.set(t,n),n}function jp(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||!yC.has(t.type))throw new Error(`appendEvent: unknown event type "${t?.type}"`);if(t.actor&&!bC.has(t.actor))throw new Error(`appendEvent: bad actor "${t.actor}"`);if(t.source&&!kC.has(t.source))throw new Error(`appendEvent: bad source "${t.source}"`);let r=typeof e=="string"?ws.join(Dp,"events"):gs(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=jp(u,Number(t.payload?.ts??t.ts)||Date.now())}let s=await xC(r,n),a=t.userId??process.env.BOSTRAT_OWNER??null,i={id:t.id||gC(),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 yb(c)&&(c=bb(c),l=JSON.parse(c)),await Pp.mkdir(r,{recursive:!0}),await Pp.appendFile(gb(r,n),c+`
15
- `),ot.emit("event",l),ot.emit(`track:${n}`,l),l}async function K(e,t){let n,r;typeof e=="string"&&t?(n=e,r=t):(r=typeof e=="string"?e:e?.id,n=typeof e=="string"?ws.join(Dp,"events"):gs(e));let o;try{o=await Pp.readFile(gb(n,r),"utf8")}catch{return[]}let s=[];for(let a of o.split(`
16
- `))if(a.trim())try{s.push(JSON.parse(yb(a)?bb(a):a))}catch{}return s}function kb(e,t){let n=`track:${e}`;return ot.on(n,t),()=>ot.off(n,t)}var yC,bC,kC,ot,Dp,gb,ml,vC,yb,bb,de=q(()=>{yC=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.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.circuit.tagged","blueprint.item.bound","decision.recorded","changelog.published","stall.detected","error"]),bC=new Set(["user","agent","orchestrator","system","peer"]),kC=new Set(["hook","otel","statusline","transcript","pane","orchestrator","vendor","cli"]),ot=new wC;ot.setMaxListeners(0);Dp=process.env.BOSTRAT_STATE_DIR||ws.join(process.env.HOME||hC.tmpdir(),".bostrat");gb=(e,t)=>ws.join(e,`${t}.ndjson`),ml=new Map;vC=/(?<!\\)((?:\\\\)*)\\u0000/g,yb=e=>e.includes("\\u0000"),bb=e=>e.replace(vC,"$1\\ufffd")});import ne from"node:fs/promises";import SC from"node:os";import be from"node:path";import{execFile as TC}from"node:child_process";import{promisify as AC}from"node:util";function wl(){return be.join(gl,"memory","repos")}function wo(e){return e===qn?be.join(gl,"memory",qn):be.join(wl(),e)}async function Ga(e){try{return JSON.parse(await ne.readFile(be.join(e,_b),"utf8"))}catch{return{}}}async function Lp(e,t){let n=await Ga(e);for(let[r,o]of t)n[r]=Math.max(Number(n[r])||0,o);await ne.mkdir(e,{recursive:!0}),await ne.writeFile(be.join(e,_b),JSON.stringify(n))}function vb(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 Sb(e){try{let{stdout:t}=await EC("git",["-C",e,"config","--get","remote.origin.url"]);return t.trim()||null}catch{return null}}async function Fp(e){if(!e)return[];let t=vb(await Sb(e));if(t)return[t];let n=[],r=[];try{r=await ne.readdir(e,{withFileTypes:!0})}catch{return[]}for(let o of r){if(!o.isDirectory()||o.name.startsWith("."))continue;let s=vb(await Sb(be.join(e,o.name)));s&&!n.includes(s)&&n.push(s)}return n}function yl(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 xr(e,t){let n=new RegExp(`^\\s*${t}:\\s*(.+?)\\s*$`,"m").exec(e||"");return n?n[1].replace(/^"|"$/g,""):null}async function bn(e,t=null){let n=t??await ne.readFile(e,"utf8").catch(()=>""),{fm:r}=yl(n),o=xr(r,"modified"),s=o?Date.parse(o):NaN;if(Number.isFinite(s))return s;try{return(await ne.stat(e)).mtimeMs}catch{return 0}}function Ib(e,t){let n=xr(e,"scope"),r=/^repo:([a-z0-9][a-z0-9._-]*)$/i.exec(n||"");if(r)return r[1].toLowerCase();if((n||"").toLowerCase()===qn){let o=xr(e,"trust");if(!o||/^operator/i.test(o))return qn}return t}function Up(e,t,n,r=new Map){let o=(e||"").split(`
13
+ `:"")}try{await $p.mkdir(il.dirname(n),{recursive:!0}),await $p.writeFile(n,r)}catch(s){console.warn(`[codex-config] could not seed folder trust for ${t}: ${s?.message||s}`)}}var cl=q(()=>{});import rb from"node:fs/promises";import WO from"node:os";import Ha from"node:path";function qO(e){let n=Ha.resolve(e).slice(1).replace(/\//g,"-").replace(/\./g,""),r=process.env.CURSOR_CONFIG_DIR||Ha.join(WO.homedir(),".cursor");return Ha.join(r,"projects",n)}async function fs(e){if(!e||typeof e!="string")return;let t=Ha.resolve(e),n=qO(t),r=Ha.join(n,".workspace-trusted");await rb.mkdir(n,{recursive:!0}),await rb.writeFile(r,`${JSON.stringify({trustedAt:new Date().toISOString(),workspacePath:t},null,2)}
14
+ `,"utf8")}var ll=q(()=>{});import Op from"node:fs/promises";import br from"node:path";import{execFile as KO}from"node:child_process";import{promisify as GO}from"node:util";async function ZO(e){try{return(await Op.stat(br.join(e,".git"))).isDirectory()?"repo":"worktree"}catch{return null}}async function QO(e){let t=i=>Op.readFile(br.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 Wn(){let e=new Map;async function t(o,s){if(e.has(o))return;let a=await ZO(o);if(a==="worktree")return;if(a==="repo"){e.set(o,{path:o,name:br.basename(o),branch:await QO(o)});return}if(s>=YO)return;let i;try{i=await Op.readdir(o,{withFileTypes:!0})}catch{return}for(let c of i)!c.isDirectory()||c.name.startsWith(".")||XO.has(c.name)||await t(br.join(o,c.name),s+1)}for(let o of JO)await t(br.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 eC(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(Rp.has(e))return Rp.get(e);let t=null;try{let{stdout:n}=await zO("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});t=eC(n)}catch{t=null}return Rp.set(e,t),t}async function ms(e){let t=String(e||"").toLowerCase();if(!t)return null;for(let n of await Wn())if((await _e(n.path))?.toLowerCase()===t)return n.path;return null}var zO,ob,VO,JO,YO,XO,Rp,kr=q(()=>{zO=GO(KO),ob=process.env.HOME||"/home/globo",VO=br.join(process.env.BOSTRAT_STATE_DIR||br.join(ob,".bostrat"),"repos"),JO=[...(process.env.BOSTRAT_REPOS_ROOT||br.join(ob,"Documents")).split(","),VO].map(e=>e.trim()).filter(Boolean),YO=Number(process.env.BOSTRAT_REPOS_DEPTH)||3,XO=new Set(["node_modules",".git",".cache","dist","build",".next","vendor","__pycache__","venv",".venv","target"]);Rp=new Map});import tC from"node:fs";import sb from"node:fs/promises";import Wa from"node:path";import nC from"node:os";import{fileURLToPath as rC}from"node:url";import{execFile as oC}from"node:child_process";import{promisify as sC}from"node:util";function $e(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 ul(e=process.env){return!!($e(e)&&e.BOSTRAT_PLANE_TOKEN)}async function dl(e,{env:t=process.env}={}){let n=String(e||"").toLowerCase();if(!ib.test(n))throw hs("repo must be owner/name",400);let r=Cp.get(n);if(r&&r.expiresAt-Date.now()>cC)return r;if(!ul(t))throw hs("node is not plane-linked \u2014 GitHub auth unavailable",503);let o;try{o=await cb(`${$e(t)}/v1/github/token?repo=${encodeURIComponent(e)}`,{headers:lb(t)})}catch(i){if(r&&r.expiresAt>Date.now())return r;throw hs(`plane unreachable \u2014 GitHub auth unavailable (${i?.message||i})`,503)}let s=await o.json().catch(()=>({}));if(!o.ok){if(o.status>=500&&r&&r.expiresAt>Date.now())return r;throw hs(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 Cp.set(n,a),a}async function qa({env:e=process.env,force:t=!1}={}){if(!ul(e))return{configured:!1,repos:[],username:null};if(!t&&ho&&Date.now()-ho.at<lC)return ho.data;try{let n=await cb(`${$e(e)}/v1/github/repos`,{headers:lb(e)});if(!n.ok)throw new Error(`plane replied ${n.status}`);let r=await n.json();return ho={at:Date.now(),data:r},r}catch(n){return ho?ho.data:{configured:!0,repos:[],username:null,error:n?.message||String(n)}}}function ub(){Cp.clear(),ho=null}async function yn({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 dl(r,{env:n});return o?{GH_TOKEN:o}:{}}catch{return{}}}async function Mp({env:e=process.env}={}){return(await qa({env:e})).username??null}function fC(e){let[t,n]=String(e).split("/");return Wa.join(iC,t,n)}async function Np(e,{env:t=process.env}={}){let n=(...r)=>ab("git",["-C",e,...r],{timeout:1e4});await n("config","--replace-all","credential.helper",""),await n("config","--add","credential.helper",`!"${dC()}" ${pC(t)}`),await n("config","credential.useHttpPath","true")}async function pl(e,{env:t=process.env,baseUrl:n="https://github.com"}={}){if(!ib.test(String(e||"")))throw hs(`bad repo slug "${e}"`,400);let r=fC(e);if(tC.existsSync(Wa.join(r,".git")))return r;let{token:o}=await dl(e,{env:t});await sb.mkdir(Wa.dirname(r),{recursive:!0});let s="!f() { echo username=x-access-token; echo password=$BOSTRAT_GIT_TOKEN; }; f";try{await ab("git",["-c","credential.helper=","-c",`credential.helper=${s}`,"clone","--no-tags","-q",`${n}/${e}.git`,r],{timeout:uC,env:{...t,BOSTRAT_GIT_TOKEN:o,GIT_TERMINAL_PROMPT:"0"}})}catch(a){throw await sb.rm(r,{recursive:!0,force:!0}).catch(()=>{}),hs(`clone of ${e} failed: ${a?.stderr?.trim?.()||a?.message||a}`,502)}return await Np(r,{env:t}),r}var ab,aC,iC,ib,cC,lC,uC,cb,Cp,ho,lb,hs,dC,pC,pt=q(()=>{kr();ab=sC(oC),aC=process.env.BOSTRAT_STATE_DIR||Wa.join(process.env.HOME||nC.tmpdir(),".bostrat"),iC=Wa.join(aC,"repos"),ib=/^[^/\s]+\/[^/\s]+$/,cC=5*6e4,lC=6e4,uC=10*6e4,cb=fetch,Cp=new Map,ho=null;lb=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),hs=(e,t)=>Object.assign(new Error(e),{status:t});dC=()=>rC(new URL("../bin/bostrat-git-credential",import.meta.url)),pC=(e=process.env)=>`http://127.0.0.1:${Number(e.PORT)||3362}`});function pb(e=process.env){return!!($e(e)&&e.BOSTRAT_PLANE_TOKEN)}async function mb(e,t,n,r=db){let o=$e(n),s=new AbortController,a=setTimeout(()=>s.abort(),r);try{return await hC(`${o}${e}`,{...t,signal:s.signal})}finally{clearTimeout(a)}}async function hb(e,{env:t=process.env,force:n=!1,timeoutMs:r=db}={}){if(!pb(t))return{facts:[],source:"unconfigured"};let o=Pp.get(e);if(!n&&o&&Date.now()-o.at<mC)return{facts:o.facts,source:"cache"};try{let s=await mb(`/v1/memory/${encodeURIComponent(e)}`,{headers:fb(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 Pp.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 fl(e,t,{env:n=process.env}={}){if(!pb(n))return{pushed:0,source:"unconfigured"};if(!t?.length)return{pushed:0,source:"empty"};try{let r=await mb(`/v1/memory/${encodeURIComponent(e)}`,{method:"POST",headers:{...fb(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 Pp.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 mC,db,Pp,hC,fb,wb=q(()=>{pt();mC=6e4,db=5e3,Pp=new Map,hC=(...e)=>fetch(...e);fb=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});import Dp from"node:fs/promises";import ws from"node:path";import wC from"node:os";import{EventEmitter as gC}from"node:events";import{randomUUID as yC}from"node:crypto";function gs(e){return e?.cwd?ws.join(e.cwd,".bostrat","events"):ws.join(Bp,"events")}async function vC(e,t){if(!ml.has(t)){let o=(await K(e,t)).reduce((s,a)=>a.seq>s?a.seq:s,0);ml.set(t,o)}let n=ml.get(t)+1;return ml.set(t,n),n}function jp(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||!bC.has(t.type))throw new Error(`appendEvent: unknown event type "${t?.type}"`);if(t.actor&&!kC.has(t.actor))throw new Error(`appendEvent: bad actor "${t.actor}"`);if(t.source&&!xC.has(t.source))throw new Error(`appendEvent: bad source "${t.source}"`);let r=typeof e=="string"?ws.join(Bp,"events"):gs(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=jp(u,Number(t.payload?.ts??t.ts)||Date.now())}let s=await vC(r,n),a=t.userId??process.env.BOSTRAT_OWNER??null,i={id:t.id||yC(),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 yb(c)&&(c=bb(c),l=JSON.parse(c)),await Dp.mkdir(r,{recursive:!0}),await Dp.appendFile(gb(r,n),c+`
15
+ `),ot.emit("event",l),ot.emit(`track:${n}`,l),l}async function K(e,t){let n,r;typeof e=="string"&&t?(n=e,r=t):(r=typeof e=="string"?e:e?.id,n=typeof e=="string"?ws.join(Bp,"events"):gs(e));let o;try{o=await Dp.readFile(gb(n,r),"utf8")}catch{return[]}let s=[];for(let a of o.split(`
16
+ `))if(a.trim())try{s.push(JSON.parse(yb(a)?bb(a):a))}catch{}return s}function kb(e,t){let n=`track:${e}`;return ot.on(n,t),()=>ot.off(n,t)}var bC,kC,xC,ot,Bp,gb,ml,SC,yb,bb,de=q(()=>{bC=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.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.circuit.tagged","blueprint.item.bound","decision.recorded","changelog.published","stall.detected","error"]),kC=new Set(["user","agent","orchestrator","system","peer"]),xC=new Set(["hook","otel","statusline","transcript","pane","orchestrator","vendor","cli"]),ot=new gC;ot.setMaxListeners(0);Bp=process.env.BOSTRAT_STATE_DIR||ws.join(process.env.HOME||wC.tmpdir(),".bostrat");gb=(e,t)=>ws.join(e,`${t}.ndjson`),ml=new Map;SC=/(?<!\\)((?:\\\\)*)\\u0000/g,yb=e=>e.includes("\\u0000"),bb=e=>e.replace(SC,"$1\\ufffd")});import ne from"node:fs/promises";import TC from"node:os";import be from"node:path";import{execFile as AC}from"node:child_process";import{promisify as EC}from"node:util";function wl(){return be.join(gl,"memory","repos")}function wo(e){return e===qn?be.join(gl,"memory",qn):be.join(wl(),e)}async function Ga(e){try{return JSON.parse(await ne.readFile(be.join(e,_b),"utf8"))}catch{return{}}}async function Fp(e,t){let n=await Ga(e);for(let[r,o]of t)n[r]=Math.max(Number(n[r])||0,o);await ne.mkdir(e,{recursive:!0}),await ne.writeFile(be.join(e,_b),JSON.stringify(n))}function vb(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 Sb(e){try{let{stdout:t}=await _C("git",["-C",e,"config","--get","remote.origin.url"]);return t.trim()||null}catch{return null}}async function Up(e){if(!e)return[];let t=vb(await Sb(e));if(t)return[t];let n=[],r=[];try{r=await ne.readdir(e,{withFileTypes:!0})}catch{return[]}for(let o of r){if(!o.isDirectory()||o.name.startsWith("."))continue;let s=vb(await Sb(be.join(e,o.name)));s&&!n.includes(s)&&n.push(s)}return n}function yl(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 xr(e,t){let n=new RegExp(`^\\s*${t}:\\s*(.+?)\\s*$`,"m").exec(e||"");return n?n[1].replace(/^"|"$/g,""):null}async function bn(e,t=null){let n=t??await ne.readFile(e,"utf8").catch(()=>""),{fm:r}=yl(n),o=xr(r,"modified"),s=o?Date.parse(o):NaN;if(Number.isFinite(s))return s;try{return(await ne.stat(e)).mtimeMs}catch{return 0}}function Ib(e,t){let n=xr(e,"scope"),r=/^repo:([a-z0-9][a-z0-9._-]*)$/i.exec(n||"");if(r)return r[1].toLowerCase();if((n||"").toLowerCase()===qn){let o=xr(e,"trust");if(!o||/^operator/i.test(o))return qn}return t}function Hp(e,t,n,r=new Map){let o=(e||"").split(`
17
17
  `),s=new Map;for(let c of(t||"").split(`
18
18
  `)){let l=bs(c);l&&c.trim().startsWith("-")&&s.set(l,c)}let a=new Set,i=o.map(c=>{let l=bs(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 $b(e,t){let n=xr(t,"name")||e.replace(/\.md$/,""),r=xr(t,"description")||"";return`- [${n}](${e})${r?` \u2014 ${r}`:""}`}async function za(e){let t=[];try{t=await ne.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 Rb(e,t){let n=be.join(e,".bostrat","memory"),r=await za(n);if(!r.length)return{harvested:0,changedByKey:new Map};let o=Tb.get(e)??0,s=Date.now(),a=new Map,i=new Map,c=0,l=new Map;for(let d of r){let p=be.join(n,d);if(o)try{if((await ne.stat(p)).mtimeMs<o-IC)continue}catch{continue}let f;try{f=await ne.readFile(p,"utf8")}catch{continue}let{fm:w}=yl(f),m=Ib(w,t);if(!m)continue;let g=wo(m),b=be.join(g,d),x=await bn(p,f);if(l.has(g)||l.set(g,await Ga(g)),(l.get(g)[d]||0)>=x)continue;let y=await bn(b).catch(()=>0);if(await ne.access(b).then(()=>!0).catch(()=>!1)&&y>=x)continue;await ne.mkdir(g,{recursive:!0}),await ne.writeFile(b,f),c++;let O=a.get(g);O||a.set(g,O={won:new Set,generated:new Map}),O.won.add(d),O.generated.set(d,$b(d,w)),i.has(m)||i.set(m,new Set),i.get(m).add(d)}let u=await ne.readFile(be.join(n,"MEMORY.md"),"utf8").catch(()=>"");for(let[d,p]of a){let f=be.join(d,"MEMORY.md"),w=await ne.readFile(f,"utf8").catch(()=>"");await ne.writeFile(f,Up(w,u,p.won,p.generated))}return Tb.set(e,s),{harvested:c,changedByKey:i}}async function Ob(e){let t=0,n=new Map;for(let r of e||[]){if(!r||!await ne.access(be.join(r,".bostrat","memory")).then(()=>!0).catch(()=>!1))continue;let[s]=await Fp(r),a=await Rb(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 $C(){let e=be.join(gl,"workspaces"),t=[];try{t=await ne.readdir(e,{withFileTypes:!0})}catch{return{harvested:0,changedByKey:new Map}}return Ob(t.filter(n=>n.isDirectory()).map(n=>be.join(e,n.name)))}async function CC(e,t){let n=wo(e),r=await Ga(n),o=new Set,s=new Map,a=[],i=0;for(let c of t||[]){let l=String(c?.file||"");if(!RC.test(l)||l==="MEMORY.md")continue;let u=be.join(n,l),d=await ne.access(u).then(()=>!0).catch(()=>!1),p=d?await bn(u):0,f=Number(c.modified)||0;if(c.deleted){f>p&&(d&&await ne.rm(u,{force:!0}),await Lp(n,[[l,f]]),d&&(a.push(l),i++));continue}d&&p>=f||(r[l]||0)>=f||(await ne.mkdir(n,{recursive:!0}),await ne.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=be.join(n,"MEMORY.md"),l=await ne.readFile(c,"utf8").catch(()=>""),u=Up(l,[...s.values()].join(`
21
+ `)}function $b(e,t){let n=xr(t,"name")||e.replace(/\.md$/,""),r=xr(t,"description")||"";return`- [${n}](${e})${r?` \u2014 ${r}`:""}`}async function za(e){let t=[];try{t=await ne.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 Rb(e,t){let n=be.join(e,".bostrat","memory"),r=await za(n);if(!r.length)return{harvested:0,changedByKey:new Map};let o=Tb.get(e)??0,s=Date.now(),a=new Map,i=new Map,c=0,l=new Map;for(let d of r){let p=be.join(n,d);if(o)try{if((await ne.stat(p)).mtimeMs<o-$C)continue}catch{continue}let f;try{f=await ne.readFile(p,"utf8")}catch{continue}let{fm:w}=yl(f),m=Ib(w,t);if(!m)continue;let g=wo(m),b=be.join(g,d),x=await bn(p,f);if(l.has(g)||l.set(g,await Ga(g)),(l.get(g)[d]||0)>=x)continue;let y=await bn(b).catch(()=>0);if(await ne.access(b).then(()=>!0).catch(()=>!1)&&y>=x)continue;await ne.mkdir(g,{recursive:!0}),await ne.writeFile(b,f),c++;let O=a.get(g);O||a.set(g,O={won:new Set,generated:new Map}),O.won.add(d),O.generated.set(d,$b(d,w)),i.has(m)||i.set(m,new Set),i.get(m).add(d)}let u=await ne.readFile(be.join(n,"MEMORY.md"),"utf8").catch(()=>"");for(let[d,p]of a){let f=be.join(d,"MEMORY.md"),w=await ne.readFile(f,"utf8").catch(()=>"");await ne.writeFile(f,Hp(w,u,p.won,p.generated))}return Tb.set(e,s),{harvested:c,changedByKey:i}}async function Ob(e){let t=0,n=new Map;for(let r of e||[]){if(!r||!await ne.access(be.join(r,".bostrat","memory")).then(()=>!0).catch(()=>!1))continue;let[s]=await Up(r),a=await Rb(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 RC(){let e=be.join(gl,"workspaces"),t=[];try{t=await ne.readdir(e,{withFileTypes:!0})}catch{return{harvested:0,changedByKey:new Map}}return Ob(t.filter(n=>n.isDirectory()).map(n=>be.join(e,n.name)))}async function MC(e,t){let n=wo(e),r=await Ga(n),o=new Set,s=new Map,a=[],i=0;for(let c of t||[]){let l=String(c?.file||"");if(!OC.test(l)||l==="MEMORY.md")continue;let u=be.join(n,l),d=await ne.access(u).then(()=>!0).catch(()=>!1),p=d?await bn(u):0,f=Number(c.modified)||0;if(c.deleted){f>p&&(d&&await ne.rm(u,{force:!0}),await Fp(n,[[l,f]]),d&&(a.push(l),i++));continue}d&&p>=f||(r[l]||0)>=f||(await ne.mkdir(n,{recursive:!0}),await ne.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=be.join(n,"MEMORY.md"),l=await ne.readFile(c,"utf8").catch(()=>""),u=Hp(l,[...s.values()].join(`
22
22
  `),o);if(a.length){let d=new Set(a);u=u.split(`
23
23
  `).filter(p=>!d.has(bs(p))).join(`
24
- `)}await ne.mkdir(n,{recursive:!0}),await ne.writeFile(c,u)}return{changed:i,tombstoned:a.length}}async function bl(e,t=null){let n=wo(e),r=t?.length?t:await za(n);if(!r.length)return{pushed:0,source:"empty"};let o=OC(await ne.readFile(be.join(n,"MEMORY.md"),"utf8").catch(()=>"")),s=[];for(let a of r){let i=be.join(n,a),c;try{c=await ne.readFile(i,"utf8")}catch{continue}s.push({file:a,content:c,modified:await bn(i,c),indexLine:o.get(a)??null})}return fl(e,s)}async function MC(e,{timeoutMs:t}={}){let{facts:n,source:r}=await hb(e,t?{timeoutMs:t}:{});n.length?await CC(e,n):r==="plane"&&await bl(e)}function NC(e){let t=e.split(`
24
+ `)}await ne.mkdir(n,{recursive:!0}),await ne.writeFile(c,u)}return{changed:i,tombstoned:a.length}}async function bl(e,t=null){let n=wo(e),r=t?.length?t:await za(n);if(!r.length)return{pushed:0,source:"empty"};let o=CC(await ne.readFile(be.join(n,"MEMORY.md"),"utf8").catch(()=>"")),s=[];for(let a of r){let i=be.join(n,a),c;try{c=await ne.readFile(i,"utf8")}catch{continue}s.push({file:a,content:c,modified:await bn(i,c),indexLine:o.get(a)??null})}return fl(e,s)}async function NC(e,{timeoutMs:t}={}){let{facts:n,source:r}=await hb(e,t?{timeoutMs:t}:{});n.length?await MC(e,n):r==="plane"&&await bl(e)}function PC(e){let t=e.split(`
25
25
  `);t.length>xb&&(t=t.slice(0,xb));let n=t.join(`
26
- `);for(;Buffer.byteLength(n,"utf8")>_C&&t.length;)t.pop(),n=t.join(`
27
- `);return n}async function DC(e,t){if(!e||!t?.length)return{materialized:!1,reason:"no-repo-key"};let n=be.join(e,".bostrat","memory"),r=0,o=0,s=[];for(let u of t){let d=wo(u),p=await Ga(d);for(let[g,b]of Object.entries(p)){let x=be.join(n,g);await ne.access(x).then(()=>!0).catch(()=>!1)&&await bn(x)<=b&&(await ne.rm(x,{force:!0}),o++)}let f=await za(d);if(!f.length)continue;await ne.mkdir(n,{recursive:!0});for(let g of f){let b=be.join(d,g),x=be.join(n,g),y=await bn(b),$=await bn(x).catch(()=>0);await ne.access(x).then(()=>!0).catch(()=>!1)&&$>=y||(await ne.copyFile(b,x),r++)}let w=await ne.readFile(be.join(d,"MEMORY.md"),"utf8").catch(()=>""),m=u===qn?"## operator memory":`## repo: ${u}`;w.trim()&&s.push(t.length>1?`${m}
26
+ `);for(;Buffer.byteLength(n,"utf8")>IC&&t.length;)t.pop(),n=t.join(`
27
+ `);return n}async function BC(e,t){if(!e||!t?.length)return{materialized:!1,reason:"no-repo-key"};let n=be.join(e,".bostrat","memory"),r=0,o=0,s=[];for(let u of t){let d=wo(u),p=await Ga(d);for(let[g,b]of Object.entries(p)){let x=be.join(n,g);await ne.access(x).then(()=>!0).catch(()=>!1)&&await bn(x)<=b&&(await ne.rm(x,{force:!0}),o++)}let f=await za(d);if(!f.length)continue;await ne.mkdir(n,{recursive:!0});for(let g of f){let b=be.join(d,g),x=be.join(n,g),y=await bn(b),$=await bn(x).catch(()=>0);await ne.access(x).then(()=>!0).catch(()=>!1)&&$>=y||(await ne.copyFile(b,x),r++)}let w=await ne.readFile(be.join(d,"MEMORY.md"),"utf8").catch(()=>""),m=u===qn?"## 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=NC(i);await ne.mkdir(n,{recursive:!0}),await ne.writeFile(be.join(n,"MEMORY.md"),c);let l=be.join(n,"claude");return await ne.mkdir(l,{recursive:!0}),await ne.writeFile(be.join(l,"MEMORY.md"),PC,{flag:"wx"}).catch(()=>{}),{materialized:!0,facts:r,capped:c!==i}}async function Cb(e){try{let t=await Fp(e);if(!t.length)return{materialized:!1,reason:"no-repo-key"};let n=[...t,qn];return await Promise.all(n.map(r=>MC(r,{timeoutMs:jC}))),await DC(e,n)}catch(t){return{materialized:!1,reason:"error",error:t?.message||String(t)}}}function Mb(){return{...et,pending:ys.size,queued:Bp.size}}function Nb(e){if(hl.has(e))return hl.get(e);Bp.add(e);let t=Ab.then(async()=>{Bp.delete(e),hl.delete(e);let n=await Wp(e);return et.runs++,et.lastRunAt=Date.now(),n.error?(et.errors++,et.lastError=n.error):et.harvested+=n.harvested||0,n}).catch(n=>({harvested:0,error:n?.message||String(n)}));return hl.set(e,t),Ab=t.then(()=>{}),t}function kl(e,{delayMs:t=BC}={}){if(!e||typeof e!="string")return;et.scheduled++;let n=ys.get(e);n&&clearTimeout(n);let r=setTimeout(()=>{ys.delete(e),Nb(e)},t);r.unref?.(),ys.set(e,r)}async function Hp(e,{timeoutMs:t=3e3}={}){if(!e)return{harvested:0,skipped:"no-cwd"};if(!await ne.access(be.join(e,".bostrat","memory")).then(()=>!0,()=>!1))return{harvested:0,skipped:"no-memory-dir"};let r=ys.get(e);r&&(clearTimeout(r),ys.delete(e));let o,s=new Promise(a=>{o=setTimeout(()=>a({harvested:0,timedOut:!0}),t),o.unref?.()});try{return await Promise.race([Nb(e),s])}finally{clearTimeout(o)}}async function Pb(e){return Ka||(Ka=(async()=>{try{Eb||(Eb=!0,await FC());let{harvested:t,changedByKey:n}=await Ob(e);for(let[r,o]of n)await bl(r,[...o]);return et.reconciles++,et.lastReconcileAt=Date.now(),et.harvested+=t,{harvested:t,keys:[...n.keys()]}}catch(t){return et.errors++,et.lastError=t?.message||String(t),{harvested:0,error:et.lastError}}finally{Ka=null}})(),Ka)}function LC(){return be.join(gl,"memory",".full-sweep-done")}async function Db(){let e=LC();try{let t=JSON.parse(await ne.readFile(e,"utf8"));return et.backfill={at:Number(t?.at)||0,harvested:Number(t?.harvested)||0,prior:!0},{ran:!1,...et.backfill}}catch{}try{let{harvested:t,changedByKey:n}=await $C();for(let[o,s]of n)await bl(o,[...s]);let r={at:Date.now(),harvested:t};return await ne.mkdir(be.dirname(e),{recursive:!0}),await ne.writeFile(e,JSON.stringify(r)),et.backfill=r,{ran:!0,...r}}catch(t){return et.errors++,et.lastError=t?.message||String(t),{ran:!1,error:et.lastError}}}async function FC(){let e=0,t=[];try{t=await ne.readdir(wl(),{withFileTypes:!0})}catch{return{moved:e}}for(let n of t){if(!n.isDirectory())continue;let r=be.join(wl(),n.name),o=wo(qn),s=new Set,a=new Map;for(let f of await za(r)){let w=be.join(r,f),m;try{m=await ne.readFile(w,"utf8")}catch{continue}let{fm:g}=yl(m);if(Ib(g,n.name)!==qn)continue;let b=be.join(o,f),x=await bn(b).catch(()=>0),y=await bn(w,m);await ne.mkdir(o,{recursive:!0}),y>x&&await ne.writeFile(b,m),await ne.rm(w,{force:!0}),s.add(f),a.set(f,$b(f,g)),e++}if(!s.size)continue;let i=Date.now();await Lp(r,[...s].map(f=>[f,i])),await fl(n.name,[...s].map(f=>({file:f,deleted:!0,modified:i})));let c=be.join(r,"MEMORY.md"),l=await ne.readFile(c,"utf8").catch(()=>""),u=l.split(`
32
+ `,c=PC(i);await ne.mkdir(n,{recursive:!0}),await ne.writeFile(be.join(n,"MEMORY.md"),c);let l=be.join(n,"claude");return await ne.mkdir(l,{recursive:!0}),await ne.writeFile(be.join(l,"MEMORY.md"),DC,{flag:"wx"}).catch(()=>{}),{materialized:!0,facts:r,capped:c!==i}}async function Cb(e){try{let t=await Up(e);if(!t.length)return{materialized:!1,reason:"no-repo-key"};let n=[...t,qn];return await Promise.all(n.map(r=>NC(r,{timeoutMs:jC}))),await BC(e,n)}catch(t){return{materialized:!1,reason:"error",error:t?.message||String(t)}}}function Mb(){return{...et,pending:ys.size,queued:Lp.size}}function Nb(e){if(hl.has(e))return hl.get(e);Lp.add(e);let t=Ab.then(async()=>{Lp.delete(e),hl.delete(e);let n=await qp(e);return et.runs++,et.lastRunAt=Date.now(),n.error?(et.errors++,et.lastError=n.error):et.harvested+=n.harvested||0,n}).catch(n=>({harvested:0,error:n?.message||String(n)}));return hl.set(e,t),Ab=t.then(()=>{}),t}function kl(e,{delayMs:t=LC}={}){if(!e||typeof e!="string")return;et.scheduled++;let n=ys.get(e);n&&clearTimeout(n);let r=setTimeout(()=>{ys.delete(e),Nb(e)},t);r.unref?.(),ys.set(e,r)}async function Wp(e,{timeoutMs:t=3e3}={}){if(!e)return{harvested:0,skipped:"no-cwd"};if(!await ne.access(be.join(e,".bostrat","memory")).then(()=>!0,()=>!1))return{harvested:0,skipped:"no-memory-dir"};let r=ys.get(e);r&&(clearTimeout(r),ys.delete(e));let o,s=new Promise(a=>{o=setTimeout(()=>a({harvested:0,timedOut:!0}),t),o.unref?.()});try{return await Promise.race([Nb(e),s])}finally{clearTimeout(o)}}async function Pb(e){return Ka||(Ka=(async()=>{try{Eb||(Eb=!0,await UC());let{harvested:t,changedByKey:n}=await Ob(e);for(let[r,o]of n)await bl(r,[...o]);return et.reconciles++,et.lastReconcileAt=Date.now(),et.harvested+=t,{harvested:t,keys:[...n.keys()]}}catch(t){return et.errors++,et.lastError=t?.message||String(t),{harvested:0,error:et.lastError}}finally{Ka=null}})(),Ka)}function FC(){return be.join(gl,"memory",".full-sweep-done")}async function Db(){let e=FC();try{let t=JSON.parse(await ne.readFile(e,"utf8"));return et.backfill={at:Number(t?.at)||0,harvested:Number(t?.harvested)||0,prior:!0},{ran:!1,...et.backfill}}catch{}try{let{harvested:t,changedByKey:n}=await RC();for(let[o,s]of n)await bl(o,[...s]);let r={at:Date.now(),harvested:t};return await ne.mkdir(be.dirname(e),{recursive:!0}),await ne.writeFile(e,JSON.stringify(r)),et.backfill=r,{ran:!0,...r}}catch(t){return et.errors++,et.lastError=t?.message||String(t),{ran:!1,error:et.lastError}}}async function UC(){let e=0,t=[];try{t=await ne.readdir(wl(),{withFileTypes:!0})}catch{return{moved:e}}for(let n of t){if(!n.isDirectory())continue;let r=be.join(wl(),n.name),o=wo(qn),s=new Set,a=new Map;for(let f of await za(r)){let w=be.join(r,f),m;try{m=await ne.readFile(w,"utf8")}catch{continue}let{fm:g}=yl(m);if(Ib(g,n.name)!==qn)continue;let b=be.join(o,f),x=await bn(b).catch(()=>0),y=await bn(w,m);await ne.mkdir(o,{recursive:!0}),y>x&&await ne.writeFile(b,m),await ne.rm(w,{force:!0}),s.add(f),a.set(f,$b(f,g)),e++}if(!s.size)continue;let i=Date.now();await Fp(r,[...s].map(f=>[f,i])),await fl(n.name,[...s].map(f=>({file:f,deleted:!0,modified:i})));let c=be.join(r,"MEMORY.md"),l=await ne.readFile(c,"utf8").catch(()=>""),u=l.split(`
33
33
  `).filter(f=>!s.has(bs(f))).join(`
34
- `);await ne.writeFile(c,u).catch(()=>{});let d=be.join(o,"MEMORY.md"),p=await ne.readFile(d,"utf8").catch(()=>"");await ne.writeFile(d,Up(p,l,s,a))}return{moved:e}}async function jb(){let e=[],t=[qn];try{for(let n of await ne.readdir(wl(),{withFileTypes:!0}))n.isDirectory()&&t.push(n.name)}catch{}for(let n of t){let r=wo(n),o=await za(r),s=await Ga(r);if(!o.length&&!Object.keys(s).length)continue;let a=[];for(let i of o){let c=await ne.readFile(be.join(r,i),"utf8").catch(()=>""),{fm:l}=yl(c);a.push({file:i,name:xr(l,"name")||i.replace(/\.md$/,""),description:xr(l,"description")||"",scope:xr(l,"scope")||null,modified:await bn(be.join(r,i),c)})}e.push({key:n,facts:a,tombstones:Object.keys(s).length})}return e}async function Bb(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=wo(e),r=be.join(n,t);if(!await ne.access(r).then(()=>!0).catch(()=>!1))throw new Error(`fact ${t} not found in ${e}`);let s=Date.now();await ne.rm(r,{force:!0}),await Lp(n,[[t,s]]);let a=be.join(n,"MEMORY.md"),i=await ne.readFile(a,"utf8").catch(()=>"");await ne.writeFile(a,i.split(`
34
+ `);await ne.writeFile(c,u).catch(()=>{});let d=be.join(o,"MEMORY.md"),p=await ne.readFile(d,"utf8").catch(()=>"");await ne.writeFile(d,Hp(p,l,s,a))}return{moved:e}}async function Bb(){let e=[],t=[qn];try{for(let n of await ne.readdir(wl(),{withFileTypes:!0}))n.isDirectory()&&t.push(n.name)}catch{}for(let n of t){let r=wo(n),o=await za(r),s=await Ga(r);if(!o.length&&!Object.keys(s).length)continue;let a=[];for(let i of o){let c=await ne.readFile(be.join(r,i),"utf8").catch(()=>""),{fm:l}=yl(c);a.push({file:i,name:xr(l,"name")||i.replace(/\.md$/,""),description:xr(l,"description")||"",scope:xr(l,"scope")||null,modified:await bn(be.join(r,i),c)})}e.push({key:n,facts:a,tombstones:Object.keys(s).length})}return e}async function jb(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=wo(e),r=be.join(n,t);if(!await ne.access(r).then(()=>!0).catch(()=>!1))throw new Error(`fact ${t} not found in ${e}`);let s=Date.now();await ne.rm(r,{force:!0}),await Fp(n,[[t,s]]);let a=be.join(n,"MEMORY.md"),i=await ne.readFile(a,"utf8").catch(()=>"");await ne.writeFile(a,i.split(`
35
35
  `).filter(l=>bs(l)!==t).join(`
36
- `)).catch(()=>{});let c=await fl(e,[{file:t,deleted:!0,modified:s}]);return{deleted:t,key:e,plane:c.source}}async function Wp(e){try{let t=await Fp(e),{harvested:n,changedByKey:r}=await Rb(e,t[0]||null);for(let[o,s]of r)await bl(o,[...s]);return n>0&&await HC(e,r).catch(()=>{}),{harvested:n}}catch(t){return{harvested:0,error:t?.message||String(t)}}}async function HC(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,UC)}}await C({id:n,cwd:e},{type:"memory.harvested",actor:"orchestrator",payload:{harvested:o,keys:r,ts:Date.now()}})}var EC,gl,xb,_C,qn,_b,bs,Tb,IC,RC,OC,PC,jC,BC,ys,Bp,Ab,et,hl,Eb,Ka,UC,Va=q(()=>{wb();de();EC=AC(TC),gl=process.env.BOSTRAT_STATE_DIR||be.join(process.env.HOME||SC.tmpdir(),".bostrat"),xb=200,_C=25*1024;qn="operator";_b=".tombstones.json";bs=e=>/\]\(([^)]+\.md)\)/.exec(e)?.[1]||null;Tb=new Map,IC=2e3;RC=/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/,OC=e=>{let t=new Map;for(let n of(e||"").split(`
37
- `)){let r=bs(n);r&&n.trim().startsWith("-")&&t.set(r,n)}return t};PC=`# Track memory
36
+ `)).catch(()=>{});let c=await fl(e,[{file:t,deleted:!0,modified:s}]);return{deleted:t,key:e,plane:c.source}}async function qp(e){try{let t=await Up(e),{harvested:n,changedByKey:r}=await Rb(e,t[0]||null);for(let[o,s]of r)await bl(o,[...s]);return n>0&&await WC(e,r).catch(()=>{}),{harvested:n}}catch(t){return{harvested:0,error:t?.message||String(t)}}}async function WC(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,HC)}}await C({id:n,cwd:e},{type:"memory.harvested",actor:"orchestrator",payload:{harvested:o,keys:r,ts:Date.now()}})}var _C,gl,xb,IC,qn,_b,bs,Tb,$C,OC,CC,DC,jC,LC,ys,Lp,Ab,et,hl,Eb,Ka,HC,Va=q(()=>{wb();de();_C=EC(AC),gl=process.env.BOSTRAT_STATE_DIR||be.join(process.env.HOME||TC.tmpdir(),".bostrat"),xb=200,IC=25*1024;qn="operator";_b=".tombstones.json";bs=e=>/\]\(([^)]+\.md)\)/.exec(e)?.[1]||null;Tb=new Map,$C=2e3;OC=/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/,CC=e=>{let t=new Map;for(let n of(e||"").split(`
37
+ `)){let r=bs(n);r&&n.trim().startsWith("-")&&t.set(r,n)}return t};DC=`# 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
- `;jC=Number(process.env.BOSTRAT_MEMORY_SPAWN_PULL_MS)||1500;BC=Number(process.env.BOSTRAT_MEMORY_HARVEST_DEBOUNCE_MS)||2e3,ys=new Map,Bp=new Set,Ab=Promise.resolve(),et={scheduled:0,runs:0,harvested:0,errors:0,lastRunAt:null,lastError:null,reconciles:0,lastReconcileAt:null,backfill:null};hl=new Map;Eb=!1,Ka=null;UC=20});import xl from"node:fs/promises";import WC from"node:path";async function Et(e,t,{mode:n}={}){await xl.mkdir(WC.dirname(e),{recursive:!0});let r=`${e}.${process.pid}.${++qC}.tmp`;try{await xl.writeFile(r,JSON.stringify(t,null,2)+`
43
- `,n!=null?{mode:n}:void 0),await xl.rename(r,e)}catch(o){throw await xl.unlink(r).catch(()=>{}),o}}var qC,vr=q(()=>{qC=0});import Wb from"node:fs/promises";import qb from"node:os";import Kb from"node:path";function Fe(e=process.env){return!!($e(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Xa(e,t={},n=process.env){let r=new AbortController,o=setTimeout(()=>r.abort(),KC);try{return await XC(`${$e(n)}${e}`,{...t,signal:r.signal})}finally{clearTimeout(o)}}async function zb(){return Sl||(qp||=Wb.readFile(Gb(),"utf8").then(e=>JSON.parse(e)).catch(()=>({ops:[]})).then(e=>Sl={ops:Array.isArray(e?.ops)?e.ops:[],parked:Array.isArray(e?.parked)?e.parked:[]}).finally(()=>qp=null),qp)}async function Tl(){await Et(Gb(),Sl).catch(()=>{})}function Ub(e){return e.op==="blob"?`blob ${e.family} ${e.id} ${e.v} ${e.kind}`:`${e.op} ${e.family} ${e.id}`}async function Gp(e){let t=await zb(),n=Ub(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=>Ub(o)===n);r>=0?t.ops[r]=e:t.ops.push(e)}t.ops.length>Lb&&(t.ops=t.ops.slice(-Lb)),await Tl()}function Hb(){vl||(vl=setTimeout(()=>{vl=null,ks().catch(()=>{})},ZC),vl.unref?.())}function Kp(e){let t=new Error(`plane ${e}`);return t.refused=!0,t}async function eM(e,t=process.env){if(e.op==="record"){let n=await Xa(`/v1/content/${encodeURIComponent(e.family)}`,{method:"POST",headers:{...Ya(t),"content-type":"application/json"},body:JSON.stringify({records:[{id:e.id,trackId:e.trackId??null,data:e.data,updatedAt:e.updatedAt,originNode:YC()}]})},t);if(!n.ok)throw Kp(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 Wb.readFile(e.path).catch(()=>null);if(!n)return{delivered:!0,dropped:"source file gone"};let r=await Xa(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}/blob?v=${e.v}&kind=${encodeURIComponent(e.kind)}`,{method:"POST",headers:{...Ya(t),"content-type":"application/octet-stream"},body:n},t);if(!r.ok&&r.status!==400)throw Kp(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 Xa(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}?deletedAt=${e.deletedAt}`,{method:"DELETE",headers:Ya(t)},t);if(!n.ok)throw Kp(n.status);return{delivered:!0}}return{delivered:!0,dropped:"unknown op"}}async function ks({env:e=process.env,log:t=console,now:n=Date.now()}={}){return Fe(e)?Ja||(Ja=(async()=>{let r=await zb();tM(r,n);let o=0,s=0;for(;r.ops.length;){let a=r.ops[0],i;try{i=await eM(a,e)}catch(c){if(!c?.refused)return Hb(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};if(a.refusals=(a.refusals||0)+1,a.refusals<zC)return Hb(),await Tl(),{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>Fb&&(r.parked=r.parked.slice(-Fb)),s++,await Tl();continue}i.rejected&&t.error?.(`[content-plane] ALARM plane rejected ${a.op} ${a.family}/${a.id}: ${i.rejected}`),r.ops.shift(),o++,await Tl()}return{flushed:o,parked:s,pending:0}})().finally(()=>{Ja=null}),Ja):{flushed:0,source:"unconfigured"}}function tM(e,t){if(!e.parked.length||e.ops.length)return;let n=e.parked.filter(r=>t-(r.parkedAt||0)>=QC);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 yt(e,t,{trackId:n=null,env:r=process.env}={}){return Fe(r)?(await Gp({op:"record",family:e,id:t.id,trackId:n??t.trackId??null,data:t,updatedAt:Number(t.updatedAt)||Date.now()}),ks({env:r})):{queued:!1,source:"unconfigured"}}async function Sr(e,t,n,r,o,{env:s=process.env}={}){return Fe(s)?(await Gp({op:"blob",family:e,id:t,v:Number(n),kind:r,path:o}),ks({env:s})):{queued:!1,source:"unconfigured"}}async function Zt(e,t,{deletedAt:n=Date.now(),env:r=process.env}={}){return Fe(r)?(await Gp({op:"delete",family:e,id:t,deletedAt:n}),ks({env:r})):{queued:!1,source:"unconfigured"}}async function st(e,{env:t=process.env}={}){if(!Fe(t))return{records:[],source:"unconfigured"};try{let n=await Xa(`/v1/content/${encodeURIComponent(e)}?tombstones=1`,{headers:Ya(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 Za(e,t,n,r,{env:o=process.env}={}){if(!Fe(o))return null;try{let s=await Xa(`/v1/content/${encodeURIComponent(e)}/${encodeURIComponent(t)}/blob?v=${Number(n)}&kind=${encodeURIComponent(r)}`,{headers:Ya(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 KC,GC,Lb,zC,Fb,VC,JC,Gb,YC,XC,ZC,QC,Ya,Sl,qp,vl,Ja,Tr=q(()=>{pt();vr();KC=1e4,GC=3e4,Lb=2e3,zC=5,Fb=100,VC=60*6e4,JC=()=>process.env.BOSTRAT_STATE_DIR||Kb.join(process.env.HOME||qb.tmpdir(),".bostrat"),Gb=()=>Kb.join(JC(),"content-outbox.json"),YC=()=>process.env.BOSTRAT_NODE_ID||qb.hostname(),XC=(...e)=>fetch(...e),ZC=GC,QC=VC;Ya=(e=process.env)=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`});Sl=null,qp=null,vl=null,Ja=null});import zp from"node:fs/promises";import Vb from"node:path";async function Jb(e,t,{box:n=null,agent:r=null}={}){if(!e||!Fe())return{pushed:!1};try{let o=Date.now();return await yt("checkpoints",{id:e,trackId:e,v:o,box:n,agent:r,updatedAt:o},{trackId:e}),await Sr("checkpoints",e,o,"md",t),Qa=null,{pushed:!0,v:o}}catch{return{pushed:!1}}}async function aM(){if(Qa&&Date.now()-Qa.at<sM)return{records:Qa.records,source:"plane"};let e=await st("checkpoints");return e.source==="plane"&&(Qa={at:Date.now(),records:e.records}),e}async function Al(e){try{let t=oM(e);if(!t||!Fe())return{restored:!1};let n=Vb.join(e,nM,rM);if(await zp.stat(n).then(()=>!0,()=>!1))return{restored:!1};let{records:r,source:o}=await aM();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 Za("checkpoints",t,s.data.v,"md");return typeof a!="string"||!a?{restored:!1}:(await zp.mkdir(Vb.dirname(n),{recursive:!0}),await zp.writeFile(n,a),{restored:!0,v:s.data.v})}catch{return{restored:!1}}}var nM,rM,oM,sM,Qa,El=q(()=>{Tr();nM=".bostrat/handoff",rM="latest.md",oM=e=>/workspaces[/\\]([0-9a-f]{8})$/.exec(e||"")?.[1]??null;sM=6e4,Qa=null});import ei from"node:fs/promises";import iM from"node:os";import Xb from"node:path";function go(e){let t=String(e??"");for(let n of cM)t=t.replace(n,"\u2039redacted\u203A");return t}function _l(){let e=process.env.BOSTRAT_HANDOFF_DEBUG;return e==="1"||e==="true"}async function lM(e){try{await ei.mkdir(Vp,{recursive:!0}),await ei.appendFile(xs,`${JSON.stringify(e)}
42
+ `;jC=Number(process.env.BOSTRAT_MEMORY_SPAWN_PULL_MS)||1500;LC=Number(process.env.BOSTRAT_MEMORY_HARVEST_DEBOUNCE_MS)||2e3,ys=new Map,Lp=new Set,Ab=Promise.resolve(),et={scheduled:0,runs:0,harvested:0,errors:0,lastRunAt:null,lastError:null,reconciles:0,lastReconcileAt:null,backfill:null};hl=new Map;Eb=!1,Ka=null;HC=20});import xl from"node:fs/promises";import qC from"node:path";async function Et(e,t,{mode:n}={}){await xl.mkdir(qC.dirname(e),{recursive:!0});let r=`${e}.${process.pid}.${++KC}.tmp`;try{await xl.writeFile(r,JSON.stringify(t,null,2)+`
43
+ `,n!=null?{mode:n}:void 0),await xl.rename(r,e)}catch(o){throw await xl.unlink(r).catch(()=>{}),o}}var KC,vr=q(()=>{KC=0});import Wb from"node:fs/promises";import qb from"node:os";import Kb from"node:path";function Fe(e=process.env){return!!($e(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Xa(e,t={},n=process.env){let r=new AbortController,o=setTimeout(()=>r.abort(),GC);try{return await ZC(`${$e(n)}${e}`,{...t,signal:r.signal})}finally{clearTimeout(o)}}async function zb(){return Sl||(Kp||=Wb.readFile(Gb(),"utf8").then(e=>JSON.parse(e)).catch(()=>({ops:[]})).then(e=>Sl={ops:Array.isArray(e?.ops)?e.ops:[],parked:Array.isArray(e?.parked)?e.parked:[]}).finally(()=>Kp=null),Kp)}async function Tl(){await Et(Gb(),Sl).catch(()=>{})}function Ub(e){return e.op==="blob"?`blob ${e.family} ${e.id} ${e.v} ${e.kind}`:`${e.op} ${e.family} ${e.id}`}async function zp(e){let t=await zb(),n=Ub(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=>Ub(o)===n);r>=0?t.ops[r]=e:t.ops.push(e)}t.ops.length>Lb&&(t.ops=t.ops.slice(-Lb)),await Tl()}function Hb(){vl||(vl=setTimeout(()=>{vl=null,ks().catch(()=>{})},QC),vl.unref?.())}function Gp(e){let t=new Error(`plane ${e}`);return t.refused=!0,t}async function tM(e,t=process.env){if(e.op==="record"){let n=await Xa(`/v1/content/${encodeURIComponent(e.family)}`,{method:"POST",headers:{...Ya(t),"content-type":"application/json"},body:JSON.stringify({records:[{id:e.id,trackId:e.trackId??null,data:e.data,updatedAt:e.updatedAt,originNode:XC()}]})},t);if(!n.ok)throw Gp(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 Wb.readFile(e.path).catch(()=>null);if(!n)return{delivered:!0,dropped:"source file gone"};let r=await Xa(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}/blob?v=${e.v}&kind=${encodeURIComponent(e.kind)}`,{method:"POST",headers:{...Ya(t),"content-type":"application/octet-stream"},body:n},t);if(!r.ok&&r.status!==400)throw Gp(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 Xa(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}?deletedAt=${e.deletedAt}`,{method:"DELETE",headers:Ya(t)},t);if(!n.ok)throw Gp(n.status);return{delivered:!0}}return{delivered:!0,dropped:"unknown op"}}async function ks({env:e=process.env,log:t=console,now:n=Date.now()}={}){return Fe(e)?Ja||(Ja=(async()=>{let r=await zb();nM(r,n);let o=0,s=0;for(;r.ops.length;){let a=r.ops[0],i;try{i=await tM(a,e)}catch(c){if(!c?.refused)return Hb(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};if(a.refusals=(a.refusals||0)+1,a.refusals<VC)return Hb(),await Tl(),{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>Fb&&(r.parked=r.parked.slice(-Fb)),s++,await Tl();continue}i.rejected&&t.error?.(`[content-plane] ALARM plane rejected ${a.op} ${a.family}/${a.id}: ${i.rejected}`),r.ops.shift(),o++,await Tl()}return{flushed:o,parked:s,pending:0}})().finally(()=>{Ja=null}),Ja):{flushed:0,source:"unconfigured"}}function nM(e,t){if(!e.parked.length||e.ops.length)return;let n=e.parked.filter(r=>t-(r.parkedAt||0)>=eM);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 yt(e,t,{trackId:n=null,env:r=process.env}={}){return Fe(r)?(await zp({op:"record",family:e,id:t.id,trackId:n??t.trackId??null,data:t,updatedAt:Number(t.updatedAt)||Date.now()}),ks({env:r})):{queued:!1,source:"unconfigured"}}async function Sr(e,t,n,r,o,{env:s=process.env}={}){return Fe(s)?(await zp({op:"blob",family:e,id:t,v:Number(n),kind:r,path:o}),ks({env:s})):{queued:!1,source:"unconfigured"}}async function Zt(e,t,{deletedAt:n=Date.now(),env:r=process.env}={}){return Fe(r)?(await zp({op:"delete",family:e,id:t,deletedAt:n}),ks({env:r})):{queued:!1,source:"unconfigured"}}async function st(e,{env:t=process.env}={}){if(!Fe(t))return{records:[],source:"unconfigured"};try{let n=await Xa(`/v1/content/${encodeURIComponent(e)}?tombstones=1`,{headers:Ya(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 Za(e,t,n,r,{env:o=process.env}={}){if(!Fe(o))return null;try{let s=await Xa(`/v1/content/${encodeURIComponent(e)}/${encodeURIComponent(t)}/blob?v=${Number(n)}&kind=${encodeURIComponent(r)}`,{headers:Ya(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 GC,zC,Lb,VC,Fb,JC,YC,Gb,XC,ZC,QC,eM,Ya,Sl,Kp,vl,Ja,Tr=q(()=>{pt();vr();GC=1e4,zC=3e4,Lb=2e3,VC=5,Fb=100,JC=60*6e4,YC=()=>process.env.BOSTRAT_STATE_DIR||Kb.join(process.env.HOME||qb.tmpdir(),".bostrat"),Gb=()=>Kb.join(YC(),"content-outbox.json"),XC=()=>process.env.BOSTRAT_NODE_ID||qb.hostname(),ZC=(...e)=>fetch(...e),QC=zC,eM=JC;Ya=(e=process.env)=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`});Sl=null,Kp=null,vl=null,Ja=null});import Vp from"node:fs/promises";import Vb from"node:path";async function Jb(e,t,{box:n=null,agent:r=null}={}){if(!e||!Fe())return{pushed:!1};try{let o=Date.now();return await yt("checkpoints",{id:e,trackId:e,v:o,box:n,agent:r,updatedAt:o},{trackId:e}),await Sr("checkpoints",e,o,"md",t),Qa=null,{pushed:!0,v:o}}catch{return{pushed:!1}}}async function iM(){if(Qa&&Date.now()-Qa.at<aM)return{records:Qa.records,source:"plane"};let e=await st("checkpoints");return e.source==="plane"&&(Qa={at:Date.now(),records:e.records}),e}async function Al(e){try{let t=sM(e);if(!t||!Fe())return{restored:!1};let n=Vb.join(e,rM,oM);if(await Vp.stat(n).then(()=>!0,()=>!1))return{restored:!1};let{records:r,source:o}=await iM();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 Za("checkpoints",t,s.data.v,"md");return typeof a!="string"||!a?{restored:!1}:(await Vp.mkdir(Vb.dirname(n),{recursive:!0}),await Vp.writeFile(n,a),{restored:!0,v:s.data.v})}catch{return{restored:!1}}}var rM,oM,sM,aM,Qa,El=q(()=>{Tr();rM=".bostrat/handoff",oM="latest.md",sM=e=>/workspaces[/\\]([0-9a-f]{8})$/.exec(e||"")?.[1]??null;aM=6e4,Qa=null});import ei from"node:fs/promises";import cM from"node:os";import Xb from"node:path";function go(e){let t=String(e??"");for(let n of lM)t=t.replace(n,"\u2039redacted\u203A");return t}function _l(){let e=process.env.BOSTRAT_HANDOFF_DEBUG;return e==="1"||e==="true"}async function uM(e){try{await ei.mkdir(Jp,{recursive:!0}),await ei.appendFile(xs,`${JSON.stringify(e)}
44
44
  `,"utf8");let n=(await ei.readFile(xs,"utf8")).split(`
45
45
  `).filter(Boolean);n.length>Yb&&await ei.writeFile(xs,`${n.slice(-Yb).join(`
46
46
  `)}
47
- `,"utf8")}catch(t){console.warn(`[handoff-debug] failed to write ${xs}: ${t?.message||t}`)}}async function le(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&&_l())try{t.paneTail=go((await je(t.sessionName,{lines:35})).slice(-4e3))}catch{t.paneTail=null}(_l()||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 lM(t)}async function Zb({limit:e=80}={}){try{return(await ei.readFile(xs,"utf8")).split(`
48
- `).filter(Boolean).slice(-e).map(r=>{try{let o=JSON.parse(r);return typeof o?.paneTail=="string"&&(o.paneTail=go(o.paneTail)),o}catch{return{raw:go(r)}}})}catch{return[]}}var cM,Vp,xs,Yb,Qb,kn=q(()=>{ct();cM=[/[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];Vp=process.env.BOSTRAT_DEBUG_DIR||Xb.join(iM.homedir(),".bostrat","debug"),xs=Xb.join(Vp,"handoff.jsonl"),Yb=Number(process.env.BOSTRAT_HANDOFF_DEBUG_MAX)||500;Qb={DEBUG_DIR:Vp,LOG_FILE:xs}});import Il from"node:fs/promises";import Jp from"node:path";import uM from"node:os";async function tk(e=ek){await Il.mkdir(e,{recursive:!0});for(let t of pM){let n=t==="prepare-commit-msg"?fM:t==="post-commit"?mM:`${Yp}exit 0
49
- `,r=Jp.join(e,t),o=null;try{o=await Il.readFile(r,"utf8")}catch{}o!==n&&await Il.writeFile(r,n,{mode:493}),await Il.chmod(r,493).catch(()=>{})}return e}function nk({nodeUrl:e,dir:t=ek,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",`${ti}=${e}`]}function rk(e=process.env){return e.BOSTRAT_NODE_URL||`http://127.0.0.1:${e.PORT||3362}`}var ti,dM,ek,pM,Yp,fM,mM,Xp=q(()=>{ds();ti="BOSTRAT_NODE_URL",dM=process.env.BOSTRAT_STATE_DIR||Jp.join(process.env.HOME||uM.tmpdir(),".bostrat"),ek=Jp.join(dM,"git-hooks"),pM=["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"],Yp=`#!/bin/sh
47
+ `,"utf8")}catch(t){console.warn(`[handoff-debug] failed to write ${xs}: ${t?.message||t}`)}}async function le(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&&_l())try{t.paneTail=go((await Be(t.sessionName,{lines:35})).slice(-4e3))}catch{t.paneTail=null}(_l()||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 uM(t)}async function Zb({limit:e=80}={}){try{return(await ei.readFile(xs,"utf8")).split(`
48
+ `).filter(Boolean).slice(-e).map(r=>{try{let o=JSON.parse(r);return typeof o?.paneTail=="string"&&(o.paneTail=go(o.paneTail)),o}catch{return{raw:go(r)}}})}catch{return[]}}var lM,Jp,xs,Yb,Qb,kn=q(()=>{ct();lM=[/[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];Jp=process.env.BOSTRAT_DEBUG_DIR||Xb.join(cM.homedir(),".bostrat","debug"),xs=Xb.join(Jp,"handoff.jsonl"),Yb=Number(process.env.BOSTRAT_HANDOFF_DEBUG_MAX)||500;Qb={DEBUG_DIR:Jp,LOG_FILE:xs}});import Il from"node:fs/promises";import Yp from"node:path";import dM from"node:os";async function tk(e=ek){await Il.mkdir(e,{recursive:!0});for(let t of fM){let n=t==="prepare-commit-msg"?mM:t==="post-commit"?hM:`${Xp}exit 0
49
+ `,r=Yp.join(e,t),o=null;try{o=await Il.readFile(r,"utf8")}catch{}o!==n&&await Il.writeFile(r,n,{mode:493}),await Il.chmod(r,493).catch(()=>{})}return e}function nk({nodeUrl:e,dir:t=ek,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",`${ti}=${e}`]}function rk(e=process.env){return e.BOSTRAT_NODE_URL||`http://127.0.0.1:${e.PORT||3362}`}var ti,pM,ek,fM,Xp,mM,hM,Zp=q(()=>{ds();ti="BOSTRAT_NODE_URL",pM=process.env.BOSTRAT_STATE_DIR||Yp.join(process.env.HOME||dM.tmpdir(),".bostrat"),ek=Yp.join(pM,"git-hooks"),fM=["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"],Xp=`#!/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,7 +61,7 @@ esac
61
61
  if [ -x "$orig/$hook" ] && [ "$orig/$hook" != "$0" ]; then
62
62
  "$orig/$hook" "$@" || exit $?
63
63
  fi
64
- `,fM=`${Yp}
64
+ `,mM=`${Xp}
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
67
  [ -z "$${Un}" ] && exit 0
@@ -73,7 +73,7 @@ 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
- `,mM=`${Yp}
76
+ `,hM=`${Xp}
77
77
  # \u2500\u2500 bostrat: report the commit (code.committed + rework analysis, node-side).
78
78
  [ -z "$${Un}" ] && exit 0
79
79
  [ -z "$${ti}" ] && exit 0
@@ -82,54 +82,54 @@ cwd=$(git rev-parse --show-toplevel 2>/dev/null)
82
82
  printf '{"sha":"%s","cwd":"%s"}' "$sha" "$cwd" | curl -sS -m 5 -X POST "$${ti}/api/git/committed" \\
83
83
  -H 'content-type: application/json' -H "${Hn}: $${Un}" --data-binary @- >/dev/null 2>&1 || true
84
84
  exit 0
85
- `});import{execFile as sk}from"node:child_process";import{promisify as hM}from"node:util";import Rl from"node:fs";import{randomUUID as ak}from"node:crypto";function Ts(e){return new Promise(t=>setTimeout(t,e))}function $l(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 ik(e){return`/tmp/tmux-${e}/default`}function wM({explicit:e,legacyExists:t,runtimeDir:n,uid:r}){if(e)return e;let o=ik(r);return t?o:n?`${n}/bostrat/tmux-default`:o}function ri(){return process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1"?[]:["-e",`${ni}=1`]}function oi(e,t,n){let r=yo(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 yo(e){return/(^|\/|\s)claude(\s|$)/.test(String(e||""))}function Ar(e){return/(^|\/|\s)claude(\s|$)/.test(e)?"claude":/cursor/.test(e)?"cursor":/codex/.test(e)?"codex":/gemini/.test(e)?"gemini":"agent"}function bM(e){let t=String(e||"").trim();return!t||/fake-|\.sh(\s|$)/.test(t)?!1:yo(t)||/(^|\/|\s)codex(\s|$)/.test(t)||/cursor-agent/.test(t)||/(^|\/|\s)gemini(\s|$)/.test(t)}async function ck(e,{loginShell:t=!1,failOpen:n=!1}={}){let r=await lk(e,{loginShell:t});return r===Ol?!0:r===vs?!1:n}async function lk(e,{loginShell:t=!1,timeoutMs:n=Zp}={}){if(!e)return vs;let r=t?process.env.SHELL||"/bin/sh":"sh",o=t?"-lic":"-c";try{return await Re(r,[o,'command -v "$1" >/dev/null 2>&1',"_",e],{timeout:n}),Ol}catch(s){return s?.killed||s?.signal?Ss:s?.code===1||s?.code===127?vs:Ss}}async function Cl(e,{retries:t=kM,sleep:n=xM,probe:r=lk}={}){let o=String(e||"").trim().split(/\s+/)[0],s=await r(o,{timeoutMs:Zp});for(let a=0;s===Ss&&a<t.length;a++)await n(t[a]),s=await r(o,{timeoutMs:Zp*2});return s}function Z(...e){return["-S",Rt,...e]}async function Er(){if(!Rl.existsSync(Rt))return!1;try{return await Re(X,Z("list-sessions")),!0}catch(e){let t=e&&e.stderr?String(e.stderr):"";return!/no server running/i.test(t)}}async function si(){if(await Er())return!0;try{Rl.mkdirSync(Rt.replace(/\/[^/]+$/,""),{recursive:!0}),await Re(X,Z("new-session","-d","-s","keeper","sleep 2147483647"))}catch{}return await Er()}function Be(e){return typeof e=="string"&&vM.test(e)}async function Qt(){if(!Rl.existsSync(Rt))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 Re(X,Z("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=>!yM.has(r.name)&&!r.name.startsWith("bostrat-view-"))}catch{return[]}}async function ke(e){return(await Qt()).find(n=>n.name===e)||null}function AM(e){if(typeof e!="string")return!1;let t=e.trim();return t.length>=1&&t.length<=TM&&SM.test(t)}function Ml(e){return e.trim().replace(/\s+/g,"-").toLowerCase().replace(/[^A-Za-z0-9_.-]/g,"").replace(/^-+|-+$/g,"")}async function uk(e){try{let{stdout:t}=await Re(X,Z("list-sessions","-F","#{session_name}"));return t.split(`
87
- `).map(n=>n.trim()).includes(e)}catch{return!1}}function IM(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 $M(e,t){let n=Date.now()+ai(),r=IM(t),o=!1,s=0,a=0;for(;;){if(await Ts(EM),s+=1,!await uk(e))return;let i=await je(e,{lines:15}),c=!o&&_M.test(i)&&!!r?.test(i),l=!o&&!!r?.test(i);if(!c&&!l&&s>1&&!await Kn(e)){if(a+=1,a>1)return}else c||(a=0);if(c){o=!0,await le({flow:"spawn",phase:"launch-retry",sessionName:e,agent:Ar(t),promptHead:t.slice(0,120)}).catch(()=>{}),await Re(X,Z("send-keys","-t",e,"C-u")),await Re(X,Z("send-keys","-t",e,"-l",t)),await Re(X,Z("send-keys","-t",e,"Enter"));continue}if(Date.now()>n){await le({flow:"spawn",phase:"launch-failed",sessionName:e,agent:Ar(t),retried:o,error:"agent CLI never started after launch was typed"}).catch(()=>{});return}}}async function _r(e,t=gM,n={}){if(!AM(e))throw new Error("displayName must be 1\u201364 chars (letters, digits, space . _ -)");let r=e.trim(),o=Ml(r);if(!Be(o))throw new Error("resulting tmux session name is invalid");if(!await si())throw new Error(`host tmux server not running on ${Rt} and auto-start failed \u2014 start one: ${X} -S ${Rt} new-session -d -s keeper "sleep 2147483647"`);if(await uk(o))throw new Error(`tmux session "${o}" already exists`);let s=n.agentCmd||Qp,a=n.agent||Ar(s),i=!!n.resumeSessionId,c=n.resumeSessionId||ak(),l=i?s:oi(s,c,o),u=i?n.pinned===!0:/(^|\s)--session-id(\s|=)/.test(l),d=a==="claude"&&yo(s),p=n.firstRun===!0;p||(d&&await yr(t),a==="codex"&&await ps(t),a==="cursor"&&await fs(t),await Cb(t),n.freshWorkspace!==!0&&await Al(t));let f=d&&!p?al():null,w=Zy(),m=["-e",`${Un}=${w}`];m.push(...nk({nodeUrl:rk()})),f&&m.push("-e",`ANTHROPIC_API_KEY=${f}`),d&&m.push(...ri());try{await Re(X,Z("new-session","-d","-s",o,"-c",t,...m))}catch(g){throw $l(f?$l(g,f):g,w)}return await bo(o),await Re(X,Z("set-option","-t",o,"@bostrat-session","1")),await Re(X,Z("set-option","-t",o,"@bostrat-title",r)),await Re(X,Z("set-option","-t",o,"@bostrat-sid",c)),await Re(X,Z("set-option","-t",o,"@bostrat-agent",a)),await Re(X,Z("send-keys","-t",o,l,"Enter")),bM(l)&&$M(o,l).catch(()=>{}),{name:o,title:r,cwd:t,sessionId:c,agent:a,pinned:u,hookToken:w}}async function en(e){if(!Be(e))throw new Error("invalid session name");await Re(X,Z("kill-session","-t",e))}async function dk(e,t){if(Be(e))try{let n=t?Z("set-option","-t",e,"@bostrat-sid",t):Z("set-option","-u","-t",e,"@bostrat-sid");await Re(X,n)}catch{}}async function je(e,{lines:t=40}={}){if(!Be(e))return"";try{let n=Z("capture-pane","-t",e,"-p");Number.isFinite(t)&&t>0&&n.push("-S",`-${Math.floor(t)}`);let{stdout:r}=await Re(X,n);return String(r||"")}catch{return""}}async function pk(e){if(!Be(e))return[];try{let{stdout:t}=await Re(X,Z("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 fk(e){if(!Be(e))return 0;try{let{stdout:t}=await Re(X,Z("list-clients","-t",e,"-F","1"));return String(t||"").trim().split(`
89
- `).filter(Boolean).length}catch{return 0}}async function bo(e,{cols:t=CM,rows:n=MM}={}){if(!Be(e))return!0;if(await fk(e))return!1;try{let r=await mk(e);if(r.cols===t&&r.rows===n)return!0;await Re(X,Z("resize-window","-t",e,"-x",String(t),"-y",String(n))),await Re(X,Z("set-window-option","-t",e,"window-size","latest")),await Ts(80)}catch{}return!0}async function NM(e){if(!Be(e))return 0;try{let{stdout:t}=await Re(X,Z("display-message","-t",e,"-p","#{pane_pid}"));return Number(String(t||"").trim())||0}catch{return 0}}async function Kn(e){let t=await NM(e);if(!t)return!1;try{return await Re("pgrep",["-P",String(t)]),!1}catch(n){return n?.code===1}}async function mk(e){if(!Be(e))return{cols:0,rows:0};try{let{stdout:t}=await Re(X,Z("display-message","-t",e,"-p","#{window_width} #{window_height}")),[n,r]=String(t||"").trim().split(/\s+/).map(o=>Number(o)||0);return{cols:n,rows:r}}catch{return{cols:0,rows:0}}}async function Nl(e,{cols:t=RM,rows:n=OM}={}){if(Be(e)&&!await fk(e))try{let r=await mk(e),o=Math.max(r.cols,t),s=Math.max(r.rows,n);(o>r.cols||s>r.rows)&&(await Re(X,Z("resize-window","-t",e,"-x",String(o),"-y",String(s))),await Re(X,Z("set-window-option","-t",e,"window-size","latest")),await Ts(80))}catch{}}async function Gn(e){return await Nl(e),je(e,{lines:tt})}async function Ke(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=>PM.has(s));for(let s=0;s<o.length;s++)await Re(X,Z("send-keys","-t",e,o[s])),n>0&&s<o.length-1&&await Ts(n);return le({flow:"tmux",phase:"send-keys",sessionName:e,kind:r||"keys",keys:o.join(" ")}).catch(()=>{}),o.length}async function As(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 Re(X,Z("send-keys","-t",e,"-N",String(r),"BSpace")),le({flow:"tmux",phase:"send-keys",sessionName:e,kind:n||"wipe",keys:`BSpace x${r}`}).catch(()=>{}),r}async function Dl(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 Re(X,Z("send-keys","-t",e,"-l",s)),n>0&&await Ts(n);le({flow:"tmux",phase:"type",sessionName:e,kind:r||"type",textLen:o.length,textHead:String(t).slice(0,120)}).catch(()=>{})}function DM(e,t){return new Promise((n,r)=>{let o=sk(X,Z(...e),(s,a,i)=>{s?r(s):n({stdout:a,stderr:i})});o.stdin.on("error",()=>{}),o.stdin.end(t)})}async function jM(e,t){let n=`bostrat-${ak().slice(0,8)}`;await DM(["load-buffer","-b",n,"-"],t),await Re(X,Z("paste-buffer","-p","-d","-b",n,"-t",e))}async function nt(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 jM(e,t):await Re(X,Z("send-keys","-t",e,"-l",t))),n){let a=Number(r);Number.isFinite(a)&&a>0&&await Ts(a),await Re(X,Z("send-keys","-t",e,"Enter"))}le({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 Re,X,ok,Rt,gM,Qp,ni,ef,yM,Ol,vs,Ss,Zp,kM,xM,tf,vM,SM,TM,ai,EM,_M,RM,OM,tt,CM,MM,PM,Pl,ct=q(()=>{Ua();cl();ll();Va();El();kn();ds();Xp();Re=hM(sk);X=process.env.BOSTRAT_TMUX_BIN||"/usr/bin/tmux";ok=typeof process.getuid=="function"?process.getuid():0,Rt=wM({explicit:process.env.BOSTRAT_TMUX_SOCKET,legacyExists:(()=>{try{return Rl.existsSync(ik(ok))}catch{return!1}})(),runtimeDir:process.env.XDG_RUNTIME_DIR,uid:ok}),gM=process.env.BOSTRAT_DEFAULT_CWD||process.env.HOME||"/",Qp=process.env.BOSTRAT_AGENT_CMD||"claude --dangerously-skip-permissions",ni="CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN";ef="bostrat-usage-probe",yM=new Set([ef]);Ol="present",vs="absent",Ss="unknown",Zp=5e3,kM=[250,1e3,3e3],xM=e=>new Promise(t=>setTimeout(t,e));tf={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"};vM=/^[A-Za-z0-9_.-]{1,64}$/;SM=/^[A-Za-z0-9 ._↻-]+$/,TM=64;ai=()=>Number(process.env.BOSTRAT_LAUNCH_VERIFY_MS)||12e3,EM=1e3,_M=/not found|Unknown command/i;RM=Number(process.env.BOSTRAT_PROMPT_CAPTURE_COLS)||100,OM=Number(process.env.BOSTRAT_PROMPT_CAPTURE_ROWS)||40,tt=Number(process.env.BOSTRAT_PROMPT_CAPTURE_LINES)||80,CM=Number(process.env.BOSTRAT_BOX_COLS)||120,MM=Number(process.env.BOSTRAT_BOX_ROWS)||40;PM=new Set(["Up","Down","Left","Right","Space","Enter","Tab","BTab","Escape","BSpace"]);Pl=1600});import ii from"node:fs";import WM from"node:fs/promises";import Es from"node:path";import qM from"node:os";function of(e){return e.replace(/[^A-Za-z0-9]/g,"-")}function sf(e){let t=Es.join(rf,of(e)),n;try{n=ii.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return null}let r=null;for(let o of n){let s=Es.join(t,o);try{let{mtimeMs:a}=ii.statSync(s);(!r||a>r.mtimeMs)&&(r={full:s,mtimeMs:a})}catch{}}return r?r.full:null}function tn(e,t){if(!t)return null;let n=Es.join(rf,of(e),`${t}.jsonl`);return ii.existsSync(n)?n:null}function xk(e){if(!e)return[];let t=Es.join(rf,of(e)),n;try{n=ii.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return[]}let r=[];for(let o of n)try{let s=ii.statSync(Es.join(t,o));r.push({id:o.slice(0,-6),birthMs:s.birthtimeMs||s.ctimeMs||s.mtimeMs})}catch{}return r}async function _t(e,t=131072){let n=await WM.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 GM(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 ci(e,t=null,{fallbackNewest:n=!0}={}){if(!e)return null;let r,o;if(t){if(r=tn(e,t),o=!0,!r)return null}else if(n){if(r=sf(e),o=!1,!r)return null}else return null;let s;try{s=GM(await _t(r))}catch{return null}if(!s)return null;let a=Object.prototype.hasOwnProperty.call(kk,s.model),i=kk[s.model]||KM;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 kk,KM,rf,nn=q(()=>{kk={"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},KM=2e5,rf=process.env.BOSTRAT_CLAUDE_PROJECTS||Es.join(qM.homedir(),".claude","projects")});function zM(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 li(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 ui(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 Ne(e,t=new Set){let n=[];for(let r=1;r<e.length;r++){let o=e[r];if(o==="<<")break;if(Tk(o)){t.has(o)&&r++;continue}n.push(o)}return n}function Ak(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 YM(e){let t=Ak(e),n=ft(Ne(e).find(r=>!/^\d+(,\d+)?p$/.test(r)));return t&&n?t.from===t.to?`Read line ${t.from} of ${Ge(n)}`:`Read lines ${t.from}\u2013${t.to} of ${Ge(n)}`:e.includes("-i")&&n?`Edit ${Ge(n)}`:null}function af(e){if(e.includes("--files")){let s=ft(Ne(e,vk)[0]);return s&&s!=="."?`List files in ${_s(s)}`:"List files"}let t=Ne(e,vk),n=t[0];if(!n)return null;let r=ft(t.slice(1).find(s=>s!==".")),o=Is(n,40);return r?`Search for \u201C${o}\u201D in ${_s(r)}`:`Search for \u201C${o}\u201D`}function cf(e){let t=Ne(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 lf(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=Ne(e)[0];return n?`Run ${Ge(n)}`:null}function XM(e){let t=Ne(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 Sk(e){return e.find(t=>/^https?:\/\//.test(t))||null}function eN(e){let t=ui(li(e));if(!t.length)return null;if(/^(ba|z)?sh$/.test(Ge(t[0]))&&(t[1]==="-lc"||t[1]==="-c")&&t[2])return uf(t[2]);let n=Ge(t[0]);if(QM.has(n))return null;if(t.includes("--version"))return`Check ${n} version`;if(n.endsWith(".sh"))return`Run ${n}`;let r=ZM[n];return r?r(t.map((o,s)=>s===0?n:o)):null}function uf(e){let t=String(e||"").trim();if(!t)return null;let n=t.indexOf("<<");if(n!==-1){let i=t.indexOf(`
92
- `,n);i!==-1&&(t=t.slice(0,i))}let r=zM(t);for(let i=0;i<r.length-1;i++){let c=ui(li(r[i])),l=ui(li(r[i+1]));if(!(!c.length||!l.length)&&["nl","cat"].includes(Ge(c[0]))&&Ge(l[0])==="sed"){let u=Ak(l),d=Ne(c)[0];if(u&&d)return Is(u.from===u.to?`Read line ${u.from} of ${Ge(d)}`:`Read lines ${u.from}\u2013${u.to} of ${Ge(d)}`,88)}}let o=[];for(let i of r){let c=eN(i);c&&o.push({d:c,head:Ge(ui(li(i))[0]||""),sub:Ne(ui(li(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":Is(s?s.d:o[0].d,88)}var Is,ft,Ge,_s,Tk,vk,VM,JM,ZM,QM,Ek=q(()=>{Is=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,ft=e=>e&&!/[$`]/.test(e)?e:null,Ge=e=>e.replace(/\/+$/,"").split("/").pop()||e,_s=e=>{let t=e.replace(/\/+$/,"").split("/").filter(Boolean);return t.length>3?t.slice(-2).join("/"):e},Tk=e=>e.startsWith("-"),vk=new Set(["-g","--glob","-t","--type","-A","-B","-C","-m","--max-count","-e","--regexp","-f","--file"]);VM={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 ${Ge(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"},JM={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"};ZM={git:e=>{let t=Ne(e,new Set(["-C","-c"])),n=VM[t[0]];return n?n(t,e):null},gh:e=>{let t=Ne(e),n=JM[t[0]];return n?n(t):null},sed:YM,rg:af,grep:af,egrep:af,nl:e=>{let t=ft(Ne(e)[0]);return t?`Read ${Ge(t)}`:null},cat:e=>{let t=ft(Ne(e)[0]);return t?`Read ${Ge(t)}`:null},head:e=>{let t=ft(Ne(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the start of ${Ge(t)}`:null},tail:e=>{let t=ft(Ne(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the end of ${Ge(t)}`:null},wc:e=>{let t=ft(Ne(e)[0]);return t?`Count lines in ${Ge(t)}`:"Count input lines"},ls:e=>{let t=ft(Ne(e)[0]);return t&&t!=="."?`List files in ${_s(t)}`:"List files"},find:e=>ft(e[1])&&!Tk(e[1])&&e[1]!=="."?`Find files in ${_s(e[1])}`:"Find files",tree:()=>"List the directory tree",mkdir:e=>{let t=ft(Ne(e)[0]);return t?`Create directory ${_s(t)}`:null},touch:e=>{let t=ft(Ne(e)[0]);return t?`Create ${Ge(t)}`:null},rm:e=>{let t=ft(Ne(e)[0]);return t?`Delete ${_s(t)}`:null},mv:e=>{let t=ft(Ne(e)[0]);return t?`Move ${Ge(t)}`:null},cp:e=>{let t=ft(Ne(e)[0]);return t?`Copy ${Ge(t)}`:null},chmod:e=>{let t=ft(Ne(e)[1]);return t?`Change permissions on ${Ge(t)}`:null},diff:e=>{let t=Ne(e);return t.length>=2?`Compare ${Ge(t[0])} and ${Ge(t[1])}`:null},curl:e=>{let t=Sk(e);return t?`Fetch ${Is(t,56)}`:"Fetch a URL"},wget:e=>{let t=Sk(e);return t?`Fetch ${Is(t,56)}`:"Fetch a URL"},npm:cf,pnpm:cf,yarn:cf,npx:e=>{let t=Ne(e)[0];return t?`Run ${t}`:null},node:e=>lf(e,"Node"),python:e=>lf(e,"Python"),python3:e=>lf(e,"Python"),make:e=>{let t=Ne(e)[0];return t?`Run make ${t}`:"Run make"},systemctl:XM,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=Ne(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=Ne(e)[0];return t?`Locate ${t}`:null},command:e=>e[1]==="-v"&&e[2]?`Locate ${e[2]}`:null,fly:e=>{let t=Ne(e)[0];return t==="deploy"?"Deploy to Fly":t?`Run fly ${t}`:null}},QM=new Set(["pwd","echo","cd","sleep","true","false","test","[","set","export","exit","read"])});function $s(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 Ir(e,t=""){let n=t.trim();return n||uf(e)||$s(e)}function df(e,t){if(e){if(Array.isArray(e)){for(let n of e)df(n,t);return}if(typeof e=="object"){if(e.type==="tool_use"&&pf.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))df(n,t)}}}async function _k(e,{maxBytes:t=1048576,limit:n=400}={}){let r;try{r=await _t(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(df(c.content,l),!l.length)continue;let u=i.timestamp?Date.parse(i.timestamp):null;for(let d of l)o.push({...d,summary:Ir(d.command,d.description),ts:u})}return o.slice(-n)}function Ik(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(...tN(i,r.get(a)||[]));return s.sort((a,i)=>(a.ts||0)-(i.ts||0))}function tN(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 pf,Rs=q(()=>{nn();Ek();pf=new Set(["Bash"])});import $k from"node:fs";import mf from"node:fs/promises";import ff from"node:path";import nN from"node:os";async function Rk(e){try{return await mf.realpath(e)}catch{return e}}function oN(e=rN){let t=[],n=r=>{let o;try{o=$k.readdirSync(r,{withFileTypes:!0})}catch{return}for(let s of o){let a=ff.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:$k.statSync(a).mtimeMs})}catch{}}}};return n(e),t.sort((r,o)=>o.mtimeMs-r.mtimeMs)}async function sN(e,t=1048576){let n;try{n=await mf.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 aN(e){let t=await sN(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 ko(e,t){if(!e&&!t)return null;let n=oN();if(t){let o=n.find(s=>s.id===t);return o||null}let r=await Rk(e);for(let o of n){let s=await aN(o.file);if(s&&(s===e||await Rk(s)===r))return o}return null}async function Ok(e,t,{limit:n=80,maxBytes:r=524288}={}){let o=await ko(e,t);if(!o)return[];let s;try{s=await _t(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:xo,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,hf.has(m.name)||c.push(m.name);continue}if(m.type!=="message"||m.role!=="assistant")continue;u=!0;let g=cN(m.content),b=c.length?c.slice():null;c=[],!(!g&&!b)&&a.push({role:"assistant",text:g,tools:b||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 lN(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 uN(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 dN(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=uN(i.slice(c.index+c[0].length).trimStart());l&&l.trim()&&o.push(l.trim())}),o}async function Ck(e,t,{limit:n=400,maxBytes:r=524288}={}){let o=await ko(e,t);if(!o)return[];let s;try{s=await _t(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"&&di.has(u.name)){let f;try{f=JSON.parse(u.arguments||"{}")}catch{continue}let w=lN(f);w&&(d=[w])}else u.type==="custom_tool_call"&&u.name==="exec"&&(d=dN(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:Ir(f),ts:l.timestamp?Date.parse(l.timestamp):null})})}return a.slice(-n)}async function Mk(e,t){let n=await ko(e,t);if(!n)return null;try{return Math.round((await mf.stat(n.file)).mtimeMs)}catch{return n.mtimeMs||null}}var rN,iN,cN,di,hf,xo,vo=q(()=>{nn();Rs();rN=process.env.BOSTRAT_CODEX_SESSIONS||ff.join(process.env.CODEX_HOME||ff.join(nN.homedir(),".codex"),"sessions");iN=new Set(["output_text","text"]),cN=e=>typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&typeof t.text=="string"&&iN.has(t.type)).map(t=>t.text).join(`
99
- `).trim():"";di=new Set(["exec_command","shell","exec"]),hf=new Set(["wait","write_stdin"]),xo="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 pi({error:e=null,status:t=null,text:n=""}={}){let r=String(e||"").trim().toLowerCase();if(r&&Nk.has(r))return Nk.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 Pk(e){if(!e||e.role!=="assistant")return null;if(e.apiError){let t=e.apiError;return{cls:t.cls||pi({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===xo?"other":pi({text:t}),code:null,status:null,requestId:null}}return null}function Dk(e,{codexFailedText:t=null}={}){let n=String(e?.text||"").trim();return n?e?.model==="<synthetic>"?/^No response requested\.$/.test(n)?null:{cls:pi({text:n}),code:null,status:pN(n),requestId:null,text:n}:t&&n===t?{cls:"other",code:null,status:null,requestId:null,text:n}:null:null}function pN(e){let t=/^API Error:\s*(\d{3})\b/.exec(e);return t?Number(t[1]):null}var YG,Nk,Bl=q(()=>{vo();YG=Object.freeze(["entitlement","auth","rate_limit","overloaded","server","other"]),Nk=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 fN(e,t){return!e||!t?null:tn(e,t)}function mN(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 hN(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 wN(e){return Array.isArray(e)&&e.length>0&&e.every(t=>t&&t.type==="tool_result")}function wf(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 jk(e,t){if(!e.uuid)return null;let n=wf(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 gf(e,{maxBytes:t=524288,limit:n=80}={}){let r;try{r=await _t(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 b=l.attachment;b?.type==="queued_command"&&b.commandMode==="task-notification"&&typeof b.prompt=="string"&&b.prompt.trim()&&o.push({role:"user",text:b.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 b of u.content){let x=b?.type==="tool_use"?b.input?.file_path||b.input?.path:null;typeof x=="string"&&gN.test(x)&&s.set(b.id,x.split("/").pop()),b?.type==="tool_use"&&b.name==="Skill"&&b.id&&a.set(b.id,String(b.input?.skill||"").trim().replace(/^\//,"")||null)}if(wN(u.content)){let b=jk(l,s);b&&o.push({role:"assistant",text:"",images:b,ts:l.timestamp?Date.parse(l.timestamp):null,model:null});continue}let p=mN(u.content),f=d==="assistant"?hN(u.content):null,w=d==="user"?jk(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:pi({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 Bk(e,t,{turns:n=16}={}){let r=fN(e,t);if(!r)return"";let o=await gf(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}:** ${yN(s.text||c,700)} ${i}`.trim()}).join(`
102
-
103
- `):""}var gN,yN,Ll=q(()=>{Bl();nn();gN=/\.(png|jpe?g|gif|webp|bmp|svg|tiff?|avif|heic|heif|ico)$/i;yN=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e});import bN from"node:fs/promises";import{execFile as kN}from"node:child_process";import{promisify as xN}from"node:util";function Hk(e){bf=typeof e=="function"?e:null}function kf(e){let t=String(e||""),n=t.indexOf("/lib/node_modules/");return n>0?t.slice(0,n):null}function Wk({sessionName:e,from:t,to:n}={}){let r=String(n||"").trim();!r||Lk.has(r)||(Lk.add(r),Fk=Fk.then(()=>SN({sessionName:e,from:t,to:r})).catch(()=>{}))}async function SN({sessionName:e,from:t,to:n}){await le({flow:"codex-update",phase:"start",sessionName:e,from:t,to:n}).catch(()=>{});try{let r=(await yf("/bin/sh",["-c","command -v codex"])).stdout.trim();if(!r)throw new Error("codex not on PATH");let o=await bN.realpath(r),s=kf(o),a=s?{...process.env,PATH:`${s}/bin:${process.env.PATH||""}`}:process.env;await yf("npm",["install","-g","@openai/codex"],{env:a,timeout:vN});let i=(await yf(r,["--version"])).stdout.trim().replace(/^codex-cli\s*/,"")||n;await le({flow:"codex-update",phase:"done",sessionName:e,from:t,to:n,version:i}).catch(()=>{}),await Uk({sessionName:e,from:t,to:n,version:i,status:"updated"})}catch(r){let o=String(r?.message||r).slice(0,300);await le({flow:"codex-update",phase:"failed",sessionName:e,from:t,to:n,error:o}).catch(()=>{}),await Uk({sessionName:e,from:t,to:n,status:"failed",error:o})}}async function Uk(e){if(bf)try{await bf(e)}catch{}}var yf,vN,Lk,Fk,bf,Fl=q(()=>{kn();yf=xN(kN),vN=Number(process.env.BOSTRAT_CODEX_UPDATE_TIMEOUT_MS)||5*6e4,Lk=new Set,Fk=Promise.resolve(),bf=null});function AN(e,{provider:t,box:n}){let r=String(e).replace(/\r/g,"").split(`
104
- `);if(!qk.test(e))return null;let o=[],s=!1;for(let l=r.length-1;l>=0;l--){let u=r[l].match(TN);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"&&qk.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 So(e){let t=String(e??"").replace(/\r/g,""),n=t.split(`
85
+ `});import{execFile as sk}from"node:child_process";import{promisify as wM}from"node:util";import Rl from"node:fs";import{randomUUID as ak}from"node:crypto";function Ts(e){return new Promise(t=>setTimeout(t,e))}function $l(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 ik(e){return`/tmp/tmux-${e}/default`}function gM({explicit:e,legacyExists:t,runtimeDir:n,uid:r}){if(e)return e;let o=ik(r);return t?o:n?`${n}/bostrat/tmux-default`:o}function ri(){return process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1"?[]:["-e",`${ni}=1`]}function oi(e,t,n){let r=yo(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&&je(n)&&(s+=` --name ${n}`),s}function yo(e){return/(^|\/|\s)claude(\s|$)/.test(String(e||""))}function Ar(e){return/(^|\/|\s)claude(\s|$)/.test(e)?"claude":/cursor/.test(e)?"cursor":/codex/.test(e)?"codex":/gemini/.test(e)?"gemini":"agent"}function kM(e){let t=String(e||"").trim();return!t||/fake-|\.sh(\s|$)/.test(t)?!1:yo(t)||/(^|\/|\s)codex(\s|$)/.test(t)||/cursor-agent/.test(t)||/(^|\/|\s)gemini(\s|$)/.test(t)}async function ck(e,{loginShell:t=!1,failOpen:n=!1}={}){let r=await lk(e,{loginShell:t});return r===Ol?!0:r===vs?!1:n}async function lk(e,{loginShell:t=!1,timeoutMs:n=Qp}={}){if(!e)return vs;let r=t?process.env.SHELL||"/bin/sh":"sh",o=t?"-lic":"-c";try{return await Re(r,[o,'command -v "$1" >/dev/null 2>&1',"_",e],{timeout:n}),Ol}catch(s){return s?.killed||s?.signal?Ss:s?.code===1||s?.code===127?vs:Ss}}async function Cl(e,{retries:t=xM,sleep:n=vM,probe:r=lk}={}){let o=String(e||"").trim().split(/\s+/)[0],s=await r(o,{timeoutMs:Qp});for(let a=0;s===Ss&&a<t.length;a++)await n(t[a]),s=await r(o,{timeoutMs:Qp*2});return s}function Z(...e){return["-S",Rt,...e]}async function Er(){if(!Rl.existsSync(Rt))return!1;try{return await Re(X,Z("list-sessions")),!0}catch(e){let t=e&&e.stderr?String(e.stderr):"";return!/no server running/i.test(t)}}async function si(){if(await Er())return!0;try{Rl.mkdirSync(Rt.replace(/\/[^/]+$/,""),{recursive:!0}),await Re(X,Z("new-session","-d","-s","keeper","sleep 2147483647"))}catch{}return await Er()}function je(e){return typeof e=="string"&&SM.test(e)}async function Qt(){if(!Rl.existsSync(Rt))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 Re(X,Z("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=>!bM.has(r.name)&&!r.name.startsWith("bostrat-view-"))}catch{return[]}}async function ke(e){return(await Qt()).find(n=>n.name===e)||null}function EM(e){if(typeof e!="string")return!1;let t=e.trim();return t.length>=1&&t.length<=AM&&TM.test(t)}function Ml(e){return e.trim().replace(/\s+/g,"-").toLowerCase().replace(/[^A-Za-z0-9_.-]/g,"").replace(/^-+|-+$/g,"")}async function uk(e){try{let{stdout:t}=await Re(X,Z("list-sessions","-F","#{session_name}"));return t.split(`
87
+ `).map(n=>n.trim()).includes(e)}catch{return!1}}function $M(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 RM(e,t){let n=Date.now()+ai(),r=$M(t),o=!1,s=0,a=0;for(;;){if(await Ts(_M),s+=1,!await uk(e))return;let i=await Be(e,{lines:15}),c=!o&&IM.test(i)&&!!r?.test(i),l=!o&&!!r?.test(i);if(!c&&!l&&s>1&&!await Kn(e)){if(a+=1,a>1)return}else c||(a=0);if(c){o=!0,await le({flow:"spawn",phase:"launch-retry",sessionName:e,agent:Ar(t),promptHead:t.slice(0,120)}).catch(()=>{}),await Re(X,Z("send-keys","-t",e,"C-u")),await Re(X,Z("send-keys","-t",e,"-l",t)),await Re(X,Z("send-keys","-t",e,"Enter"));continue}if(Date.now()>n){await le({flow:"spawn",phase:"launch-failed",sessionName:e,agent:Ar(t),retried:o,error:"agent CLI never started after launch was typed"}).catch(()=>{});return}}}async function _r(e,t=yM,n={}){if(!EM(e))throw new Error("displayName must be 1\u201364 chars (letters, digits, space . _ -)");let r=e.trim(),o=Ml(r);if(!je(o))throw new Error("resulting tmux session name is invalid");if(!await si())throw new Error(`host tmux server not running on ${Rt} and auto-start failed \u2014 start one: ${X} -S ${Rt} new-session -d -s keeper "sleep 2147483647"`);if(await uk(o))throw new Error(`tmux session "${o}" already exists`);let s=n.agentCmd||ef,a=n.agent||Ar(s),i=!!n.resumeSessionId,c=n.resumeSessionId||ak(),l=i?s:oi(s,c,o),u=i?n.pinned===!0:/(^|\s)--session-id(\s|=)/.test(l),d=a==="claude"&&yo(s),p=n.firstRun===!0;p||(d&&await yr(t),a==="codex"&&await ps(t),a==="cursor"&&await fs(t),await Cb(t),n.freshWorkspace!==!0&&await Al(t));let f=d&&!p?al():null,w=Zy(),m=["-e",`${Un}=${w}`];m.push(...nk({nodeUrl:rk()})),f&&m.push("-e",`ANTHROPIC_API_KEY=${f}`),d&&m.push(...ri());try{await Re(X,Z("new-session","-d","-s",o,"-c",t,...m))}catch(g){throw $l(f?$l(g,f):g,w)}return await bo(o),await Re(X,Z("set-option","-t",o,"@bostrat-session","1")),await Re(X,Z("set-option","-t",o,"@bostrat-title",r)),await Re(X,Z("set-option","-t",o,"@bostrat-sid",c)),await Re(X,Z("set-option","-t",o,"@bostrat-agent",a)),await Re(X,Z("send-keys","-t",o,l,"Enter")),kM(l)&&RM(o,l).catch(()=>{}),{name:o,title:r,cwd:t,sessionId:c,agent:a,pinned:u,hookToken:w}}async function en(e){if(!je(e))throw new Error("invalid session name");await Re(X,Z("kill-session","-t",e))}async function dk(e,t){if(je(e))try{let n=t?Z("set-option","-t",e,"@bostrat-sid",t):Z("set-option","-u","-t",e,"@bostrat-sid");await Re(X,n)}catch{}}async function Be(e,{lines:t=40}={}){if(!je(e))return"";try{let n=Z("capture-pane","-t",e,"-p");Number.isFinite(t)&&t>0&&n.push("-S",`-${Math.floor(t)}`);let{stdout:r}=await Re(X,n);return String(r||"")}catch{return""}}async function pk(e){if(!je(e))return[];try{let{stdout:t}=await Re(X,Z("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 fk(e){if(!je(e))return 0;try{let{stdout:t}=await Re(X,Z("list-clients","-t",e,"-F","1"));return String(t||"").trim().split(`
89
+ `).filter(Boolean).length}catch{return 0}}async function bo(e,{cols:t=MM,rows:n=NM}={}){if(!je(e))return!0;if(await fk(e))return!1;try{let r=await mk(e);if(r.cols===t&&r.rows===n)return!0;await Re(X,Z("resize-window","-t",e,"-x",String(t),"-y",String(n))),await Re(X,Z("set-window-option","-t",e,"window-size","latest")),await Ts(80)}catch{}return!0}async function PM(e){if(!je(e))return 0;try{let{stdout:t}=await Re(X,Z("display-message","-t",e,"-p","#{pane_pid}"));return Number(String(t||"").trim())||0}catch{return 0}}async function Kn(e){let t=await PM(e);if(!t)return!1;try{return await Re("pgrep",["-P",String(t)]),!1}catch(n){return n?.code===1}}async function mk(e){if(!je(e))return{cols:0,rows:0};try{let{stdout:t}=await Re(X,Z("display-message","-t",e,"-p","#{window_width} #{window_height}")),[n,r]=String(t||"").trim().split(/\s+/).map(o=>Number(o)||0);return{cols:n,rows:r}}catch{return{cols:0,rows:0}}}async function Nl(e,{cols:t=OM,rows:n=CM}={}){if(je(e)&&!await fk(e))try{let r=await mk(e),o=Math.max(r.cols,t),s=Math.max(r.rows,n);(o>r.cols||s>r.rows)&&(await Re(X,Z("resize-window","-t",e,"-x",String(o),"-y",String(s))),await Re(X,Z("set-window-option","-t",e,"window-size","latest")),await Ts(80))}catch{}}async function Gn(e){return await Nl(e),Be(e,{lines:tt})}async function Ke(e,t,{settleMs:n=40,kind:r}={}){if(!je(e))throw new Error("invalid session name");let o=(Array.isArray(t)?t:[t]).filter(s=>DM.has(s));for(let s=0;s<o.length;s++)await Re(X,Z("send-keys","-t",e,o[s])),n>0&&s<o.length-1&&await Ts(n);return le({flow:"tmux",phase:"send-keys",sessionName:e,kind:r||"keys",keys:o.join(" ")}).catch(()=>{}),o.length}async function As(e,t,{kind:n}={}){if(!je(e))throw new Error("invalid session name");let r=Math.max(0,Math.floor(Number(t)||0));return r>0&&await Re(X,Z("send-keys","-t",e,"-N",String(r),"BSpace")),le({flow:"tmux",phase:"send-keys",sessionName:e,kind:n||"wipe",keys:`BSpace x${r}`}).catch(()=>{}),r}async function Dl(e,t,{perCharDelayMs:n=120,kind:r}={}){if(!je(e))throw new Error("invalid session name");let o=[...String(t)];for(let s of o)await Re(X,Z("send-keys","-t",e,"-l",s)),n>0&&await Ts(n);le({flow:"tmux",phase:"type",sessionName:e,kind:r||"type",textLen:o.length,textHead:String(t).slice(0,120)}).catch(()=>{})}function BM(e,t){return new Promise((n,r)=>{let o=sk(X,Z(...e),(s,a,i)=>{s?r(s):n({stdout:a,stderr:i})});o.stdin.on("error",()=>{}),o.stdin.end(t)})}async function jM(e,t){let n=`bostrat-${ak().slice(0,8)}`;await BM(["load-buffer","-b",n,"-"],t),await Re(X,Z("paste-buffer","-p","-d","-b",n,"-t",e))}async function nt(e,t,{enter:n=!0,submitDelayMs:r=0,kind:o,paste:s=!1}={}){if(!je(e))throw new Error("invalid session name");if(typeof t=="string"&&t.length>0&&(s?await jM(e,t):await Re(X,Z("send-keys","-t",e,"-l",t))),n){let a=Number(r);Number.isFinite(a)&&a>0&&await Ts(a),await Re(X,Z("send-keys","-t",e,"Enter"))}le({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 Re,X,ok,Rt,yM,ef,ni,tf,bM,Ol,vs,Ss,Qp,xM,vM,nf,SM,TM,AM,ai,_M,IM,OM,CM,tt,MM,NM,DM,Pl,ct=q(()=>{Ua();cl();ll();Va();El();kn();ds();Zp();Re=wM(sk);X=process.env.BOSTRAT_TMUX_BIN||"/usr/bin/tmux";ok=typeof process.getuid=="function"?process.getuid():0,Rt=gM({explicit:process.env.BOSTRAT_TMUX_SOCKET,legacyExists:(()=>{try{return Rl.existsSync(ik(ok))}catch{return!1}})(),runtimeDir:process.env.XDG_RUNTIME_DIR,uid:ok}),yM=process.env.BOSTRAT_DEFAULT_CWD||process.env.HOME||"/",ef=process.env.BOSTRAT_AGENT_CMD||"claude --dangerously-skip-permissions",ni="CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN";tf="bostrat-usage-probe",bM=new Set([tf]);Ol="present",vs="absent",Ss="unknown",Qp=5e3,xM=[250,1e3,3e3],vM=e=>new Promise(t=>setTimeout(t,e));nf={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"};SM=/^[A-Za-z0-9_.-]{1,64}$/;TM=/^[A-Za-z0-9 ._↻-]+$/,AM=64;ai=()=>Number(process.env.BOSTRAT_LAUNCH_VERIFY_MS)||12e3,_M=1e3,IM=/not found|Unknown command/i;OM=Number(process.env.BOSTRAT_PROMPT_CAPTURE_COLS)||100,CM=Number(process.env.BOSTRAT_PROMPT_CAPTURE_ROWS)||40,tt=Number(process.env.BOSTRAT_PROMPT_CAPTURE_LINES)||80,MM=Number(process.env.BOSTRAT_BOX_COLS)||120,NM=Number(process.env.BOSTRAT_BOX_ROWS)||40;DM=new Set(["Up","Down","Left","Right","Space","Enter","Tab","BTab","Escape","BSpace"]);Pl=1600});import ii from"node:fs";import qM from"node:fs/promises";import Es from"node:path";import KM from"node:os";function sf(e){return e.replace(/[^A-Za-z0-9]/g,"-")}function af(e){let t=Es.join(of,sf(e)),n;try{n=ii.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return null}let r=null;for(let o of n){let s=Es.join(t,o);try{let{mtimeMs:a}=ii.statSync(s);(!r||a>r.mtimeMs)&&(r={full:s,mtimeMs:a})}catch{}}return r?r.full:null}function tn(e,t){if(!t)return null;let n=Es.join(of,sf(e),`${t}.jsonl`);return ii.existsSync(n)?n:null}function xk(e){if(!e)return[];let t=Es.join(of,sf(e)),n;try{n=ii.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return[]}let r=[];for(let o of n)try{let s=ii.statSync(Es.join(t,o));r.push({id:o.slice(0,-6),birthMs:s.birthtimeMs||s.ctimeMs||s.mtimeMs})}catch{}return r}async function _t(e,t=131072){let n=await qM.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 zM(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 ci(e,t=null,{fallbackNewest:n=!0}={}){if(!e)return null;let r,o;if(t){if(r=tn(e,t),o=!0,!r)return null}else if(n){if(r=af(e),o=!1,!r)return null}else return null;let s;try{s=zM(await _t(r))}catch{return null}if(!s)return null;let a=Object.prototype.hasOwnProperty.call(kk,s.model),i=kk[s.model]||GM;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 kk,GM,of,nn=q(()=>{kk={"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},GM=2e5,of=process.env.BOSTRAT_CLAUDE_PROJECTS||Es.join(KM.homedir(),".claude","projects")});function VM(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 li(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 ui(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 Ne(e,t=new Set){let n=[];for(let r=1;r<e.length;r++){let o=e[r];if(o==="<<")break;if(Tk(o)){t.has(o)&&r++;continue}n.push(o)}return n}function Ak(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 XM(e){let t=Ak(e),n=ft(Ne(e).find(r=>!/^\d+(,\d+)?p$/.test(r)));return t&&n?t.from===t.to?`Read line ${t.from} of ${Ge(n)}`:`Read lines ${t.from}\u2013${t.to} of ${Ge(n)}`:e.includes("-i")&&n?`Edit ${Ge(n)}`:null}function cf(e){if(e.includes("--files")){let s=ft(Ne(e,vk)[0]);return s&&s!=="."?`List files in ${_s(s)}`:"List files"}let t=Ne(e,vk),n=t[0];if(!n)return null;let r=ft(t.slice(1).find(s=>s!==".")),o=Is(n,40);return r?`Search for \u201C${o}\u201D in ${_s(r)}`:`Search for \u201C${o}\u201D`}function lf(e){let t=Ne(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 uf(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=Ne(e)[0];return n?`Run ${Ge(n)}`:null}function ZM(e){let t=Ne(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 Sk(e){return e.find(t=>/^https?:\/\//.test(t))||null}function tN(e){let t=ui(li(e));if(!t.length)return null;if(/^(ba|z)?sh$/.test(Ge(t[0]))&&(t[1]==="-lc"||t[1]==="-c")&&t[2])return df(t[2]);let n=Ge(t[0]);if(eN.has(n))return null;if(t.includes("--version"))return`Check ${n} version`;if(n.endsWith(".sh"))return`Run ${n}`;let r=QM[n];return r?r(t.map((o,s)=>s===0?n:o)):null}function df(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=VM(t);for(let i=0;i<r.length-1;i++){let c=ui(li(r[i])),l=ui(li(r[i+1]));if(!(!c.length||!l.length)&&["nl","cat"].includes(Ge(c[0]))&&Ge(l[0])==="sed"){let u=Ak(l),d=Ne(c)[0];if(u&&d)return Is(u.from===u.to?`Read line ${u.from} of ${Ge(d)}`:`Read lines ${u.from}\u2013${u.to} of ${Ge(d)}`,88)}}let o=[];for(let i of r){let c=tN(i);c&&o.push({d:c,head:Ge(ui(li(i))[0]||""),sub:Ne(ui(li(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":Is(s?s.d:o[0].d,88)}var Is,ft,Ge,_s,Tk,vk,JM,YM,QM,eN,Ek=q(()=>{Is=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,ft=e=>e&&!/[$`]/.test(e)?e:null,Ge=e=>e.replace(/\/+$/,"").split("/").pop()||e,_s=e=>{let t=e.replace(/\/+$/,"").split("/").filter(Boolean);return t.length>3?t.slice(-2).join("/"):e},Tk=e=>e.startsWith("-"),vk=new Set(["-g","--glob","-t","--type","-A","-B","-C","-m","--max-count","-e","--regexp","-f","--file"]);JM={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 ${Ge(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"},YM={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"};QM={git:e=>{let t=Ne(e,new Set(["-C","-c"])),n=JM[t[0]];return n?n(t,e):null},gh:e=>{let t=Ne(e),n=YM[t[0]];return n?n(t):null},sed:XM,rg:cf,grep:cf,egrep:cf,nl:e=>{let t=ft(Ne(e)[0]);return t?`Read ${Ge(t)}`:null},cat:e=>{let t=ft(Ne(e)[0]);return t?`Read ${Ge(t)}`:null},head:e=>{let t=ft(Ne(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the start of ${Ge(t)}`:null},tail:e=>{let t=ft(Ne(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the end of ${Ge(t)}`:null},wc:e=>{let t=ft(Ne(e)[0]);return t?`Count lines in ${Ge(t)}`:"Count input lines"},ls:e=>{let t=ft(Ne(e)[0]);return t&&t!=="."?`List files in ${_s(t)}`:"List files"},find:e=>ft(e[1])&&!Tk(e[1])&&e[1]!=="."?`Find files in ${_s(e[1])}`:"Find files",tree:()=>"List the directory tree",mkdir:e=>{let t=ft(Ne(e)[0]);return t?`Create directory ${_s(t)}`:null},touch:e=>{let t=ft(Ne(e)[0]);return t?`Create ${Ge(t)}`:null},rm:e=>{let t=ft(Ne(e)[0]);return t?`Delete ${_s(t)}`:null},mv:e=>{let t=ft(Ne(e)[0]);return t?`Move ${Ge(t)}`:null},cp:e=>{let t=ft(Ne(e)[0]);return t?`Copy ${Ge(t)}`:null},chmod:e=>{let t=ft(Ne(e)[1]);return t?`Change permissions on ${Ge(t)}`:null},diff:e=>{let t=Ne(e);return t.length>=2?`Compare ${Ge(t[0])} and ${Ge(t[1])}`:null},curl:e=>{let t=Sk(e);return t?`Fetch ${Is(t,56)}`:"Fetch a URL"},wget:e=>{let t=Sk(e);return t?`Fetch ${Is(t,56)}`:"Fetch a URL"},npm:lf,pnpm:lf,yarn:lf,npx:e=>{let t=Ne(e)[0];return t?`Run ${t}`:null},node:e=>uf(e,"Node"),python:e=>uf(e,"Python"),python3:e=>uf(e,"Python"),make:e=>{let t=Ne(e)[0];return t?`Run make ${t}`:"Run make"},systemctl:ZM,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=Ne(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=Ne(e)[0];return t?`Locate ${t}`:null},command:e=>e[1]==="-v"&&e[2]?`Locate ${e[2]}`:null,fly:e=>{let t=Ne(e)[0];return t==="deploy"?"Deploy to Fly":t?`Run fly ${t}`:null}},eN=new Set(["pwd","echo","cd","sleep","true","false","test","[","set","export","exit","read"])});function $s(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 Ir(e,t=""){let n=t.trim();return n||df(e)||$s(e)}function pf(e,t){if(e){if(Array.isArray(e)){for(let n of e)pf(n,t);return}if(typeof e=="object"){if(e.type==="tool_use"&&ff.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))pf(n,t)}}}async function _k(e,{maxBytes:t=1048576,limit:n=400}={}){let r;try{r=await _t(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(pf(c.content,l),!l.length)continue;let u=i.timestamp?Date.parse(i.timestamp):null;for(let d of l)o.push({...d,summary:Ir(d.command,d.description),ts:u})}return o.slice(-n)}function Ik(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(...nN(i,r.get(a)||[]));return s.sort((a,i)=>(a.ts||0)-(i.ts||0))}function nN(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 ff,Rs=q(()=>{nn();Ek();ff=new Set(["Bash"])});import $k from"node:fs";import hf from"node:fs/promises";import mf from"node:path";import rN from"node:os";async function Rk(e){try{return await hf.realpath(e)}catch{return e}}function sN(e=oN){let t=[],n=r=>{let o;try{o=$k.readdirSync(r,{withFileTypes:!0})}catch{return}for(let s of o){let a=mf.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:$k.statSync(a).mtimeMs})}catch{}}}};return n(e),t.sort((r,o)=>o.mtimeMs-r.mtimeMs)}async function aN(e,t=1048576){let n;try{n=await hf.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 iN(e){let t=await aN(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 ko(e,t){if(!e&&!t)return null;let n=sN();if(t){let o=n.find(s=>s.id===t);return o||null}let r=await Rk(e);for(let o of n){let s=await iN(o.file);if(s&&(s===e||await Rk(s)===r))return o}return null}async function Ok(e,t,{limit:n=80,maxBytes:r=524288}={}){let o=await ko(e,t);if(!o)return[];let s;try{s=await _t(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:xo,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,wf.has(m.name)||c.push(m.name);continue}if(m.type!=="message"||m.role!=="assistant")continue;u=!0;let g=lN(m.content),b=c.length?c.slice():null;c=[],!(!g&&!b)&&a.push({role:"assistant",text:g,tools:b||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 uN(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 dN(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 pN(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=dN(i.slice(c.index+c[0].length).trimStart());l&&l.trim()&&o.push(l.trim())}),o}async function Ck(e,t,{limit:n=400,maxBytes:r=524288}={}){let o=await ko(e,t);if(!o)return[];let s;try{s=await _t(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"&&di.has(u.name)){let f;try{f=JSON.parse(u.arguments||"{}")}catch{continue}let w=uN(f);w&&(d=[w])}else u.type==="custom_tool_call"&&u.name==="exec"&&(d=pN(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:Ir(f),ts:l.timestamp?Date.parse(l.timestamp):null})})}return a.slice(-n)}async function Mk(e,t){let n=await ko(e,t);if(!n)return null;try{return Math.round((await hf.stat(n.file)).mtimeMs)}catch{return n.mtimeMs||null}}var oN,cN,lN,di,wf,xo,vo=q(()=>{nn();Rs();oN=process.env.BOSTRAT_CODEX_SESSIONS||mf.join(process.env.CODEX_HOME||mf.join(rN.homedir(),".codex"),"sessions");cN=new Set(["output_text","text"]),lN=e=>typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&typeof t.text=="string"&&cN.has(t.type)).map(t=>t.text).join(`
99
+ `).trim():"";di=new Set(["exec_command","shell","exec"]),wf=new Set(["wait","write_stdin"]),xo="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 pi({error:e=null,status:t=null,text:n=""}={}){let r=String(e||"").trim().toLowerCase();if(r&&Nk.has(r))return Nk.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 Pk(e){if(!e||e.role!=="assistant")return null;if(e.apiError){let t=e.apiError;return{cls:t.cls||pi({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===xo?"other":pi({text:t}),code:null,status:null,requestId:null}}return null}function Dk(e,{codexFailedText:t=null}={}){let n=String(e?.text||"").trim();return n?e?.model==="<synthetic>"?/^No response requested\.$/.test(n)?null:{cls:pi({text:n}),code:null,status:fN(n),requestId:null,text:n}:t&&n===t?{cls:"other",code:null,status:null,requestId:null,text:n}:null:null}function fN(e){let t=/^API Error:\s*(\d{3})\b/.exec(e);return t?Number(t[1]):null}var XG,Nk,jl=q(()=>{vo();XG=Object.freeze(["entitlement","auth","rate_limit","overloaded","server","other"]),Nk=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 mN(e,t){return!e||!t?null:tn(e,t)}function hN(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 wN(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 gN(e){return Array.isArray(e)&&e.length>0&&e.every(t=>t&&t.type==="tool_result")}function gf(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 Bk(e,t){if(!e.uuid)return null;let n=gf(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 yf(e,{maxBytes:t=524288,limit:n=80}={}){let r;try{r=await _t(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 b=l.attachment;b?.type==="queued_command"&&b.commandMode==="task-notification"&&typeof b.prompt=="string"&&b.prompt.trim()&&o.push({role:"user",text:b.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 b of u.content){let x=b?.type==="tool_use"?b.input?.file_path||b.input?.path:null;typeof x=="string"&&yN.test(x)&&s.set(b.id,x.split("/").pop()),b?.type==="tool_use"&&b.name==="Skill"&&b.id&&a.set(b.id,String(b.input?.skill||"").trim().replace(/^\//,"")||null)}if(gN(u.content)){let b=Bk(l,s);b&&o.push({role:"assistant",text:"",images:b,ts:l.timestamp?Date.parse(l.timestamp):null,model:null});continue}let p=hN(u.content),f=d==="assistant"?wN(u.content):null,w=d==="user"?Bk(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:pi({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 jk(e,t,{turns:n=16}={}){let r=mN(e,t);if(!r)return"";let o=await yf(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}:** ${bN(s.text||c,700)} ${i}`.trim()}).join(`
102
+
103
+ `):""}var yN,bN,Ll=q(()=>{jl();nn();yN=/\.(png|jpe?g|gif|webp|bmp|svg|tiff?|avif|heic|heif|ico)$/i;bN=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e});import kN from"node:fs/promises";import{execFile as xN}from"node:child_process";import{promisify as vN}from"node:util";function Hk(e){kf=typeof e=="function"?e:null}function xf(e){let t=String(e||""),n=t.indexOf("/lib/node_modules/");return n>0?t.slice(0,n):null}function Wk({sessionName:e,from:t,to:n}={}){let r=String(n||"").trim();!r||Lk.has(r)||(Lk.add(r),Fk=Fk.then(()=>TN({sessionName:e,from:t,to:r})).catch(()=>{}))}async function TN({sessionName:e,from:t,to:n}){await le({flow:"codex-update",phase:"start",sessionName:e,from:t,to:n}).catch(()=>{});try{let r=(await bf("/bin/sh",["-c","command -v codex"])).stdout.trim();if(!r)throw new Error("codex not on PATH");let o=await kN.realpath(r),s=xf(o),a=s?{...process.env,PATH:`${s}/bin:${process.env.PATH||""}`}:process.env;await bf("npm",["install","-g","@openai/codex"],{env:a,timeout:SN});let i=(await bf(r,["--version"])).stdout.trim().replace(/^codex-cli\s*/,"")||n;await le({flow:"codex-update",phase:"done",sessionName:e,from:t,to:n,version:i}).catch(()=>{}),await Uk({sessionName:e,from:t,to:n,version:i,status:"updated"})}catch(r){let o=String(r?.message||r).slice(0,300);await le({flow:"codex-update",phase:"failed",sessionName:e,from:t,to:n,error:o}).catch(()=>{}),await Uk({sessionName:e,from:t,to:n,status:"failed",error:o})}}async function Uk(e){if(kf)try{await kf(e)}catch{}}var bf,SN,Lk,Fk,kf,Fl=q(()=>{kn();bf=vN(xN),SN=Number(process.env.BOSTRAT_CODEX_UPDATE_TIMEOUT_MS)||5*6e4,Lk=new Set,Fk=Promise.resolve(),kf=null});function EN(e,{provider:t,box:n}){let r=String(e).replace(/\r/g,"").split(`
104
+ `);if(!qk.test(e))return null;let o=[],s=!1;for(let l=r.length-1;l>=0;l--){let u=r[l].match(AN);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"&&qk.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 So(e){let t=String(e??"").replace(/\r/g,""),n=t.split(`
105
105
  `);for(let r=n.length-1;r>=0;r--)if(zk.test(n[r]))return n.slice(r).join(`
106
- `);return t}function EN(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 _N(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 IN(e,t=""){let n=So(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(Kk);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(Kk.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&&!zk.test(r[l])&&EN(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=_N(l.label);return{label:l.label,description:[l.desc,u].filter(Boolean).join(" \xB7 ")}})}]}}function ON(e,t=""){let n=So(e);if(fi.test(n)||!$N.test(n))return null;let r=n.trimEnd().split(`
108
- `).pop()||"";return RN.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 MN(e,t=""){let n=So(e);if(fi.test(n)||!Gk.test(n))return null;let r=n.split(`
109
- `),o=r.findIndex(i=>Gk.test(i)),s="";for(let i=o+1;i<r.length;i++){let c=r[i].match(CN);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 NN(e,t=""){let n=So(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 PN(e,t=""){let n=So(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 DN(e,t=""){let n=String(e);if(!/Press any key to log in/.test(n)||xf.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 BN(e,t=""){let n=String(e);if(!jN.test(n)||xf.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 LN(e,t=""){let n=String(e);return!/Scan this QR code to log in/.test(n)||xf.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 Vk(e,t,n=""){if(e!=="cursor"&&e!=="codex")return null;if(e==="codex"){let r=ON(t,n)||MN(t,n)||NN(t,n)||PN(t,n)||IN(t,n);if(r)return r}if(e==="cursor"){let r=BN(t,n)||LN(t,n)||DN(t,n);if(r)return r}return AN(t,{provider:e,box:n})}function Jk(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 TN,qk,fi,zk,Kk,$N,RN,Gk,CN,xf,jN,Ul=q(()=>{TN=/^\s*[›>*\-❯]?\s*(\d+)[.)]\s+(.+?)\s*$/,qk=/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i;fi=/(^|\n)\s*›/,zk=/^\s*Welcome to Codex\b/;Kk=/^\s*(>)?\s*(\d+)\.\s+(.+?)\s*$/;$N=/Successfully logged in\./,RN=/^\s*Press Enter to continue\.\s*$/;Gk=/Enter this one-time code/,CN=/^\s*([A-Z0-9]{2,10}-[A-Z0-9]{2,10})\s*$/;xf=/Run Everything|Add a follow-up|Plan, search, build anything/;jN=/click this link to log in|Signing in with the browser/});function WN(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(UN.test(r)||HN.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 VN(e){let t=String(e||"");if(!Je.codex.block.test(t))return null;let n=So(t);if(!Je.codex.block.test(n))return null;let r=n.match(zN);return{from:r?.[1]||null,to:r?.[2]||null}}function xn(e){return new Promise(t=>setTimeout(t,e))}function vf(e,t){let n=Date.now(),r=JN();for(let[s,a]of Wl)n-a>=r&&Wl.delete(s);let o=`${e}::${t}`;return Wl.has(o)?!1:(Wl.set(o,n),!0)}function Qk(e,t){if(e?.busyScope!=="footer")return t;let n=String(t||"").split(`
106
+ `);return t}function _N(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 IN(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 $N(e,t=""){let n=So(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(Kk);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(Kk.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&&!zk.test(r[l])&&_N(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=IN(l.label);return{label:l.label,description:[l.desc,u].filter(Boolean).join(" \xB7 ")}})}]}}function CN(e,t=""){let n=So(e);if(fi.test(n)||!RN.test(n))return null;let r=n.trimEnd().split(`
108
+ `).pop()||"";return ON.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 NN(e,t=""){let n=So(e);if(fi.test(n)||!Gk.test(n))return null;let r=n.split(`
109
+ `),o=r.findIndex(i=>Gk.test(i)),s="";for(let i=o+1;i<r.length;i++){let c=r[i].match(MN);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 PN(e,t=""){let n=So(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 DN(e,t=""){let n=So(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 BN(e,t=""){let n=String(e);if(!/Press any key to log in/.test(n)||vf.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 LN(e,t=""){let n=String(e);if(!jN.test(n)||vf.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 FN(e,t=""){let n=String(e);return!/Scan this QR code to log in/.test(n)||vf.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 Vk(e,t,n=""){if(e!=="cursor"&&e!=="codex")return null;if(e==="codex"){let r=CN(t,n)||NN(t,n)||PN(t,n)||DN(t,n)||$N(t,n);if(r)return r}if(e==="cursor"){let r=LN(t,n)||FN(t,n)||BN(t,n);if(r)return r}return EN(t,{provider:e,box:n})}function Jk(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 AN,qk,fi,zk,Kk,RN,ON,Gk,MN,vf,jN,Ul=q(()=>{AN=/^\s*[›>*\-❯]?\s*(\d+)[.)]\s+(.+?)\s*$/,qk=/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i;fi=/(^|\n)\s*›/,zk=/^\s*Welcome to Codex\b/;Kk=/^\s*(>)?\s*(\d+)\.\s+(.+?)\s*$/;RN=/Successfully logged in\./,ON=/^\s*Press Enter to continue\.\s*$/;Gk=/Enter this one-time code/,MN=/^\s*([A-Z0-9]{2,10}-[A-Z0-9]{2,10})\s*$/;vf=/Run Everything|Add a follow-up|Plan, search, build anything/;jN=/click this link to log in|Signing in with the browser/});function qN(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(HN.test(r)||WN.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 JN(e){let t=String(e||"");if(!Je.codex.block.test(t))return null;let n=So(t);if(!Je.codex.block.test(n))return null;let r=n.match(VN);return{from:r?.[1]||null,to:r?.[2]||null}}function xn(e){return new Promise(t=>setTimeout(t,e))}function Sf(e,t){let n=Date.now(),r=YN();for(let[s,a]of Wl)n-a>=r&&Wl.delete(s);let o=`${e}::${t}`;return Wl.has(o)?!1:(Wl.set(o,n),!0)}function Qk(e,t){if(e?.busyScope!=="footer")return t;let n=String(t||"").split(`
114
114
  `),r=-1;for(let o=n.length-1;o>=0;o--)if(Zk.test(n[o])){r=o;break}return r<0?t:n.slice(r+1).join(`
115
- `)}function XN(e){let t=0;for(let n of String(e).split(`
116
- `))Zk.test(n)&&(t=Math.max(t,n.trimEnd().length));return t}function Sf(e,t){let n=Je[e];if(!n?.busy)return{state:"idle",reason:null};if(Af(e,t))return{state:"unknown",reason:"blocked"};if(n.up&&!n.up.test(t))return{state:"idle",reason:null};if(n.busy.test(Qk(n,t)))return{state:"busy",reason:null};if(n.busyAlt&&n.busyAlt.test(t))return{state:"busy",reason:null};let r=XN(t);return e==="claude"&&r>0&&r<YN?{state:"unknown",reason:"narrow"}:{state:"idle",reason:null}}function Tf(e,t){return Sf(e,t).state}function e0(e,t){if(e!=="claude")return!1;let n=String(t||"").split(`
117
- `).slice(-QN).join(`
118
- `);return ZN.test(n)}function Cs(e,t){return Tf(e,t)==="busy"}function ql(e,t){return Tf(e,t)!=="idle"}function Ms(e,t){let n=Je[e];return n?.up?n.up.test(t):!0}function eP(e,t){let n=Je[e];return n?Af(e,t)?!1:n.up.test(t)&&Tf(e,t)==="idle":!0}function Af(e,t){let n=Je[e];return n?n.auth?.test(t)&&!n.up.test(t)?!0:n.block?.test(t)?e==="codex"?!0:!n.up.test(t):!1:!1}function Ef(e,t){let n=String(t||"").trim();if(!n)return e;let r=String(e||"").split(`
115
+ `)}function ZN(e){let t=0;for(let n of String(e).split(`
116
+ `))Zk.test(n)&&(t=Math.max(t,n.trimEnd().length));return t}function Tf(e,t){let n=Je[e];if(!n?.busy)return{state:"idle",reason:null};if(Ef(e,t))return{state:"unknown",reason:"blocked"};if(n.up&&!n.up.test(t))return{state:"idle",reason:null};if(n.busy.test(Qk(n,t)))return{state:"busy",reason:null};if(n.busyAlt&&n.busyAlt.test(t))return{state:"busy",reason:null};let r=ZN(t);return e==="claude"&&r>0&&r<XN?{state:"unknown",reason:"narrow"}:{state:"idle",reason:null}}function Af(e,t){return Tf(e,t).state}function e0(e,t){if(e!=="claude")return!1;let n=String(t||"").split(`
117
+ `).slice(-eP).join(`
118
+ `);return QN.test(n)}function Cs(e,t){return Af(e,t)==="busy"}function ql(e,t){return Af(e,t)!=="idle"}function Ms(e,t){let n=Je[e];return n?.up?n.up.test(t):!0}function tP(e,t){let n=Je[e];return n?Ef(e,t)?!1:n.up.test(t)&&Af(e,t)==="idle":!0}function Ef(e,t){let n=Je[e];return n?n.auth?.test(t)&&!n.up.test(t)?!0:n.block?.test(t)?e==="codex"?!0:!n.up.test(t):!1:!1}function _f(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 t0(e){let t=String(e||"").trim();return t?t.slice(0,32):null}function Yk(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 Xk(e,t,n,{bailOnDialog:r=!1,launchEcho:o=null,onReady:s}={}){let a=Date.now()+n,i=0,c=null;for(await bo(e).catch(()=>{});;){let l=Ef(await je(e),o);if(eP(t,l))return await s?.(),await xn(Os),"up";if(Je[t]?.up&&!Je[t].up.test(l))if(await Kn(e)){if(c??=Date.now(),Date.now()-c>=ai()){let u=Yk(t);throw le({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"&&GN.test(l)&&!Je.claude.up.test(l))return le({flow:"agent-ready",phase:"dialog",sessionName:e,agent:t,dialog:"resume-confirm"}).catch(()=>{}),"dialog-bail";if(t==="codex"&&KN.test(l)&&!Je.codex.up.test(l)&&i<3){if(!vf(e,"codex-trust")){await xn(Hl);continue}i+=1,await le({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,gate:"codex-trust",attempt:i}).catch(()=>{}),await nt(e,"",{enter:!0,kind:"codex-trust-accept"}),await xn(Os);continue}if(t==="cursor"&&qN.test(l)&&!Je.cursor.up.test(l)&&i<3){if(!vf(e,"cursor-trust")){await xn(Hl);continue}i+=1,await le({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i}).catch(()=>{}),await nt(e,"a",{enter:!1,kind:"cursor-trust-accept"}),await xn(Os);continue}if(t==="codex"&&i<3){let u=VN(l);if(u){if(!vf(e,`codex-update:${u.from}->${u.to}`)){await xn(Hl);continue}i+=1,await le({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i,update:`${u.from} -> ${u.to}`}).catch(()=>{}),await nt(e,"3",{enter:!1,kind:"codex-update-skip"}),Wk({sessionName:e,from:u.from,to:u.to}),await xn(Os);continue}}if(Date.now()>a){if(Af(t,l)){let u=`${t} is blocked on an interactive prompt`;throw t==="codex"?u=Je.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"&&Je.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"&&Je.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"&&Je.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'),le({flow:"agent-ready",phase:"blocked",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:u}).catch(()=>{}),new Error(u)}if(await Kn(e)){let u=Yk(t);throw le({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.`),le({flow:"agent-ready",phase:"timeout",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,paneBlocked:!!Je[t]?.block?.test(l),paneUp:!!Je[t]?.up?.test(l),paneBusy:!!Je[t]?.busy?.test(Qk(Je[t],l))}).catch(()=>{}),await xn(Os),"timeout"}await xn(Hl)}}function _f({agent:e,agentCmd:t}={}){let n=t?Ar(t):Ar(e||"");return{label:n,realClaude:t?yo(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 n0({agent:e,agentCmd:t}={}){let{realClaude:n,realCodex:r,realCursor:o}=_f({agent:e,agentCmd:t});return n||r||o||process.env.BOSTRAT_FAKE_POLL_READY==="1"}function mi({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o}={}){let{realCodex:s,realCursor:a}=_f({agent:n,agentCmd:r});return!t||!s&&!a?null:$r({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o}).then(()=>{},()=>{})}async function $r({cwd:e,sessionId:t,sessionName:n,agent:r,agentCmd:o,timeoutMs:s=FN(),bailOnDialog:a=!1,launchEcho:i=null,onReady:c}={}){let{label:l,realClaude:u,realCodex:d,realCursor:p}=_f({agent:r,agentCmd:o});if(u&&e&&await yr(e),d&&e&&await ps(e),p&&e&&await fs(e),(u||d||p)&&n)return await Xk(n,l,s,{bailOnDialog:a,launchEcho:i,onReady:c});let f=Je[r]?r:Je[l]?l:null;return process.env.BOSTRAT_FAKE_POLL_READY==="1"&&n&&f?await Xk(n,f,s,{launchEcho:i}):(await xn(Os),"settle")}var FN,Hl,Os,UN,HN,Je,qN,KN,GN,zN,JN,Wl,YN,Zk,ZN,QN,hi=q(()=>{ct();Ua();cl();ll();Fl();Ul();kn();FN=()=>Number(process.env.BOSTRAT_AGENT_READY_TIMEOUT_MS)||9e4,Hl=Number(process.env.BOSTRAT_AGENT_READY_POLL_MS)||500,Os=Number(process.env.BOSTRAT_AGENT_READY_SETTLE_MS)||800,UN=/^\s{0,4}[^\s›•■◦╭╰│]\S*(?: \S+){0,3} · \S/,HN=/^\s*tab to queue message\b/;Je={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:WN},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/}},qN=/Trust this workspace|\[a\]\s*Trust/,KN=/Do you trust the contents of this directory\?[\s\S]*›\s*1\. Yes, continue[\s\S]*Press enter to continue/,GN=/Resume from summary/i,zN=/Update available!\s*([\d][\w.-]*)\s*->\s*([\d][\w.-]*)/;JN=()=>Number(process.env.BOSTRAT_GATE_RESEND_MS)||3e3,Wl=new Map;YN=68,Zk=/^\s*[─━]{10,}(?: [^─━\n]+ [─━]+)?\s*$/;ZN=/\bWaiting for \d+\b[^\n]*\bto finish\b|\/workflows to (?:stop|monitor)\b/,QN=15});function oP(e){return typeof e!="string"||!e?!1:e.includes(`
121
- `)?!0:Buffer.byteLength(e,"utf8")>=rP}function vn(e,t){return e==="codex"?{enter:!0,submitDelayMs:tP,...oP(t)?{paste:!0}:{}}:e==="claude"?{enter:!0,submitDelayMs:nP}:{enter:!0}}var tP,nP,rP,wi=q(()=>{tP=(()=>{let e=Number(process.env.BOSTRAT_CODEX_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),nP=(()=>{let e=Number(process.env.BOSTRAT_CLAUDE_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),rP=(()=>{let e=Number(process.env.BOSTRAT_CODEX_PASTE_MIN_BYTES??512);return Number.isFinite(e)&&e>=0?e:512})()});function gi(e,t){if(e==="codex")return lP(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(r0.test(n[c])){r=c;break}if(r<=0)return null;let o=-1;for(let c=r-1;c>=0;c--)if(r0.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(sP);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 lP(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]){(aP.test(t[o])||iP.test(t[o]))&&!If.test(t[o])?n=o:If.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(If);if(a){r.unshift(a[1]);let i=r.map(c=>c.trim()).filter(Boolean);return i.length?i.join(" "):null}if(cP.test(s))return null;r.unshift(s)}return null}function $f(e,t){let n=String(t||"");if(!/\[Pasted Content \d+ chars\]/.test(n))return!1;let r=0,o=He(n.replace(uP,(i,c)=>(r+=Number(c)," "))),s=[...String(e||"")].length;return o&&!He(e).includes(o)?!1:r+o.length<=s+Math.max(4,Math.round(s*.05))}function He(e){return String(e||"").replace(/\s+/g," ").trim()}function o0(e,t,{slackMs:n=2e4}={}){let r=He(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&&He(a.text).includes(r));return s>=0&&s<o.length-1}function s0(e,t,n,{busy:r=!1}={}){let o=gi(e,n);return o&&Kl(t,o)||o&&e==="codex"&&$f(t,o)?"stuck":r&&e!=="codex"||o?"submitted":"unknown"}function Kl(e,t){let n=He(e),r=He(t).replace(/^…\s*/,"").replace(/\s*…$/,"");return!n||!r||r.length<Math.min(n.length,12)?!1:n===r||n.includes(r)}var r0,sP,If,aP,iP,cP,uP,yi=q(()=>{r0=/^\s*─{8,}(?: [^─\n]+ ─+)?\s*$/,sP=/^❯[  ]?(.*)$/,If=/^\s*›[  ]?(.*)$/,aP=/\S+ · \S/,iP=/^\s*(?:\? for shortcuts|tab to queue message)\b/,cP=/^\s*(?:[•■◦✶✻⚠]|╭|╰|│)/;uP=/\[Pasted Content (\d+) chars\](?: #\d+)?/g});async function ki({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=(H,P,E={})=>(a&&typeof a=="object"&&Object.assign(a,{verdict:H,retries:E.retries??0,ms:(i.now||Date.now)()-c,sawUp:!!E.sawUp,reason:E.reason??null}),P);if(!dP.has(t))return l("skipped",!0);let u=i.waitForUp??n0({agent:t,agentCmd:n}),d=i.capture||(H=>je(H,{lines:tt})),p=i.pressEnter||(H=>Ke(H,["Enter"],{kind:"submit-retry"})),f=i.sleep||hP,w=i.now||Date.now,m=i.log||(H=>le(H).catch(()=>{})),g=i.maxMs??mP(),b=w()+g,x={flow:s,trackId:o,sessionName:e,agent:t,textHead:String(r).slice(0,120)},y=0,$=0,O=0,M=!1;for(await f(bi[0]);;){let H=await d(e).catch(()=>""),P=Ms(t,H),E=Cs(t,H),R=s0(t,r,H,{busy:E});if(R==="submitted")return l("submitted",!0,{retries:y,sawUp:!0});if(u&&(!P||R==="stuck"&&E)){if(w()>=b)return R==="stuck"?(m({...x,phase:"submit-failed",reason:"stuck-at-deadline",retries:y}),l("failed",!1,{retries:y,sawUp:M,reason:"stuck-at-deadline"})):(m({...x,phase:"submit-unverified",reason:M?"cli-down":"cli-never-up",retries:y,waitedMs:g}),l("unverified",!0,{retries:y,sawUp:M,reason:M?"cli-down":"cli-never-up"}));await f(pP);continue}if(M=!0,R==="stuck"){if(y>=fP)return m({...x,phase:"submit-failed",retries:y}),l("failed",!1,{retries:y,sawUp:!0,reason:"stuck"});y+=1,$=0,O=0,await p(e),m({...x,phase:"submit-retry",attempt:y}),await f(bi[0]);continue}if($+=1,$>=bi.length||w()>=b)return l("assumed",!0,{retries:y,sawUp:!0});O+=1,await f(bi[Math.min(O,bi.length-1)])}}var dP,bi,pP,fP,mP,hP,Rf=q(()=>{ct();hi();yi();kn();dP=new Set(["claude","codex"]),bi=[250,450,700],pP=500,fP=2,mP=()=>{let e=Number(process.env.BOSTRAT_SUBMIT_VERIFY_MAX_MS);return Number.isFinite(e)&&e>0?e:3e4},hP=e=>new Promise(t=>setTimeout(t,e))});function a0(e){return String(e||"").replace(/[\u2018\u2019\u201A\u02BC\u0060\u00B4]/g,"'").replace(/[\u201C\u201D\u201E]/g,'"')}function zn(e){let t=a0(e).toLowerCase();if(!t.trim())return null;let n=null;for(let r of wP){let o=0;for(let s of gP[r])s.test(t)&&o++;o>0&&(!n||o>n.score)&&(n={category:r,score:o})}return n}function i0(e){let t=0,n=0;for(let[r,o]of Object.entries(e||{}))yP.has(r)&&(t+=o||0),bP.has(r)&&(n+=o||0);return t>=5&&n===0?{category:"research",score:1}:n>=3?{category:"feature-build",score:1}:null}function xi(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 c0(e){let t=a0(e).trim();return t?xP.test(t)?!0:t.split(/\s+/).length<=kP:!1}var wP,gP,yP,bP,kP,xP,Gl=q(()=>{wP=["bug-fix","orchestration","design","ops-infra","docs-writing","research","feature-build"],gP={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/]};yP=new Set(["Read","Grep","Glob","LS","WebSearch","WebFetch","NotebookRead"]),bP=new Set(["Edit","Write","MultiEdit","NotebookEdit"]);kP=12,xP=/^\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 p0(e){let t=xi(String(e||"")).toLowerCase(),n=[];for(let r of t.split(/[^a-z0-9]+/))r.length<2||vP.has(r)||n.push(r);return n}function SP(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(d0(n,"user",o))}else if(n.type==="turn.agent"){if(!o)continue;t.push(d0(n,"assistant",o))}}return t}function d0(e,t,n){let r=zn(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 vi(e){let t=SP(e),n=new Map,r=new Array(t.length).fill(0),o=0;t.forEach((a,i)=>{let c=p0(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 zl(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(p0(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],b=m+l0*(1-u0+u0*(g/(e.avgdl||1))),x=f*(m*(l0+1)/b);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 l0,u0,vP,Of=q(()=>{Gl();l0=1.5,u0=.75,vP=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 Vl from"node:fs/promises";import f0 from"node:path";async function TP(e){let t=f0.join(e,".bostrat","events"),n;try{n=await Vl.readdir(t)}catch{return vi([])}let r=[];for(let o of n)if(o.endsWith(".ndjson"))try{let s=await Vl.readFile(f0.join(t,o),"utf8");for(let a of s.split(`
124
- `))if(a.trim())try{r.push(JSON.parse(a))}catch{}}catch{}return vi(r)}function AP(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 EP(e,t,{k:n=6,maxChars:r=4e3,exclude:o=null}={}){let s=zl(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?["",`## ${m0}, 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 h0(e,t,n={}){let{k:r=6,maxChars:o=4e3,exclude:s=null}=n;try{let a=await Vl.readFile(t,"utf8");if(a.includes(m0))return{appended:!1,reason:"already-enriched"};let i=await TP(e);if(!i.N)return{appended:!1,reason:"empty-index"};let c=EP(i,AP(a),{k:r,maxChars:o,exclude:s});return c?(await Vl.appendFile(t,`
120
+ `);return e}function t0(e){let t=String(e||"").trim();return t?t.slice(0,32):null}function Yk(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 Xk(e,t,n,{bailOnDialog:r=!1,launchEcho:o=null,onReady:s}={}){let a=Date.now()+n,i=0,c=null;for(await bo(e).catch(()=>{});;){let l=_f(await Be(e),o);if(tP(t,l))return await s?.(),await xn(Os),"up";if(Je[t]?.up&&!Je[t].up.test(l))if(await Kn(e)){if(c??=Date.now(),Date.now()-c>=ai()){let u=Yk(t);throw le({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"&&zN.test(l)&&!Je.claude.up.test(l))return le({flow:"agent-ready",phase:"dialog",sessionName:e,agent:t,dialog:"resume-confirm"}).catch(()=>{}),"dialog-bail";if(t==="codex"&&GN.test(l)&&!Je.codex.up.test(l)&&i<3){if(!Sf(e,"codex-trust")){await xn(Hl);continue}i+=1,await le({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,gate:"codex-trust",attempt:i}).catch(()=>{}),await nt(e,"",{enter:!0,kind:"codex-trust-accept"}),await xn(Os);continue}if(t==="cursor"&&KN.test(l)&&!Je.cursor.up.test(l)&&i<3){if(!Sf(e,"cursor-trust")){await xn(Hl);continue}i+=1,await le({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i}).catch(()=>{}),await nt(e,"a",{enter:!1,kind:"cursor-trust-accept"}),await xn(Os);continue}if(t==="codex"&&i<3){let u=JN(l);if(u){if(!Sf(e,`codex-update:${u.from}->${u.to}`)){await xn(Hl);continue}i+=1,await le({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i,update:`${u.from} -> ${u.to}`}).catch(()=>{}),await nt(e,"3",{enter:!1,kind:"codex-update-skip"}),Wk({sessionName:e,from:u.from,to:u.to}),await xn(Os);continue}}if(Date.now()>a){if(Ef(t,l)){let u=`${t} is blocked on an interactive prompt`;throw t==="codex"?u=Je.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"&&Je.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"&&Je.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"&&Je.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'),le({flow:"agent-ready",phase:"blocked",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:u}).catch(()=>{}),new Error(u)}if(await Kn(e)){let u=Yk(t);throw le({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.`),le({flow:"agent-ready",phase:"timeout",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,paneBlocked:!!Je[t]?.block?.test(l),paneUp:!!Je[t]?.up?.test(l),paneBusy:!!Je[t]?.busy?.test(Qk(Je[t],l))}).catch(()=>{}),await xn(Os),"timeout"}await xn(Hl)}}function If({agent:e,agentCmd:t}={}){let n=t?Ar(t):Ar(e||"");return{label:n,realClaude:t?yo(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 n0({agent:e,agentCmd:t}={}){let{realClaude:n,realCodex:r,realCursor:o}=If({agent:e,agentCmd:t});return n||r||o||process.env.BOSTRAT_FAKE_POLL_READY==="1"}function mi({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o}={}){let{realCodex:s,realCursor:a}=If({agent:n,agentCmd:r});return!t||!s&&!a?null:$r({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o}).then(()=>{},()=>{})}async function $r({cwd:e,sessionId:t,sessionName:n,agent:r,agentCmd:o,timeoutMs:s=UN(),bailOnDialog:a=!1,launchEcho:i=null,onReady:c}={}){let{label:l,realClaude:u,realCodex:d,realCursor:p}=If({agent:r,agentCmd:o});if(u&&e&&await yr(e),d&&e&&await ps(e),p&&e&&await fs(e),(u||d||p)&&n)return await Xk(n,l,s,{bailOnDialog:a,launchEcho:i,onReady:c});let f=Je[r]?r:Je[l]?l:null;return process.env.BOSTRAT_FAKE_POLL_READY==="1"&&n&&f?await Xk(n,f,s,{launchEcho:i}):(await xn(Os),"settle")}var UN,Hl,Os,HN,WN,Je,KN,GN,zN,VN,YN,Wl,XN,Zk,QN,eP,hi=q(()=>{ct();Ua();cl();ll();Fl();Ul();kn();UN=()=>Number(process.env.BOSTRAT_AGENT_READY_TIMEOUT_MS)||9e4,Hl=Number(process.env.BOSTRAT_AGENT_READY_POLL_MS)||500,Os=Number(process.env.BOSTRAT_AGENT_READY_SETTLE_MS)||800,HN=/^\s{0,4}[^\s›•■◦╭╰│]\S*(?: \S+){0,3} · \S/,WN=/^\s*tab to queue message\b/;Je={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:qN},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/}},KN=/Trust this workspace|\[a\]\s*Trust/,GN=/Do you trust the contents of this directory\?[\s\S]*›\s*1\. Yes, continue[\s\S]*Press enter to continue/,zN=/Resume from summary/i,VN=/Update available!\s*([\d][\w.-]*)\s*->\s*([\d][\w.-]*)/;YN=()=>Number(process.env.BOSTRAT_GATE_RESEND_MS)||3e3,Wl=new Map;XN=68,Zk=/^\s*[─━]{10,}(?: [^─━\n]+ [─━]+)?\s*$/;QN=/\bWaiting for \d+\b[^\n]*\bto finish\b|\/workflows to (?:stop|monitor)\b/,eP=15});function sP(e){return typeof e!="string"||!e?!1:e.includes(`
121
+ `)?!0:Buffer.byteLength(e,"utf8")>=oP}function vn(e,t){return e==="codex"?{enter:!0,submitDelayMs:nP,...sP(t)?{paste:!0}:{}}:e==="claude"?{enter:!0,submitDelayMs:rP}:{enter:!0}}var nP,rP,oP,wi=q(()=>{nP=(()=>{let e=Number(process.env.BOSTRAT_CODEX_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),rP=(()=>{let e=Number(process.env.BOSTRAT_CLAUDE_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),oP=(()=>{let e=Number(process.env.BOSTRAT_CODEX_PASTE_MIN_BYTES??512);return Number.isFinite(e)&&e>=0?e:512})()});function gi(e,t){if(e==="codex")return uP(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(r0.test(n[c])){r=c;break}if(r<=0)return null;let o=-1;for(let c=r-1;c>=0;c--)if(r0.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(aP);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 uP(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]){(iP.test(t[o])||cP.test(t[o]))&&!$f.test(t[o])?n=o:$f.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($f);if(a){r.unshift(a[1]);let i=r.map(c=>c.trim()).filter(Boolean);return i.length?i.join(" "):null}if(lP.test(s))return null;r.unshift(s)}return null}function Rf(e,t){let n=String(t||"");if(!/\[Pasted Content \d+ chars\]/.test(n))return!1;let r=0,o=He(n.replace(dP,(i,c)=>(r+=Number(c)," "))),s=[...String(e||"")].length;return o&&!He(e).includes(o)?!1:r+o.length<=s+Math.max(4,Math.round(s*.05))}function He(e){return String(e||"").replace(/\s+/g," ").trim()}function o0(e,t,{slackMs:n=2e4}={}){let r=He(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&&He(a.text).includes(r));return s>=0&&s<o.length-1}function s0(e,t,n,{busy:r=!1}={}){let o=gi(e,n);return o&&Kl(t,o)||o&&e==="codex"&&Rf(t,o)?"stuck":r&&e!=="codex"||o?"submitted":"unknown"}function Kl(e,t){let n=He(e),r=He(t).replace(/^…\s*/,"").replace(/\s*…$/,"");return!n||!r||r.length<Math.min(n.length,12)?!1:n===r||n.includes(r)}var r0,aP,$f,iP,cP,lP,dP,yi=q(()=>{r0=/^\s*─{8,}(?: [^─\n]+ ─+)?\s*$/,aP=/^❯[  ]?(.*)$/,$f=/^\s*›[  ]?(.*)$/,iP=/\S+ · \S/,cP=/^\s*(?:\? for shortcuts|tab to queue message)\b/,lP=/^\s*(?:[•■◦✶✻⚠]|╭|╰|│)/;dP=/\[Pasted Content (\d+) chars\](?: #\d+)?/g});async function ki({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=(H,P,E={})=>(a&&typeof a=="object"&&Object.assign(a,{verdict:H,retries:E.retries??0,ms:(i.now||Date.now)()-c,sawUp:!!E.sawUp,reason:E.reason??null}),P);if(!pP.has(t))return l("skipped",!0);let u=i.waitForUp??n0({agent:t,agentCmd:n}),d=i.capture||(H=>Be(H,{lines:tt})),p=i.pressEnter||(H=>Ke(H,["Enter"],{kind:"submit-retry"})),f=i.sleep||wP,w=i.now||Date.now,m=i.log||(H=>le(H).catch(()=>{})),g=i.maxMs??hP(),b=w()+g,x={flow:s,trackId:o,sessionName:e,agent:t,textHead:String(r).slice(0,120)},y=0,$=0,O=0,M=!1;for(await f(bi[0]);;){let H=await d(e).catch(()=>""),P=Ms(t,H),E=Cs(t,H),R=s0(t,r,H,{busy:E});if(R==="submitted")return l("submitted",!0,{retries:y,sawUp:!0});if(u&&(!P||R==="stuck"&&E)){if(w()>=b)return R==="stuck"?(m({...x,phase:"submit-failed",reason:"stuck-at-deadline",retries:y}),l("failed",!1,{retries:y,sawUp:M,reason:"stuck-at-deadline"})):(m({...x,phase:"submit-unverified",reason:M?"cli-down":"cli-never-up",retries:y,waitedMs:g}),l("unverified",!0,{retries:y,sawUp:M,reason:M?"cli-down":"cli-never-up"}));await f(fP);continue}if(M=!0,R==="stuck"){if(y>=mP)return m({...x,phase:"submit-failed",retries:y}),l("failed",!1,{retries:y,sawUp:!0,reason:"stuck"});y+=1,$=0,O=0,await p(e),m({...x,phase:"submit-retry",attempt:y}),await f(bi[0]);continue}if($+=1,$>=bi.length||w()>=b)return l("assumed",!0,{retries:y,sawUp:!0});O+=1,await f(bi[Math.min(O,bi.length-1)])}}var pP,bi,fP,mP,hP,wP,Of=q(()=>{ct();hi();yi();kn();pP=new Set(["claude","codex"]),bi=[250,450,700],fP=500,mP=2,hP=()=>{let e=Number(process.env.BOSTRAT_SUBMIT_VERIFY_MAX_MS);return Number.isFinite(e)&&e>0?e:3e4},wP=e=>new Promise(t=>setTimeout(t,e))});function a0(e){return String(e||"").replace(/[\u2018\u2019\u201A\u02BC\u0060\u00B4]/g,"'").replace(/[\u201C\u201D\u201E]/g,'"')}function zn(e){let t=a0(e).toLowerCase();if(!t.trim())return null;let n=null;for(let r of gP){let o=0;for(let s of yP[r])s.test(t)&&o++;o>0&&(!n||o>n.score)&&(n={category:r,score:o})}return n}function i0(e){let t=0,n=0;for(let[r,o]of Object.entries(e||{}))bP.has(r)&&(t+=o||0),kP.has(r)&&(n+=o||0);return t>=5&&n===0?{category:"research",score:1}:n>=3?{category:"feature-build",score:1}:null}function xi(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 c0(e){let t=a0(e).trim();return t?vP.test(t)?!0:t.split(/\s+/).length<=xP:!1}var gP,yP,bP,kP,xP,vP,Gl=q(()=>{gP=["bug-fix","orchestration","design","ops-infra","docs-writing","research","feature-build"],yP={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/]};bP=new Set(["Read","Grep","Glob","LS","WebSearch","WebFetch","NotebookRead"]),kP=new Set(["Edit","Write","MultiEdit","NotebookEdit"]);xP=12,vP=/^\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 p0(e){let t=xi(String(e||"")).toLowerCase(),n=[];for(let r of t.split(/[^a-z0-9]+/))r.length<2||SP.has(r)||n.push(r);return n}function TP(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(d0(n,"user",o))}else if(n.type==="turn.agent"){if(!o)continue;t.push(d0(n,"assistant",o))}}return t}function d0(e,t,n){let r=zn(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 vi(e){let t=TP(e),n=new Map,r=new Array(t.length).fill(0),o=0;t.forEach((a,i)=>{let c=p0(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 zl(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(p0(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],b=m+l0*(1-u0+u0*(g/(e.avgdl||1))),x=f*(m*(l0+1)/b);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 l0,u0,SP,Cf=q(()=>{Gl();l0=1.5,u0=.75,SP=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 Vl from"node:fs/promises";import f0 from"node:path";async function AP(e){let t=f0.join(e,".bostrat","events"),n;try{n=await Vl.readdir(t)}catch{return vi([])}let r=[];for(let o of n)if(o.endsWith(".ndjson"))try{let s=await Vl.readFile(f0.join(t,o),"utf8");for(let a of s.split(`
124
+ `))if(a.trim())try{r.push(JSON.parse(a))}catch{}}catch{}return vi(r)}function EP(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 _P(e,t,{k:n=6,maxChars:r=4e3,exclude:o=null}={}){let s=zl(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?["",`## ${m0}, 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 h0(e,t,n={}){let{k:r=6,maxChars:o=4e3,exclude:s=null}=n;try{let a=await Vl.readFile(t,"utf8");if(a.includes(m0))return{appended:!1,reason:"already-enriched"};let i=await AP(e);if(!i.N)return{appended:!1,reason:"empty-index"};let c=_P(i,EP(a),{k:r,maxChars:o,exclude:s});return c?(await Vl.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 m0,w0=q(()=>{Of();m0="Relevant prior discussion (verbatim, retrieved"});function CP(e){return _P.test(String(e||"").trimStart())}function b0(e){let t=String(e||"");if(!CP(t.trimStart()))return null;let n=t.replace(IP,"").trim(),r=MP(n),o=[];for(let u of RP){let d=u.from.map(p=>Ns(r.get(p))).find(p=>p&&!g0(p));d&&o.push({h:u.h,text:Si(d,$P)})}let s=Ns(r.get("Current Work"))||Ns(r.get("Primary Request and Intent"))||PP(n),a=Yl(s),i=Si(Jl(Nf(a[0]||"")),OP)||"Context resumed from summary",c=[],l=a.slice(1).join(" ").trim();l&&c.push(Si(Jl(Nf(l)),Mf));for(let u of["Pending Tasks","Optional Next Step"]){let d=Yl(Ns(r.get(u)))[0]||"";if(!(!d||g0(d))){c.push(Si(`Left to do: ${Jl(Nf(d))}`,Mf));break}}if(!c.length){let u=Yl(Ns(r.get("Problem Solving"))||"")[0];u&&c.push(Si(Jl(u),Mf))}return{kind:"resume-summary",title:i,bullets:c.slice(0,2),sections:o,rawChars:t.length}}function MP(e){let t=new Map,n=[];Cf.lastIndex=0;for(let r=Cf.exec(e);r;r=Cf.exec(e))n.push({name:NP(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 NP(e){return y0.find(n=>n.toLowerCase()===e.toLowerCase())||e}function Ns(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 PP(e){let t=e.replace(/^[\s\S]*?\bSummary:\s*/i,"");return Ns(t.split(/\n{2,}/).slice(0,2).join(" "))}function Yl(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 Nf(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 Jl(e){return String(e||"").replace(/(?<![:\w/])(?:\/[\w.@+-]+){4,}/g,t=>`\u2026/${t.split("/").slice(-2).join("/")}`)}function g0(e){return/^(none|nothing|n\/a|no pending|there are no)\b/i.test(String(e||"").trim())}function Si(e,t){let n=String(e||"").trim();if(n.length<=t)return n;let r=Yl(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 _P,y0,Cf,IP,$P,RP,OP,Mf,k0=q(()=>{_P=/^This session is being continued from a previous conversation that ran out of context\./,y0=["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"],Cf=new RegExp(String.raw`^[ \t]*#{0,4}[ \t]*(?:\d+[.)][ \t]*)?\*{0,2}(${y0.join("|")})[:*\t ]*$`,"gim"),IP=/\n+If you need specific details from before compaction[\s\S]*$|\n+Continue the conversation from where it left off[\s\S]*$/,$P=420,RP=[{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"]}],OP=116,Mf=168});function v0(e){return Pf.has(String(e||"").replace(/^\//,"").toLowerCase())}function Ti(e){let t=String(e||"").trim();if(!t)return null;let n=b0(t);if(n)return n;let r=t.match(DP);if(r)return{kind:"skill",name:r[1].split("/").filter(Boolean).pop()||"skill"};let o=t.match(jP);if(o)return{kind:"skill",name:o[1]};let s=t.match(BP);if(s)return{kind:"skill",name:s[1].toLowerCase()};let a=t.match(LP);if(a){let c=a[1].toLowerCase();return Pf.has(c)?{kind:"suppress"}:{kind:"command",command:`/${c}`}}let i=t.match(JP);if(i&&Pf.has(i[1].toLowerCase()))return{kind:"suppress"};if(FP.test(t))return{kind:"suppress"};if(HP.test(t))return{kind:"suppress"};if(UP.test(t))return{kind:"suppress"};if(WP.test(t)){let c=u=>YP(t.match(u)?.[1].trim()||"")||null,l=c(VP);return{kind:"task",summary:c(qP)||"",taskId:c(KP),toolUseId:c(GP),status:c(zP)?.toLowerCase()||null,resultHead:l?l.length>x0?`${l.slice(0,x0).trimEnd()}\u2026`:l:null}}return null}function S0(e){let t=Ti(e?.text);return t||(e?.injected?{kind:"skill",name:e.injected.skill||"skill"}:null)}function YP(e){return e.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&amp;/g,"&")}function T0(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 A0(e){return e?.kind==="skill"?"skill-run":e?.kind==="task"?"task-done":e?.kind==="resume-summary"?"context-resumed":"command-run"}var DP,jP,BP,LP,FP,UP,HP,WP,qP,KP,GP,zP,VP,x0,Pf,JP,Xl=q(()=>{k0();DP=/^Base directory for this skill:\s*(\S+)/,jP=/^Run the "([^"]+)" workflow\./,BP=/^#\s*\/([a-z0-9:_-]+)\s*[—–:-]/i,LP=/<command-name>\s*\/?([a-z0-9:_-]+)\s*<\/command-name>/i,FP=/^<local-command-(?:stdout|caveat)>/i,UP=/^\[Image: original \d+x\d+, displayed at \d+x\d+\.\s*Multiply coordinates by [\d.]+ to map to original image\.\]$/,HP=/^Continue from where you left off\.$/,WP=/^<task-notification>/i,qP=/<summary>([\s\S]*?)<\/summary>/i,KP=/<task-id>([\s\S]*?)<\/task-id>/i,GP=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i,zP=/<status>([\s\S]*?)<\/status>/i,VP=/<result>([\s\S]*?)(?:<\/result>|$)/i,x0=600,Pf=new Set(["model","clear","compact","login","exit","quit"]);JP=/^\/([a-z0-9:_-]+)$/i});import XP from"node:crypto";function tD(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,_0)){let o=Ai(r?.question);if(!o)return null;let s=Array.isArray(r?.options)?r.options:[],a=[];for(let i of s.slice(0,ZP)){let c=Ai(i?.label);if(!c)return null;let l=Ai(i?.description);a.push(l?{label:c,description:l}:{label:c})}if(a.length<QP)return null;n.push({question:o,header:Ai(r?.header).slice(0,eD),multiSelect:r?.multiSelect===!0,options:a})}return n.length?n:null}function Df(e){if(typeof e!="string"||!e.includes("```bostrat-question"))return null;E0.lastIndex=0;let t=null;for(let o;o=E0.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=tD(n);return r?{text:e.slice(0,t.index).trimEnd(),questions:r}:null}function jf(e,t,n){let r=XP.createHash("sha256").update(JSON.stringify(n)).digest("hex").slice(0,8);return`${e}:ask:${t||"turn"}:${r}`}function Bf(e,{leadBoxId:t,provider:n,isAnswered:r,maxQuestions:o=_0}={}){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||Df(s.text)?.questions;if(!a?.length)return null;let i=a.slice(0,Math.max(1,o)),c=jf(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",multiSelect:i[0].multiSelect,questionIndex:0,questionTotal:i.length,questions:i}}function I0(e,t,n){let r=[];(e?.questions||[]).forEach((a,i)=>{let c=(t?.[i]||[]).map(l=>a.options?.[l]?.label).filter(Boolean);c.length&&r.push({name:a.header||a.question,picks:c.join(", ")})});let o=Ai(n),s;return r.length?r.length===1?s=`${r[0].name}: ${r[0].picks}`:s=`Answers:
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 m0,w0=q(()=>{Cf();m0="Relevant prior discussion (verbatim, retrieved"});function MP(e){return IP.test(String(e||"").trimStart())}function b0(e){let t=String(e||"");if(!MP(t.trimStart()))return null;let n=t.replace($P,"").trim(),r=NP(n),o=[];for(let u of OP){let d=u.from.map(p=>Ns(r.get(p))).find(p=>p&&!g0(p));d&&o.push({h:u.h,text:Si(d,RP)})}let s=Ns(r.get("Current Work"))||Ns(r.get("Primary Request and Intent"))||DP(n),a=Yl(s),i=Si(Jl(Pf(a[0]||"")),CP)||"Context resumed from summary",c=[],l=a.slice(1).join(" ").trim();l&&c.push(Si(Jl(Pf(l)),Nf));for(let u of["Pending Tasks","Optional Next Step"]){let d=Yl(Ns(r.get(u)))[0]||"";if(!(!d||g0(d))){c.push(Si(`Left to do: ${Jl(Pf(d))}`,Nf));break}}if(!c.length){let u=Yl(Ns(r.get("Problem Solving"))||"")[0];u&&c.push(Si(Jl(u),Nf))}return{kind:"resume-summary",title:i,bullets:c.slice(0,2),sections:o,rawChars:t.length}}function NP(e){let t=new Map,n=[];Mf.lastIndex=0;for(let r=Mf.exec(e);r;r=Mf.exec(e))n.push({name:PP(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 PP(e){return y0.find(n=>n.toLowerCase()===e.toLowerCase())||e}function Ns(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 DP(e){let t=e.replace(/^[\s\S]*?\bSummary:\s*/i,"");return Ns(t.split(/\n{2,}/).slice(0,2).join(" "))}function Yl(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 Pf(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 Jl(e){return String(e||"").replace(/(?<![:\w/])(?:\/[\w.@+-]+){4,}/g,t=>`\u2026/${t.split("/").slice(-2).join("/")}`)}function g0(e){return/^(none|nothing|n\/a|no pending|there are no)\b/i.test(String(e||"").trim())}function Si(e,t){let n=String(e||"").trim();if(n.length<=t)return n;let r=Yl(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 IP,y0,Mf,$P,RP,OP,CP,Nf,k0=q(()=>{IP=/^This session is being continued from a previous conversation that ran out of context\./,y0=["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"],Mf=new RegExp(String.raw`^[ \t]*#{0,4}[ \t]*(?:\d+[.)][ \t]*)?\*{0,2}(${y0.join("|")})[:*\t ]*$`,"gim"),$P=/\n+If you need specific details from before compaction[\s\S]*$|\n+Continue the conversation from where it left off[\s\S]*$/,RP=420,OP=[{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"]}],CP=116,Nf=168});function v0(e){return Df.has(String(e||"").replace(/^\//,"").toLowerCase())}function Ti(e){let t=String(e||"").trim();if(!t)return null;let n=b0(t);if(n)return n;let r=t.match(BP);if(r)return{kind:"skill",name:r[1].split("/").filter(Boolean).pop()||"skill"};let o=t.match(jP);if(o)return{kind:"skill",name:o[1]};let s=t.match(LP);if(s)return{kind:"skill",name:s[1].toLowerCase()};let a=t.match(FP);if(a){let c=a[1].toLowerCase();return Df.has(c)?{kind:"suppress"}:{kind:"command",command:`/${c}`}}let i=t.match(YP);if(i&&Df.has(i[1].toLowerCase()))return{kind:"suppress"};if(UP.test(t))return{kind:"suppress"};if(WP.test(t))return{kind:"suppress"};if(HP.test(t))return{kind:"suppress"};if(qP.test(t)){let c=u=>XP(t.match(u)?.[1].trim()||"")||null,l=c(JP);return{kind:"task",summary:c(KP)||"",taskId:c(GP),toolUseId:c(zP),status:c(VP)?.toLowerCase()||null,resultHead:l?l.length>x0?`${l.slice(0,x0).trimEnd()}\u2026`:l:null}}return null}function S0(e){let t=Ti(e?.text);return t||(e?.injected?{kind:"skill",name:e.injected.skill||"skill"}:null)}function XP(e){return e.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&amp;/g,"&")}function T0(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 A0(e){return e?.kind==="skill"?"skill-run":e?.kind==="task"?"task-done":e?.kind==="resume-summary"?"context-resumed":"command-run"}var BP,jP,LP,FP,UP,HP,WP,qP,KP,GP,zP,VP,JP,x0,Df,YP,Xl=q(()=>{k0();BP=/^Base directory for this skill:\s*(\S+)/,jP=/^Run the "([^"]+)" workflow\./,LP=/^#\s*\/([a-z0-9:_-]+)\s*[—–:-]/i,FP=/<command-name>\s*\/?([a-z0-9:_-]+)\s*<\/command-name>/i,UP=/^<local-command-(?:stdout|caveat)>/i,HP=/^\[Image: original \d+x\d+, displayed at \d+x\d+\.\s*Multiply coordinates by [\d.]+ to map to original image\.\]$/,WP=/^Continue from where you left off\.$/,qP=/^<task-notification>/i,KP=/<summary>([\s\S]*?)<\/summary>/i,GP=/<task-id>([\s\S]*?)<\/task-id>/i,zP=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i,VP=/<status>([\s\S]*?)<\/status>/i,JP=/<result>([\s\S]*?)(?:<\/result>|$)/i,x0=600,Df=new Set(["model","clear","compact","login","exit","quit"]);YP=/^\/([a-z0-9:_-]+)$/i});import ZP from"node:crypto";function nD(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,_0)){let o=Ai(r?.question);if(!o)return null;let s=Array.isArray(r?.options)?r.options:[],a=[];for(let i of s.slice(0,QP)){let c=Ai(i?.label);if(!c)return null;let l=Ai(i?.description);a.push(l?{label:c,description:l}:{label:c})}if(a.length<eD)return null;n.push({question:o,header:Ai(r?.header).slice(0,tD),multiSelect:r?.multiSelect===!0,options:a})}return n.length?n:null}function Bf(e){if(typeof e!="string"||!e.includes("```bostrat-question"))return null;E0.lastIndex=0;let t=null;for(let o;o=E0.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=nD(n);return r?{text:e.slice(0,t.index).trimEnd(),questions:r}:null}function jf(e,t,n){let r=ZP.createHash("sha256").update(JSON.stringify(n)).digest("hex").slice(0,8);return`${e}:ask:${t||"turn"}:${r}`}function Lf(e,{leadBoxId:t,provider:n,isAnswered:r,maxQuestions:o=_0}={}){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||Bf(s.text)?.questions;if(!a?.length)return null;let i=a.slice(0,Math.max(1,o)),c=jf(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",multiSelect:i[0].multiSelect,questionIndex:0,questionTotal:i.length,questions:i}}function I0(e,t,n){let r=[];(e?.questions||[]).forEach((a,i)=>{let c=(t?.[i]||[]).map(l=>a.options?.[l]?.label).filter(Boolean);c.length&&r.push({name:a.header||a.question,picks:c.join(", ")})});let o=Ai(n),s;return r.length?r.length===1?s=`${r[0].name}: ${r[0].picks}`:s=`Answers:
130
130
  ${r.map(a=>`- ${a.name}: ${a.picks}`).join(`
131
131
  `)}`:s=o,r.length&&o&&(s+=`
132
- ${o}`),s||""}var _0,ZP,QP,eD,E0,Ai,$0,Lf=q(()=>{_0=4,ZP=4,QP=2,eD=24,E0=/^[ \t]{0,3}(`{3,})bostrat-question[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]{0,3}\1`*[ \t]*$/gm,Ai=e=>typeof e=="string"?e.trim():"";$0=`
132
+ ${o}`),s||""}var _0,QP,eD,tD,E0,Ai,$0,Ff=q(()=>{_0=4,QP=4,eD=2,tD=24,E0=/^[ \t]{0,3}(`{3,})bostrat-question[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]{0,3}\1`*[ \t]*$/gm,Ai=e=>typeof e=="string"?e.trim():"";$0=`
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
@@ -149,76 +149,76 @@ your turn. The operator sees the questions as an interactive card in their chat
149
149
  answer. Never use the block for rhetorical questions, progress updates, or
150
150
  anything you can decide yourself; keep asking in prose for questions without
151
151
  enumerable options.
152
- `});function nD(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 O0(e,t,n){let r=Ff(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 Sn(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,b=20*6e4,x=(k,h)=>!!(k?.name&&m.get(String(k.name).toLowerCase()))?.some(D=>D>=h-g&&D<=h+b);for(let k of e||[])if(k.type==="turn.retracted"){r.add(`${k.boxId}|${k.payload?.saidTs}`);let h=He(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=He(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 y=new Map,$=new Map,O=null,M=new Map,H=new Map,P=new Map,E=new Map,R=new Map,G=new Map,V=new Map,A=new Map,_=new Map,N=new Map,U=new Map,z=new Map,ue=new Map,pe=new Map,Se=new Map,Ae=[],W=k=>Ae.push(k),te=k=>{if(!Ae.length)return;let h=he(k);for(let v of Ae){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)}},ie=new Map,J=new Map,ge=new Map,Oe=new Map,Me=new Map,I=new Map,j=new Map,fe=new Map,Pe=()=>{for(let k of fe.values())k.questions.length&&t.push(k);fe.clear()},Ce=null,wn=6e4,gt=new Map,gr=(k,h)=>{let v=o.get(k);if(!v?.length)return!1;let D=He(h),ce=s.get(k);return v.some(ye=>{if(!D.startsWith(ye))return!1;let De=He(D.slice(ye.length));return!!De&&!!ce?.has(De)})};for(let k of e||[]){let h=k.payload||{};switch(k.type){case"turn.user":{if(k.source==="hook"||(Ae.length=0,!String(h.text||"").trim()&&!h.images?.length&&!h.attachments?.length))break;{let v=h.note||Ti(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"&&v0(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:A0(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"&&gr(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"&&(Ce=null);break}for(let v of M.values())v.status="stale";M.clear();for(let v of P.values())v.status="stale";P.clear();for(let v of ue.values())v.status="stale";ue.clear(),Ce&&Ce.box===k.boxId&&(t.push(nD(Ce)),Ce=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=Dk(h,{codexFailedText:xo});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}Pe();let D=(h.images||[]).filter(qe=>!x(qe,he(k)));if(!String(h.text||"").trim()&&!D.length)break;if(k.provider==="cursor"){let qe=`${k.boxId}|${h.text}`;if(n.has(qe))break;n.add(qe)}(!Ce||Ce.box===k.boxId)&&(Ce=null);let ce=k.provider==="codex"?(h.tools||[]).filter(qe=>!hf.has(qe)&&!di.has(qe)):h.tools||[],ye=h.text,De=null,St=Df(String(h.text||""));St&&(ye=St.text,De={questions:St.questions}),t.push({id:k.id,kind:"message",role:"assistant",text:ye,ts:he(k),box:k.boxId,agent:k.provider,boxRole:h.boxRole,...De?{ask:De}:{},...ce.length?{tools:ce}:{},...h.model?{model:h.model}:{},...h.sourceId?{sourceId:h.sourceId}:{},...D.length?{images:D}:{}}),te(k),De&&(Ce={id:k.id,groupId:jf(k.provider,h.sourceId||k.id,De.questions),provider:k.provider,box:k.boxId,questions:De.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 rt=u.get(h.name);rt&&rt.ts>=v&&(D=rt)}let ce=D?null:i.get(h.id)||null,ye={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":ce?"stalled":"running",startedTs:v,finishedTs:D?.ts??ce?.ts??null,quietMs:ce?.quietMs??null,summary:D?.summary??null,resultHead:D?.resultHead??null},De=gt.get(k.boxId),St=De?.jobs[De.jobs.length-1]?.startedTs;if(De&&St!=null&&v-St<=wn)De.jobs.push(ye);else{let rt={id:k.id,kind:"job-dock",dockId:h.id,ts:v,box:k.boxId,agent:k.provider,jobs:[ye]};gt.set(k.boxId,rt),t.push(rt)}break}case"handoff.done":t.push(lt(k,"lead-handoff"));break;case"subtask.delegated":t.push({...lt(k,"subtask-delegated"),to:k.boxId,toAgent:k.provider});break;case"subtask.merged":t.push(lt(k,"subtask-merged"));break;case"pr.state.changed":{if(!h.change)break;if(h.change==="opened"){for(let D of M.values())D.status="stale";M.clear();for(let D of P.values())D.status="stale";P.clear()}let v=lt(k,`pr-${h.change}`);if(v.box=k.boxId??null,R0.has(h.change)&&h.number!=null){let D=O0(y,$,h);if(y.size>=2){for(let ye of $.values())for(let De of ye)De.grouped=!0;v.groupPrs=[...y.values()];let ce=[v];for(let ye of y.keys())$.set(ye,ce)}else{let ce=$.get(D)??[];ce.push(v),$.set(D,ce)}}else if(h.change==="merged"||h.change==="closed"||h.change==="lost"){let D=Ff(h),ce=O&&!O.complete||y.size>=2;if(y.has(D))y.delete(D),$.delete(D);else if(h.number!=null)for(let ye of[...y.keys()])ye.endsWith(`#${h.number}`)&&(y.delete(ye),$.delete(ye));if(ce&&h.number!=null){(!O||O.complete)&&(O={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(O)),O.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)}),O.remaining=[...y.values()],O.complete=y.size===0;break}}t.push(v);break}case"pr.offered":{if(!h.offerId)break;for(let D of M.values())D.status="stale";M.clear();for(let D of P.values())D.status="stale";P.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};M.set(h.offerId,v),H.set(h.offerId,v),t.push(v),v.source==="cli"&&W(v);break}case"pr.offer.answered":{let v=H.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}),M.delete(h.offerId));break}case"pr.exists.offered":{if(!h.offerId)break;for(let D of P.values())D.status="stale";P.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};P.set(h.offerId,v),E.set(h.offerId,v),t.push(v);break}case"pr.exists.answered":{let v=E.get(h.offerId);v&&(v.status=h.choice||"dismiss",P.delete(h.offerId));break}case"box.state.changed":{let v=h.change==="model"?"model-change":h.change;if(!v)break;let D=lt(k,v);if(v==="model-change"&&(D.to=h.model),v==="node-update"&&D.latest){let ce=t.findIndex(ye=>ye.kind==="event"&&ye.type==="node-update"&&ye.latest===D.latest);if(ce>=0){let ye=t[ce];t[ce]={...D,ts:ye.ts,at:ye.at,firstAt:ye.firstAt??ye.ts,updatedAt:D.ts};break}}t.push(D);break}case"track.transferred":case"track.recovered":t.push(lt(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 V.values())D.box===(h.box||k.boxId)&&(D.status="stale",V.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};V.set(h.offerId,v),A.set(h.offerId,v),t.push(v);break}case"box.fullscreen.answered":{let v=A.get(h.offerId);v&&(v.status=h.action==="restarted"?"restarted":h.action==="cleared"?"cleared":"dismiss",V.delete(h.offerId));break}case"ticket.move.offered":{if(!h.offerId)break;for(let D of R.values())D.key===h.key&&(D.status="stale",R.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};R.set(h.offerId,v),G.set(h.offerId,v),t.push(v);break}case"ticket.move.answered":{let v=G.get(h.offerId);v&&(v.status=h.action==="moved"?"moved":"dismiss",R.delete(h.offerId));break}case"ticket.state.changed":{for(let v of R.values())v.key===h.key&&v.to===h.to&&(v.status="stale",R.delete(v.offerId));if(h.mode==="offer")break;t.push(lt(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(lt(k,"ticket-flow"));break;case"ticket.create.offered":{if(!h.proposalId)break;for(let D of _.values())D.status="stale";_.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};_.set(h.proposalId,v),N.set(h.proposalId,v),t.push(v),W(v);break}case"ticket.create.answered":{let v=N.get(h.proposalId);v&&(v.status=h.action==="created"?"created":"dismiss",v.createdCount=h.createdCount??null,v.failedCount=h.failedCount??null,_.delete(h.proposalId));break}case"loop.create.offered":{if(!h.proposalId)break;for(let D of U.values())D.status="stale";U.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};U.set(h.proposalId,v),z.set(h.proposalId,v),t.push(v),W(v);break}case"loop.create.answered":{let v=z.get(h.proposalId);v&&(v.status=h.action==="created"?"created":"dismiss",U.delete(h.proposalId));break}case"followup.armed":{if(!h.armId)break;let v=h.replaces?Se.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};Se.set(h.armId,D),D.trigger!=="now"&&t.push(D);break}case"followup.armed.cancelled":{let v=Se.get(h.armId);v&&v.status==="armed"&&(v.status="cancelled");break}case"followup.offered":{if(!h.offerId)break;for(let ce of ue.values())ce.trigger===h.trigger&&(ce.status="stale",ue.delete(ce.offerId));let v=Array.isArray(h.rows)?h.rows:[];for(let ce of v){let ye=ce.armId?Se.get(ce.armId):null;ye&&ye.status==="armed"&&(ye.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(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(k),box:k.boxId,agent:k.provider};ue.set(h.offerId,D),pe.set(h.offerId,D),t.push(D),D.trigger==="now"&&W(D);break}case"followup.answered":{let v=pe.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},ue.delete(h.offerId));break}case"followup.create.offered":{if(!h.proposalId)break;for(let D of ie.values())D.status="stale";ie.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};ie.set(h.proposalId,v),J.set(h.proposalId,v),t.push(v),W(v);break}case"followup.create.answered":{let v=J.get(h.proposalId);v&&(v.status=h.action==="created"?"created":"dismiss",ie.delete(h.proposalId));break}case"followup.created":{let v=h.proposalId?J.get(h.proposalId):null;v&&(v.created={followupId:h.followupId??null});break}case"loop.created":{let v=h.proposalId?z.get(h.proposalId):null;v&&(v.created={loopId:h.loopId??null,nextFireAt:Number.isFinite(Number(h.nextFireAt))?Number(h.nextFireAt):null}),t.push(lt(k,"loop-created"));break}case"loop.update.offered":case"loop.delete.offered":{if(!h.proposalId||!h.loopId)break;for(let ce of ge.values())ce.loopId===h.loopId&&(ce.status="stale",ce.staleReason="superseded",ge.delete(ce.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};ge.set(h.proposalId,D),Oe.set(h.proposalId,D),t.push(D),W(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",ge.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",ge.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(lt(k,"loop-updated"));break}case"loop.deleted":t.push(lt(k,"loop-deleted"));break;case"loop.paused":t.push(lt(k,"loop-paused"));break;case"planning.change.offered":{if(!h.proposalId||!Array.isArray(h.ops)||!h.ops.length)break;for(let D of Me.values())D.status="stale",D.staleReason="superseded",Me.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};Me.set(h.proposalId,v),I.set(h.proposalId,v),t.push(v),W(v);break}case"planning.change.answered":{let v=I.get(h.proposalId);v&&(h.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=h.action==="applied"?"applied":"dismiss",Me.delete(h.proposalId));break}case"planning.changed":{let v=h.proposalId?I.get(h.proposalId):null;v&&(v.applied={results:Array.isArray(h.results)?h.results:[]}),t.push(lt(k,"planning-changed"));break}case"rework.cause.offered":{if(!h.sha||j.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};j.set(h.sha,v),t.push(v);break}case"rework.cause.answered":{let v=h.sha?j.get(h.sha):null;v&&(v.status="answered",v.cause=h.cause??null);break}case"rework.cause.retracted":{let v=h.sha?j.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?N.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(lt(k,h.kind));break}case"provider.error":t.push({...lt(k,"provider-error"),provider:k.provider,box:k.boxId,agent:k.provider});break;case"usage.cap.hit":t.push(lt(k,"usage-cap-hit"));break;case"usage.cap.warning":t.push(lt(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(Ce=null,h.control||!h.question)break;let v=h.groupId||h.promptId;if(!v)break;let D=fe.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)},fe.set(v,D));let ce=h.questionIndex??0,ye={index:ce,header:h.header||"",question:h.question,multiSelect:!!h.multiSelect,chosen:Array.isArray(h.chosen)?h.chosen:[]},De=D.questions.findIndex(qe=>qe.index===ce&&He(qe.question)===He(ye.question));De>=0?D.questions[De]=ye:D.questions.push(ye),D.questions.sort((qe,rt)=>qe.index-rt.index),D.questionTotal=Math.max(D.questionTotal,h.questionTotal??1),D.questions.length>=D.questionTotal&&(t.push(D),fe.delete(v));break}default:break}}let gn=d.size?t.filter(k=>!k.retired):t;return oD(gn.sort((k,h)=>(k.ts??0)-(h.ts??0)))}function oD(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<=rD){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 Uf(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:sD(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??Sn(e)).filter(o=>o.kind==="message");return Ik(n,r)}function sD(e){let t=String(e.summary||"").trim();return t&&t!==e.command&&t!==$s(e.command)?t:Ir(e.command,e.description||"")}function lt(e,t){let{ts:n,change:r,...o}=e.payload||{};return{id:e.id,kind:"event",type:t,...o,at:he(e),ts:he(e)}}function C0(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)+aD,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||a?.kind==="event"&&iD.has(a.type))break;s++}s>n&&t.splice(s,0,...t.splice(n,1)),n=s}return t}function M0(e){let t=[...e];for(let n=0;n<t.length;n++){let r=t[n];if(r?.kind!=="event"||!lD.has(r.type)||!r.box)continue;let o=(r.ts??0)+cD,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 Zl(e){return(e||[]).filter(t=>uD.has(t?.kind)&&t.status==="open")}function N0(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(R0.has(o.change)&&o.number!=null)O0(t,n,o);else if(o.change==="merged"||o.change==="closed"||o.change==="lost"){let s=Ff(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,R0,Ff,rD,aD,iD,cD,lD,uD,Ql=q(()=>{Rs();vo();Bl();yi();Xl();Lf();he=e=>e.payload?.ts??e.ts;R0=new Set(["opened","ci-fixed","reconciled","pushed"]),Ff=e=>`${e.repo??""}#${e.number}`;rD=2*6e4;aD=12e4,iD=new Set(["archived","unarchived","opened"]);cD=2500,lD=new Set(["pr-opened","pr-merged","pr-auto-armed"]);uD=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 hD(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 gD(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 yD(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<fD&&(o.add(c.path),n.push(c.path)),c.head&&!s.has(c.head)&&r.length<mD&&(s.add(c.head),r.push(c.head))}return{files:n,heads:r}}function B0(e,{trackName:t="this Track",now:n=null,mode:r="failover"}={}){let o=hD(e),s=gD(e),a=s?.payload?.content??null,i=s?s.payload?.ts??s.ts??null:null,c=Sn(e??[]).filter(p=>p?.kind==="message"&&typeof p.text=="string"&&p.text.trim()).slice(-dD);if(!a&&!c.length)return null;let l=[];if(l.push(`# Reconstructed resume brief \u2014 ${t}`),l.push(""),l.push(j0[r]??j0.failover),l.push(""),o.lastPush?.sha){let p=D0(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=D0(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=yD(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"}:** ${wD(p.text,pD)}`),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(`
152
+ `});function rD(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 O0(e,t,n){let r=Uf(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 Sn(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,b=20*6e4,x=(k,h)=>!!(k?.name&&m.get(String(k.name).toLowerCase()))?.some(D=>D>=h-g&&D<=h+b);for(let k of e||[])if(k.type==="turn.retracted"){r.add(`${k.boxId}|${k.payload?.saidTs}`);let h=He(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=He(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 y=new Map,$=new Map,O=null,M=new Map,H=new Map,P=new Map,E=new Map,R=new Map,G=new Map,V=new Map,A=new Map,_=new Map,N=new Map,U=new Map,z=new Map,ue=new Map,pe=new Map,Se=new Map,Ae=[],W=k=>Ae.push(k),te=k=>{if(!Ae.length)return;let h=he(k);for(let v of Ae){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)}},ie=new Map,J=new Map,ge=new Map,Oe=new Map,Me=new Map,I=new Map,B=new Map,fe=new Map,Pe=()=>{for(let k of fe.values())k.questions.length&&t.push(k);fe.clear()},Ce=null,wn=6e4,gt=new Map,gr=(k,h)=>{let v=o.get(k);if(!v?.length)return!1;let D=He(h),ce=s.get(k);return v.some(ye=>{if(!D.startsWith(ye))return!1;let De=He(D.slice(ye.length));return!!De&&!!ce?.has(De)})};for(let k of e||[]){let h=k.payload||{};switch(k.type){case"turn.user":{if(k.source==="hook"||(Ae.length=0,!String(h.text||"").trim()&&!h.images?.length&&!h.attachments?.length))break;{let v=h.note||Ti(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"&&v0(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:A0(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"&&gr(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"&&(Ce=null);break}for(let v of M.values())v.status="stale";M.clear();for(let v of P.values())v.status="stale";P.clear();for(let v of ue.values())v.status="stale";ue.clear(),Ce&&Ce.box===k.boxId&&(t.push(rD(Ce)),Ce=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=Dk(h,{codexFailedText:xo});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}Pe();let D=(h.images||[]).filter(qe=>!x(qe,he(k)));if(!String(h.text||"").trim()&&!D.length)break;if(k.provider==="cursor"){let qe=`${k.boxId}|${h.text}`;if(n.has(qe))break;n.add(qe)}(!Ce||Ce.box===k.boxId)&&(Ce=null);let ce=k.provider==="codex"?(h.tools||[]).filter(qe=>!wf.has(qe)&&!di.has(qe)):h.tools||[],ye=h.text,De=null,St=Bf(String(h.text||""));St&&(ye=St.text,De={questions:St.questions}),t.push({id:k.id,kind:"message",role:"assistant",text:ye,ts:he(k),box:k.boxId,agent:k.provider,boxRole:h.boxRole,...De?{ask:De}:{},...ce.length?{tools:ce}:{},...h.model?{model:h.model}:{},...h.sourceId?{sourceId:h.sourceId}:{},...D.length?{images:D}:{}}),te(k),De&&(Ce={id:k.id,groupId:jf(k.provider,h.sourceId||k.id,De.questions),provider:k.provider,box:k.boxId,questions:De.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 rt=u.get(h.name);rt&&rt.ts>=v&&(D=rt)}let ce=D?null:i.get(h.id)||null,ye={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":ce?"stalled":"running",startedTs:v,finishedTs:D?.ts??ce?.ts??null,quietMs:ce?.quietMs??null,summary:D?.summary??null,resultHead:D?.resultHead??null},De=gt.get(k.boxId),St=De?.jobs[De.jobs.length-1]?.startedTs;if(De&&St!=null&&v-St<=wn)De.jobs.push(ye);else{let rt={id:k.id,kind:"job-dock",dockId:h.id,ts:v,box:k.boxId,agent:k.provider,jobs:[ye]};gt.set(k.boxId,rt),t.push(rt)}break}case"handoff.done":t.push(lt(k,"lead-handoff"));break;case"subtask.delegated":t.push({...lt(k,"subtask-delegated"),to:k.boxId,toAgent:k.provider});break;case"subtask.merged":t.push(lt(k,"subtask-merged"));break;case"pr.state.changed":{if(!h.change)break;if(h.change==="opened"){for(let D of M.values())D.status="stale";M.clear();for(let D of P.values())D.status="stale";P.clear()}let v=lt(k,`pr-${h.change}`);if(v.box=k.boxId??null,R0.has(h.change)&&h.number!=null){let D=O0(y,$,h);if(y.size>=2){for(let ye of $.values())for(let De of ye)De.grouped=!0;v.groupPrs=[...y.values()];let ce=[v];for(let ye of y.keys())$.set(ye,ce)}else{let ce=$.get(D)??[];ce.push(v),$.set(D,ce)}}else if(h.change==="merged"||h.change==="closed"||h.change==="lost"){let D=Uf(h),ce=O&&!O.complete||y.size>=2;if(y.has(D))y.delete(D),$.delete(D);else if(h.number!=null)for(let ye of[...y.keys()])ye.endsWith(`#${h.number}`)&&(y.delete(ye),$.delete(ye));if(ce&&h.number!=null){(!O||O.complete)&&(O={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(O)),O.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)}),O.remaining=[...y.values()],O.complete=y.size===0;break}}t.push(v);break}case"pr.offered":{if(!h.offerId)break;for(let D of M.values())D.status="stale";M.clear();for(let D of P.values())D.status="stale";P.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};M.set(h.offerId,v),H.set(h.offerId,v),t.push(v),v.source==="cli"&&W(v);break}case"pr.offer.answered":{let v=H.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}),M.delete(h.offerId));break}case"pr.exists.offered":{if(!h.offerId)break;for(let D of P.values())D.status="stale";P.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};P.set(h.offerId,v),E.set(h.offerId,v),t.push(v);break}case"pr.exists.answered":{let v=E.get(h.offerId);v&&(v.status=h.choice||"dismiss",P.delete(h.offerId));break}case"box.state.changed":{let v=h.change==="model"?"model-change":h.change;if(!v)break;let D=lt(k,v);if(v==="model-change"&&(D.to=h.model),v==="node-update"&&D.latest){let ce=t.findIndex(ye=>ye.kind==="event"&&ye.type==="node-update"&&ye.latest===D.latest);if(ce>=0){let ye=t[ce];t[ce]={...D,ts:ye.ts,at:ye.at,firstAt:ye.firstAt??ye.ts,updatedAt:D.ts};break}}t.push(D);break}case"track.transferred":case"track.recovered":t.push(lt(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 V.values())D.box===(h.box||k.boxId)&&(D.status="stale",V.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};V.set(h.offerId,v),A.set(h.offerId,v),t.push(v);break}case"box.fullscreen.answered":{let v=A.get(h.offerId);v&&(v.status=h.action==="restarted"?"restarted":h.action==="cleared"?"cleared":"dismiss",V.delete(h.offerId));break}case"ticket.move.offered":{if(!h.offerId)break;for(let D of R.values())D.key===h.key&&(D.status="stale",R.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};R.set(h.offerId,v),G.set(h.offerId,v),t.push(v);break}case"ticket.move.answered":{let v=G.get(h.offerId);v&&(v.status=h.action==="moved"?"moved":"dismiss",R.delete(h.offerId));break}case"ticket.state.changed":{for(let v of R.values())v.key===h.key&&v.to===h.to&&(v.status="stale",R.delete(v.offerId));if(h.mode==="offer")break;t.push(lt(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(lt(k,"ticket-flow"));break;case"ticket.create.offered":{if(!h.proposalId)break;for(let D of _.values())D.status="stale";_.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};_.set(h.proposalId,v),N.set(h.proposalId,v),t.push(v),W(v);break}case"ticket.create.answered":{let v=N.get(h.proposalId);v&&(v.status=h.action==="created"?"created":"dismiss",v.createdCount=h.createdCount??null,v.failedCount=h.failedCount??null,_.delete(h.proposalId));break}case"loop.create.offered":{if(!h.proposalId)break;for(let D of U.values())D.status="stale";U.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};U.set(h.proposalId,v),z.set(h.proposalId,v),t.push(v),W(v);break}case"loop.create.answered":{let v=z.get(h.proposalId);v&&(v.status=h.action==="created"?"created":"dismiss",U.delete(h.proposalId));break}case"followup.armed":{if(!h.armId)break;let v=h.replaces?Se.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};Se.set(h.armId,D),D.trigger!=="now"&&t.push(D);break}case"followup.armed.cancelled":{let v=Se.get(h.armId);v&&v.status==="armed"&&(v.status="cancelled");break}case"followup.offered":{if(!h.offerId)break;for(let ce of ue.values())ce.trigger===h.trigger&&(ce.status="stale",ue.delete(ce.offerId));let v=Array.isArray(h.rows)?h.rows:[];for(let ce of v){let ye=ce.armId?Se.get(ce.armId):null;ye&&ye.status==="armed"&&(ye.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(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(k),box:k.boxId,agent:k.provider};ue.set(h.offerId,D),pe.set(h.offerId,D),t.push(D),D.trigger==="now"&&W(D);break}case"followup.answered":{let v=pe.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},ue.delete(h.offerId));break}case"followup.create.offered":{if(!h.proposalId)break;for(let D of ie.values())D.status="stale";ie.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};ie.set(h.proposalId,v),J.set(h.proposalId,v),t.push(v),W(v);break}case"followup.create.answered":{let v=J.get(h.proposalId);v&&(v.status=h.action==="created"?"created":"dismiss",ie.delete(h.proposalId));break}case"followup.created":{let v=h.proposalId?J.get(h.proposalId):null;v&&(v.created={followupId:h.followupId??null});break}case"loop.created":{let v=h.proposalId?z.get(h.proposalId):null;v&&(v.created={loopId:h.loopId??null,nextFireAt:Number.isFinite(Number(h.nextFireAt))?Number(h.nextFireAt):null}),t.push(lt(k,"loop-created"));break}case"loop.update.offered":case"loop.delete.offered":{if(!h.proposalId||!h.loopId)break;for(let ce of ge.values())ce.loopId===h.loopId&&(ce.status="stale",ce.staleReason="superseded",ge.delete(ce.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};ge.set(h.proposalId,D),Oe.set(h.proposalId,D),t.push(D),W(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",ge.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",ge.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(lt(k,"loop-updated"));break}case"loop.deleted":t.push(lt(k,"loop-deleted"));break;case"loop.paused":t.push(lt(k,"loop-paused"));break;case"planning.change.offered":{if(!h.proposalId||!Array.isArray(h.ops)||!h.ops.length)break;for(let D of Me.values())D.status="stale",D.staleReason="superseded",Me.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};Me.set(h.proposalId,v),I.set(h.proposalId,v),t.push(v),W(v);break}case"planning.change.answered":{let v=I.get(h.proposalId);v&&(h.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=h.action==="applied"?"applied":"dismiss",Me.delete(h.proposalId));break}case"planning.changed":{let v=h.proposalId?I.get(h.proposalId):null;v&&(v.applied={results:Array.isArray(h.results)?h.results:[]}),t.push(lt(k,"planning-changed"));break}case"rework.cause.offered":{if(!h.sha||B.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};B.set(h.sha,v),t.push(v);break}case"rework.cause.answered":{let v=h.sha?B.get(h.sha):null;v&&(v.status="answered",v.cause=h.cause??null);break}case"rework.cause.retracted":{let v=h.sha?B.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?N.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(lt(k,h.kind));break}case"provider.error":t.push({...lt(k,"provider-error"),provider:k.provider,box:k.boxId,agent:k.provider});break;case"usage.cap.hit":t.push(lt(k,"usage-cap-hit"));break;case"usage.cap.warning":t.push(lt(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(Ce=null,h.control||!h.question)break;let v=h.groupId||h.promptId;if(!v)break;let D=fe.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)},fe.set(v,D));let ce=h.questionIndex??0,ye={index:ce,header:h.header||"",question:h.question,multiSelect:!!h.multiSelect,chosen:Array.isArray(h.chosen)?h.chosen:[]},De=D.questions.findIndex(qe=>qe.index===ce&&He(qe.question)===He(ye.question));De>=0?D.questions[De]=ye:D.questions.push(ye),D.questions.sort((qe,rt)=>qe.index-rt.index),D.questionTotal=Math.max(D.questionTotal,h.questionTotal??1),D.questions.length>=D.questionTotal&&(t.push(D),fe.delete(v));break}default:break}}let gn=d.size?t.filter(k=>!k.retired):t;return sD(gn.sort((k,h)=>(k.ts??0)-(h.ts??0)))}function sD(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<=oD){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 Hf(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:aD(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??Sn(e)).filter(o=>o.kind==="message");return Ik(n,r)}function aD(e){let t=String(e.summary||"").trim();return t&&t!==e.command&&t!==$s(e.command)?t:Ir(e.command,e.description||"")}function lt(e,t){let{ts:n,change:r,...o}=e.payload||{};return{id:e.id,kind:"event",type:t,...o,at:he(e),ts:he(e)}}function C0(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)+iD,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||a?.kind==="event"&&cD.has(a.type))break;s++}s>n&&t.splice(s,0,...t.splice(n,1)),n=s}return t}function M0(e){let t=[...e];for(let n=0;n<t.length;n++){let r=t[n];if(r?.kind!=="event"||!uD.has(r.type)||!r.box)continue;let o=(r.ts??0)+lD,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 Zl(e){return(e||[]).filter(t=>dD.has(t?.kind)&&t.status==="open")}function N0(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(R0.has(o.change)&&o.number!=null)O0(t,n,o);else if(o.change==="merged"||o.change==="closed"||o.change==="lost"){let s=Uf(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,R0,Uf,oD,iD,cD,lD,uD,dD,Ql=q(()=>{Rs();vo();jl();yi();Xl();Ff();he=e=>e.payload?.ts??e.ts;R0=new Set(["opened","ci-fixed","reconciled","pushed"]),Uf=e=>`${e.repo??""}#${e.number}`;oD=2*6e4;iD=12e4,cD=new Set(["archived","unarchived","opened"]);lD=2500,uD=new Set(["pr-opened","pr-merged","pr-auto-armed"]);dD=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 wD(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 yD(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 bD(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<mD&&(o.add(c.path),n.push(c.path)),c.head&&!s.has(c.head)&&r.length<hD&&(s.add(c.head),r.push(c.head))}return{files:n,heads:r}}function j0(e,{trackName:t="this Track",now:n=null,mode:r="failover"}={}){let o=wD(e),s=yD(e),a=s?.payload?.content??null,i=s?s.payload?.ts??s.ts??null:null,c=Sn(e??[]).filter(p=>p?.kind==="message"&&typeof p.text=="string"&&p.text.trim()).slice(-pD);if(!a&&!c.length)return null;let l=[];if(l.push(`# Reconstructed resume brief \u2014 ${t}`),l.push(""),l.push(B0[r]??B0.failover),l.push(""),o.lastPush?.sha){let p=D0(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=D0(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=bD(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"}:** ${gD(p.text,fD)}`),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(`
153
153
  `);return d.length<=P0?d:`${d.slice(0,P0)}
154
154
 
155
- [\u2026 brief truncated]`}var dD,pD,P0,fD,mD,wD,D0,j0,L0=q(()=>{Ql();dD=12,pD=2e3,P0=48e3,fD=30,mD=10;wD=(e,t)=>{let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1)}\u2026`},D0=(e,t)=>e&&t?Math.max(1,Math.round((e-t)/6e4)):null;j0={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 bD from"node:fs";import Rr from"node:fs/promises";import Or from"node:path";function z0(e){let t=go(String(e??"")),n=Buffer.byteLength(t,"utf8");return n<=F0?{content:t,bytes:n,truncated:!1}:{content:`${Buffer.from(t,"utf8").subarray(0,F0).toString("utf8").replace(/�+$/,"")}
156
-
157
- [\u2026 truncated by bostrat at 32 KiB \u2014 full artifact in the workspace]`,bytes:n,truncated:!0}}function ID(e){let t=String(e||"").split(/\r?\n/).map(s=>s.trim()).filter(Boolean),n=[],r=[];for(let s of t)if(H0.test(s)){if(r.length>=Q0)continue;let a=_D(s.replace(H0,"").replace(/[.;,:]+$/,""),ex,AD);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>U0&&(o=`${o.slice(0,U0-1).trimEnd()}\u2026`),{text:o,items:r.length>1?r:[]}}async function tx(e,t,{timeoutMs:n=9e4}={}){let r=Or.join(t,SD),o=Or.join(r,TD);await Rr.mkdir(r,{recursive:!0});let s=await eu(o),a=await ke(e);if(!a)throw new Error(`session "${e}" not found`);return await tu(e,a,ED(o)),await cx(o,s,n),ID(await Rr.readFile(o,"utf8"))}function nx(e,t){let n=(t||"").trim();if(!n)return!1;if(e==="assistant")return n===J0||n===Z0;let r=n.replace(/^\/[a-z0-9:_-]+\s+/i,"");return r.startsWith(V0)||n===kD||r.startsWith(Y0)||r.startsWith(X0)}function rx(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-$D;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 ox(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 sx(e,{windows:t=[]}={}){if(nx(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 Hf.get(e)||null}async function ax(e){let t=Hf.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:Or.join(n.cwd,K0,G0)};return Hf.set(e,r),CD(r,n.cwd).catch(o=>{r.error=o?.message||String(o),r.finishedAt=Date.now()}),r}async function CD(e,t){e.step="summarize",await ix(e.name,t),e.step="clear";let n=await ke(e.name);await tu(e.name,n,"/clear"),await Kf(RD),e.step="resume",await tu(e.name,n,vD),e.step="done",e.finishedAt=Date.now()}async function ix(e,t,{timeoutMs:n=OD}={}){let r=Or.join(t,K0),o=Or.join(r,G0);await Rr.mkdir(r,{recursive:!0});let s=await eu(o),a=await ke(e);await le({flow:"checkpoint",phase:"summarize-start",sessionName:e,cwd:t,file:o,beforeMtime:s}),await tu(e,a,xD(o)),await cx(o,s,n),await le({flow:"checkpoint",phase:"summarize-done",sessionName:e,file:o,afterMtime:await eu(o)});let i=await h0(t,o,{exclude:u=>nx(u.role,u.text)});await le({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 Rr.readFile(o,"utf8");await C({id:c,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...z0(u),ts:Date.now()}})}catch{}}await Wp(t);let l=await MD(r,o);return c&&await Jb(c,l||o,{box:e,agent:a?.agent??null}),o}async function Wf(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 ix(e,n.cwd,t?{timeoutMs:t}:void 0)}async function qf(e,t,{trackName:n="this Track"}={}){let r=await K({id:e,cwd:t}),o=B0(r,{trackName:n,now:Date.now(),mode:"in-place"});if(!o)return null;let s=Or.join(t,W0);return await Rr.mkdir(Or.dirname(s),{recursive:!0}),await Rr.writeFile(s,o,"utf8"),await C({id:e,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...z0(o),reconstructed:!0,ts:Date.now()}}).catch(()=>{}),W0}async function eu(e){try{return(await Rr.stat(e)).mtimeMs}catch{return 0}}async function cx(e,t,n){let r=Date.now()+n;for(;;){if(await eu(e)>t)return;if(Date.now()>r)throw new Error(`timed out waiting for the handoff file to be written (${e})`);await Kf(2e3)}}async function MD(e,t){try{if(!bD.existsSync(t))return null;let n=new Date().toISOString().replace(/[:.]/g,"-"),r=Or.join(e,`${n}.md`);return await Rr.copyFile(t,r),r}catch{return null}}function Kf(e){return new Promise(t=>setTimeout(t,e))}function q0(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 tu(e,t,n){if(t){let o=q0(t.agent);await $r({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 Ke(e,["Escape"],{kind:"drive-wipe"}),await Kf(150),await As(e,Pl,{kind:"drive-wipe"}),await nt(e,n,{kind:"orchestration-drive",...vn(r.agent,n)}),await ki({sessionName:e,agent:r.agent,agentCmd:q0(r.agent),text:n,flow:"orchestration-drive"})}var K0,G0,F0,V0,J0,Y0,kD,xD,vD,X0,Z0,SD,TD,U0,Q0,ex,AD,ED,H0,_D,$D,RD,OD,Hf,W0,Gf=q(()=>{ct();hi();kn();wi();Rf();w0();Va();de();El();L0();K0=".bostrat/handoff",G0="latest.md",F0=32*1024;V0="Checkpoint: write a work-in-progress handoff",J0="HANDOFF WRITTEN",Y0="Resume from .bostrat/handoff/latest.md",kD="/clear",xD=e=>`${V0} 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 ${J0} and take no further action.`,vD=`${Y0}: read it, restate the Objective and the single next step in one line, then continue the work from 'Next steps'.`,X0="Beat: write a",Z0="BEAT WRITTEN",SD=".bostrat/arc",TD="beat.txt",U0=200,Q0=4,ex=5,AD=36,ED=e=>`${X0} 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 ${Q0} further lines, each starting with "- " and naming ONE piece in at most ${ex} 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 ${Z0} and take no further action.`,H0=/^(?:[-–—*•·]|\d+[.)])\s+/,_D=(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};$D=6e5;RD=3500,OD=3e5,Hf=new Map;W0=".bostrat/handoff/status-latest.md"});function Mr(e,t,n){if(e==null)return t==="from"?-1/0:1/0;if(!ru.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 dx(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:Mr(o.from,"from",n),toMs:Mr(o.to,"to",n)}))}return t}function Vf(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 PD(e){if(!e)return null;let t=String(e).trim();return Cr[t]?t:lx[t]?lx[t]:Object.keys(Cr).find(r=>t.startsWith(r))||null}function DD(e){if(!e||e===Cr)return ND;let t=ux.get(e);return t||(t=dx(e),ux.set(e,t)),t}function px(e,t,n={}){let{table:r,speed:o}=n,s=DD(r),a=r&&r!==Cr?s[e]?e:null:PD(e);if(!a)return null;let i=Vf(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 Tn(e,t={},n,r){let o=px(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 jD(e=Cr){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:Mr(a.from,"from",n),toMs:Mr(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`),ru.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 LD({now:e=Date.now(),table:t=Cr,...n}={}){let{staleDays:r,leadDays:o,confirmDays:s}={...BD,...n},a=[],i=Vf(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:Mr(d.from,"from",c),toMs:Mr(d.to,"to",c),verifiedMs:ru.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*zf;p&&i-d.verifiedMs>r*zf&&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*zf&&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 Ps({now:e=Date.now(),table:t=Cr,...n}={}){let r=Vf(e)??Date.now(),o=null,s=[];for(let[i,c]of Object.entries(t))for(let l of c){let u=Mr(l.from,"from",i),d=Mr(l.to,"to",i);r>=u&&r<=d&&ru.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=[...jD(t),...LD({now:r,table:t,...n})];return{tableVerifiedAt:o,upcomingChanges:s,problems:a,ok:a.length===0}}var Cr,lx,ru,ND,ux,fx,BD,zf,Vn=q(()=>{Cr={"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)."}]},lx={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"},ru=/^\d{4}-\d{2}-\d{2}$/;ND=dx(Cr);ux=new WeakMap;fx=(e,t,n)=>px(e,t,n)!==null;BD=Object.freeze({staleDays:90,leadDays:14,confirmDays:30}),zf=864e5});function FD(e){return e?{input:e.input||0,output:e.output||0,cacheRead:e.cacheRead||0,cacheWrite:e.cacheWrite??e.cacheCreation??0}:null}function hx(e,t){t&&(e.input+=t.input,e.output+=t.output,e.cacheRead+=t.cacheRead,e.cacheCreation+=t.cacheWrite)}function Wt(e){let t=e.payload?.model||"unknown",n=FD(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=Tn(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&&!fx(t,e.ts,o?{speed:o}:void 0);return{usd:a,model:t,tokens:n,repriced:i,unpriced:l,asRecorded:r}}function Nr(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=mx();for(let p of n){let{usd:f,model:w,tokens:m,repriced:g,unpriced:b,asRecorded:x}=Wt(p);i+=x;let y=p.provider||"unknown",$=p.boxId||"unattributed";if(g&&c++,b&&(l++,u.add(w)),a+=f,hx(d,m),r[w]||={usd:0,tokens:mx(),events:0},r[w].usd+=f,r[w].events+=1,hx(r[w].tokens,m),o[y]||={usd:0,events:0},o[y].usd+=f,o[y].events+=1,s[$]||={usd:0,events:0,provider:y,models:new Set,label:t[$]||$},s[$].usd+=f,s[$].events+=1,w!=="unknown"&&s[$].models.add(w),p.epoch!=null){let O=(s[$].epochs||={})[p.epoch]||={usd:0,events:0,provider:y,models:new Set};O.usd+=f,O.events+=1,O.provider=y,w!=="unknown"&&O.models.add(w)}}return{totalUsd:Ds(a),asRecordedUsd:Ds(i),totalTokens:d,turns:n.length,repricedTurns:c,unpricedTurns:l,unpricedModels:[...u],byModel:ou(r,p=>({...p,usd:Ds(p.usd)})),byProvider:ou(o,p=>({...p,usd:Ds(p.usd)})),byBox:ou(s,p=>({usd:Ds(p.usd),events:p.events,provider:p.provider,label:p.label,models:[...p.models],...p.epochs?{epochs:ou(p.epochs,f=>({usd:Ds(f.usd),events:f.events,provider:f.provider,models:[...f.models]}))}:{}}))}}var mx,Ds,ou,Pr=q(()=>{Vn();mx=()=>({input:0,output:0,cacheRead:0,cacheCreation:0});Ds=e=>Math.round(e*1e4)/1e4,ou=(e,t)=>Object.fromEntries(Object.entries(e).map(([n,r])=>[n,t(r)]))});function UD(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 wx(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(Jf(s,"PR")+" opened");let a=Object.keys(e?.subtasks||{}).length||r.filter(u=>u.type==="subtask-delegated").length;a&&n.push(Jf(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(`${Jf(i.length,"handoff")} ${u}${i.length>3?"\u2026":""}`)}let c=Nr(t);c.totalUsd>=.01&&n.push(`$${c.totalUsd.toFixed(2)}`);let l=Number.isFinite(e?.archivedAt)&&Number.isFinite(e?.createdAt)?UD(e.archivedAt-e.createdAt):null;return n.length&&l&&n.push(l),n.length?n.join(" \xB7 "):null}var Jf,gx=q(()=>{Pr();Jf=(e,t)=>`${e} ${t}${e===1?"":"s"}`});import{execFile as HD}from"node:child_process";import{promisify as WD}from"node:util";import{randomUUID as qD}from"node:crypto";async function Yf(e,t){let n=Date.now()+t;for(;;){if(await Kn(e))return!0;if(Date.now()>n)return!1;await Ei(GD)}}async function VD(e,t){let n=bx[t]||bx.default;n.escape&&(await Ke(e,["Escape"],{kind:"swap-exit"}),await Ei(150)),n.wipe&&await As(e,Pl,{kind:"swap-exit"}),await Dl(e,n.text,{perCharDelayMs:90,kind:"swap-exit"});let r=vn(t).submitDelayMs||0;await Ei(Math.max(r,250)),await Ke(e,["Enter"],{kind:"swap-exit"})}async function kx(e,t){try{let{stdout:n}=await To(X,Z("show-environment","-t",e,t));return!String(n||"").trimStart().startsWith("-")}catch{return!1}}async function xx(e){await To(X,Z("respawn-pane","-k","-t",e))}async function Xf(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 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||Ar(n),a=Number(t.exitTimeoutMs)||KD;await le({flow:"swap",phase:"start",sessionName:e,from:o,to:s,cwd:r.cwd});let i=!1;if(!await Kn(e)&&(await VD(e,o),!await Yf(e,a)&&(i=!0,await le({flow:"swap",phase:"respawn-forced",sessionName:e,from:o}),await xx(e),!await Yf(e,yx))))throw new Error(`pane shell did not come back after respawn-pane in "${e}"`);let c=s==="claude"&&yo(n),l=c?al():null,u=await kx(e,"ANTHROPIC_API_KEY"),d=!1;try{l?(await To(X,Z("set-environment","-t",e,"ANTHROPIC_API_KEY",l)),d=!0):u&&(await To(X,Z("set-environment","-u","-t",e,"ANTHROPIC_API_KEY")),d=!0)}catch(g){throw l?$l(g,l):g}if(d&&!i&&(await xx(e),!await Yf(e,yx)))throw new Error(`pane shell did not come back after env respawn in "${e}"`);let p=!!t.resumeSessionId,f=t.resumeSessionId||qD(),w=p?n:oi(n,f,e),m=p?t.pinned===!0:/(^|\s)--session-id(\s|=)/.test(w);return c&&await yr(r.cwd),s==="codex"&&await ps(r.cwd),s==="cursor"&&await fs(r.cwd),await bo(e),await To(X,Z("set-option","-t",e,"@bostrat-sid",f)),await To(X,Z("set-option","-t",e,"@bostrat-agent",s)),await Ei(zD),c&&ri().length&&(await kx(e,ni)||await To(X,Z("set-environment","-t",e,ni,"1")).catch(()=>{}),await nt(e,`export ${ni}=1`,{kind:"swap-env"}),await Ei(150)),await nt(e,w,{kind:"swap-launch"}),await le({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 To,Ei,KD,yx,GD,zD,bx,vx=q(()=>{ct();Ua();cl();ll();wi();kn();To=WD(HD),Ei=e=>new Promise(t=>setTimeout(t,e)),KD=Number(process.env.BOSTRAT_SWAP_EXIT_TIMEOUT_MS)||15e3,yx=Number(process.env.BOSTRAT_SWAP_SHELL_TIMEOUT_MS)||8e3,GD=250,zD=400,bx={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 QD(e){if(e.type==="queue-operation"&&e.operation==="enqueue")return Sx.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"&&Sx.test(t)?t:null}async function Tx(e,t={}){return(await Ex(e,t)).launches}async function Ax(e,t={}){let{launches:n,done:r}=await Ex(e,t);return n.filter(o=>!r.has(o.id))}async function Ex(e,{maxBytes:t=2097152,limit:n=100}={}){let r;try{r=await _t(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(`
158
- `)){let u=l.trim();if(!u||u[0]!=="{")continue;let d;try{d=JSON.parse(u)}catch{continue}if(d.isSidechain)continue;let p=QD(d);if(p){let m=p.match(ZD)?.[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(),b={id:m.id,kind:"command",name:String(m.input?.description||"").trim()||(g?$s(g):null),detail:g?$s(g):null,ts:w,proven:m.input?.run_in_background===!0};b.proven?o.set(m.id,b):i.set(m.id,b)}}else if(m.type==="tool_result"&&m.tool_use_id){let g=e1(m.content);if(JD.test(g)&&s.add(m.tool_use_id),g.match(YD)){let x=i.get(m.tool_use_id);x&&(i.delete(m.tool_use_id),x.proven=!0,x.outputFile=g.match(XD)?.[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 JD,YD,XD,Sx,ZD,e1,_x=q(()=>{nn();Rs();JD=/^Async (?:agent|task) launched/i,YD=/^Command did not complete within its [^\n]*?moved to the background \(ID: ([^)]+)\)/i,XD=/Output is being written to:\s*(\S+)/i,Sx=/^\s*<task-notification>/i,ZD=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i;e1=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 Dr(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 t1(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 Ix(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:rn(`read ${Dr(r,n)}${o?` (lines ${o}\u2013${s??"end"})`:""}`,140),description:o?`Read lines ${o}\u2013${s??"end"} of ${js(r)}`:`Read ${js(r)}`}}case"Grep":{let r=t?.pattern;if(!r)return null;let o=t?.path?Dr(t.path,n):null,s=t?.glob?` --glob ${Zf(t.glob)}`:"",a=rn(String(r),40);return{command:rn(`grep ${Zf(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?Dr(t.target_directory,n):null;return{command:rn(`glob ${Zf(r)}${o&&o!=="."?` ${o}`:""}`,140),description:`Find files matching \u201C${rn(String(r),40)}\u201D`}}case"StrReplace":return t?.path?{command:rn(`edit ${Dr(t.path,n)}`,140),description:`Edit ${js(t.path)}`}:null;case"Write":return t?.path?{command:rn(`write ${Dr(t.path,n)}`,140),description:`Write ${js(t.path)}`}:null;case"Delete":return t?.path?{command:rn(`delete ${Dr(t.path,n)}`,140),description:`Delete ${js(t.path)}`}:null;case"ReadLints":{let o=(Array.isArray(t?.paths)?t.paths:[]).map(s=>Dr(s,n)).filter(Boolean);return{command:rn(o.length?`lints ${o.join(" ")}`:"lints",140),description:"Check lints"}}case"ApplyPatch":{let r=t1(t);if(!r.length)return null;let o=r.length>1?` (+${r.length-1} more)`:"";return{command:rn(`apply_patch ${Dr(r[0],n)}${o}`,140),description:r.length>1?`Patch ${r.length} files`:`Patch ${js(r[0])}`}}case"Await":{let r=t?.shell_id??t?.task_id;return{command:rn(`await ${r??"background output"}`,140),description:"Wait for a background command"}}default:return null}}var su,rn,js,Zf,$x=q(()=>{su=new Set(["Shell","Read","Grep","Glob","StrReplace","Write","ReadLints","Delete","ApplyPatch","Await"]),rn=(e,t=88)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,js=e=>String(e).replace(/\/+$/,"").split("/").pop()||String(e);Zf=e=>`"${String(e).replace(/"/g,'\\"')}"`});import _i from"node:fs";import n1 from"node:fs/promises";import Ao from"node:path";import r1 from"node:os";import o1 from"node:crypto";import s1 from"node:zlib";function Cx(e){let t=o1.createHash("md5").update(String(e)).digest("hex");return Ao.join(a1,t)}function Mx(e){try{let t=JSON.parse(_i.readFileSync(Ao.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 i1(e){let t=Cx(e),n;try{n=_i.readdirSync(t,{withFileTypes:!0}).filter(o=>o.isDirectory())}catch{return null}let r=null;for(let o of n){let s=Ao.join(t,o.name),a=Ao.join(s,"store.db");if(!_i.existsSync(a))continue;let i=Mx(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 au(e,t){if(!e)return null;if(t){let n=Ao.join(Cx(e),t),r=Ao.join(n,"store.db");if(_i.existsSync(r))return{id:t,dir:n,store:r,...Mx(n)||{createdAtMs:null,updatedAtMs:null}}}return i1(e)}function Rx(e,t){let n=e.prepare("SELECT data FROM blobs WHERE id = ?").get(t);return n?Buffer.from(n.data):null}function c1(e){if(!e)return null;let t=e;if(t.length>1&&t[0]===31&&t[1]===139)try{t=s1.gunzipSync(t)}catch{}try{return JSON.parse(t.toString("utf8"))}catch{return null}}function l1(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 u1(e,t){if(!Array.isArray(e))return[];let n=[];for(let r of e){if(!r||r.type!=="tool-call"||!su.has(r.toolName))continue;let o=Ix(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 Qf(e,t){if(!Ox)return Bs;let{DatabaseSync:n}=Ox,r;try{r=new n(e,{readOnly:!0})}catch{return Bs}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 Bs;let s;try{s=JSON.parse(Buffer.from(String(o.value),"hex").toString("utf8"))}catch{return Bs}let a=s.lastUsedModel||null,i=s.latestRootBlobId?Rx(r,s.latestRootBlobId):null;if(!i)return{...Bs,model:a};let c=[],l=[],u=[],d=null,p=[];for(let f of l1(i)){let w=c1(Rx(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 y=x?.providerOptions?.cursor?.modelName;y&&(d=y)}l.push(...u1(w.content,t).map((x,y)=>({...x,id:x.id||`${f}:${y}`}))),u.push(...p1(w.content));let g=d1(w.content);if(!g)continue;let b=[...new Set(u)];u=[],c.push({id:f,text:g,tools:b.length?b:void 0,commands:l,model:d}),l=[]}return{turns:c,trailingCommands:l,model:a,requestIds:p}}catch{return Bs}finally{try{r.close()}catch{}}}function Nx(e,t){let n=e.updatedAtMs;if(!n)try{n=Math.round(_i.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 Px(e,t,{limit:n=80}={}){let r=au(e,t);if(!r)return[];let{turns:o,model:s}=await Qf(r.store,e);if(!o.length)return[];let a=o.slice(-n),{tsAt:i}=Nx(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 Dx(e,t){let n=au(e,t);if(!n)return null;let{turns:r,requestIds:o,model:s}=await Qf(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 jx(e,t,{limit:n=80}={}){let r=au(e,t);if(!r)return[];let{turns:o,trailingCommands:s}=await Qf(r.store,e);if(!o.length&&!s.length)return[];let a=o.slice(-n),{end:i,tsAt:c}=Nx(r,a.length||1),l=[];a.forEach((u,d)=>{for(let p of u.commands)l.push({...p,summary:Ir(p.command,p.description),ts:c(d)})});for(let u of s)l.push({...u,summary:Ir(u.command,u.description),ts:i+1});return l}async function Bx(e,t){let n=au(e,t);if(!n)return null;if(n.updatedAtMs)return n.updatedAtMs;try{return Math.round((await n1.stat(n.store)).mtimeMs)}catch{return null}}var a1,d1,p1,Ox,Bs,em=q(()=>{Rs();$x();a1=process.env.BOSTRAT_CURSOR_CHATS||Ao.join(r1.homedir(),".cursor","chats");d1=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(`
159
- `).trim():"",p1=e=>Array.isArray(e)?e.filter(t=>t&&t.type==="tool-call"&&t.toolName).map(t=>t.toolName):[],Ox=process.getBuiltinModule?.("node:sqlite"),Bs={turns:[],trailingCommands:[],model:null,requestIds:[]}});import f1 from"node:fs/promises";function om(e){return Lx.set(e.agent,e),e}function jr(e){return Lx.get(e)||m1}async function sm(e,t={}){return(await jr(e.agent).readMessages(e,t)).map(iu(e))}async function Fx(e,t={}){return(await jr(e.agent).readCommands(e,t)).map(iu(e))}async function Ux(e,t={}){return(await jr(e.agent).readJobs(e,t)).map(iu(e))}async function Hx(e,t={}){return(await jr(e.agent).readOpenJobs(e,t)).map(iu(e))}var Ls,tm,nm,rm,m1,Lx,iu,am=q(()=>{nn();Ll();Rs();_x();em();vo();Ls=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}},tm=class extends Ls{transcript(t){return!t?.cwd||!t?.sessionId?null:tn(t.cwd,t.sessionId)}async readMessages(t,n){let r=this.transcript(t);return r?gf(r,n):[]}async readCommands(t,n){let r=this.transcript(t);return r?_k(r,n):[]}async readJobs(t,n){let r=this.transcript(t);return r?Tx(r,n):[]}async readOpenJobs(t,n){let r=this.transcript(t);return r?Ax(r,n):[]}async updatedAt(t){let n=this.transcript(t);if(!n)return null;try{return Math.round((await f1.stat(n)).mtimeMs)}catch{return null}}},nm=class extends Ls{async readMessages(t,n){return Px(t.cwd,t.sessionId,n)}async readCommands(t,n){return jx(t.cwd,t.sessionId,n)}async updatedAt(t){return Bx(t.cwd,t.sessionId)}},rm=class extends Ls{sessionId(t){return t?.pinned?t.sessionId:null}async readMessages(t,n){return Ok(t.cwd,this.sessionId(t),n)}async readCommands(t,n){return Ck(t.cwd,this.sessionId(t),n)}async updatedAt(t){return Mk(t.cwd,this.sessionId(t))}},m1=new Ls("unknown"),Lx=new Map;om(new tm("claude",pf));om(new nm("cursor",su));om(new rm("codex",di));iu=e=>t=>({...t,box:e.name,agent:e.agent,boxRole:e.role})});function Io(e){let t=e.search(um);return(t>=0?e.slice(0,t):e).trim()}function h1(e){if(!e)return"";let t=e.replace(/[│┌└├─┘┤┬┴┼─✂].*$/,"").trim();return!t||/hidden|\d+\s+lines?/i.test(t)?"":t}function w1(e){let t=String(e).trim();return!!(!t||_o.test(e)||um.test(t)||/hidden|\d+\s+lines?/i.test(t)||/notespress|press n to add/i.test(t)||/^\s*notes?\s*$/i.test(t))}function g1(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=y1(n,t);return n.forEach((a,i)=>{a.current=i===s}),{tabs:n,questionIndex:s,questionTotal:n.length,currentTabLabel:n[s].label}}function y1(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 qx(e){return e.replace(/[←→✔☐☒●▶]/g," ").replace(/\bSubmit\b/g," ").replace(/\s+/g," ").trim()}function b1(e,t=""){let n=String(e);if(!Gx.test(n))return null;let r=n.replace(/\r/g,"").split(`
160
- `),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(Eo);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&&!_o.test(r[u])&&a.push(p)}}if(s.length<2)return null;let i=s.map(u=>({label:Io(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 x1(e,t=""){let n=String(e).replace(/\r/g,"").split(`
161
- `),r=n.length-1;for(;r>=0&&n[r].trim()==="";)r--;if(r<0||!zx.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(Eo);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&&!(k1.test(n[c])||_o.test(n[c]));c--){let l=n[c].trim();l&&a.unshift(l)}let i=s.map(c=>({label:Io(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 v1(e,t=""){let n=String(e);if(!/ready to submit your answers/i.test(n))return null;let r=n.replace(/\r/g,"").split(`
162
- `),o=[];for(let c=0;c<r.length;c++){let l=r[c].match(Eo);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 T1(e,t=""){let n=String(e);if(!im.test(n))return null;let r=n.replace(/\r/g,"").split(`
163
- `),o=-1;for(let u=r.length-1;u>=0;u--)if(S1.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(Eo);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&&!_o.test(r[u])&&a.push(p)}}if(s.length<2||!s.some(u=>im.test(u.label)))return null;let i=s.map(u=>({label:Io(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 dm(e){let t=[];for(let r=0;r<e.length;r++){let o=e[r].match(Eo);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 A1(e,t=""){let n=String(e);if(!Vx.test(n)||!Jx.test(n)||$o.test(n))return null;let r=n.replace(/\r/g,"").split(`
164
- `),o=dm(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:Io(s.label),description:""}))}]}:null}function E1(e,t=""){let n=String(e);if(!Yx.test(n)||$o.test(n))return null;let r=n.replace(/\r/g,"").split(`
165
- `),o=dm(r);if(!o)return null;let s=o.map(a=>{let[i,...c]=a.label.split("\xB7");return{label:Io(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 I1(e,t){let n=e[t].trim();for(let r=t+1;r<e.length;r++){let o=e[r].trim();if(!o||!_1.test(o)||pm.test(e[r]))break;n+=o}return n}function $1(e,t=""){let n=String(e);if(!pm.test(n)||$o.test(n))return null;let r=n.replace(/\r/g,"").split(`
166
- `),o="";for(let s=0;s<r.length;s++)if(/^\s*https:\/\//.test(r[s])){o=I1(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 O1(e,t=""){let n=String(e);if(!cm.test(n)||!R1.test(n)||$o.test(n))return null;let s=([...n.replace(/\r/g,"").split(`
167
- `)].reverse().find(a=>cm.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 C1(e,t=""){let n=String(e);if(!Xx.test(n)||$o.test(n))return null;let r=n.replace(/\r/g,"").split(`
168
- `),o=dm(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:Io(s.label),description:""}))}]}:null}function M1(e,t=""){let n=String(e);if($o.test(n))return null;let r=n.replace(/\r/g,"").split(`
169
- `),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(Zx);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(_o.test(r[l])||um.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 N1(e){let t=-1;for(let r=e.length-1;r>=0;r--)if(lm.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 P1(e,t=""){let n=String(e);if(!Kx.test(n)||!lm.test(n))return null;let r=n.replace(/\r/g,"").split(`
170
- `),o=N1(r);if(!o)return null;let{headerLine:s,chatLine:a,optStart:i,optEnd:c}=o,l=[],u=-1;for(let P=i;P<c;P++){let E=r[P].match(Eo);E&&(u<0&&(u=P),l.push({line:P,cursor:!!E[1],checked:E[3]!=null&&E[3]!==" ",hasCheckbox:E[3]!=null,label:E[4].trim(),desc:""}))}if(!l.length)return null;for(let P of l)for(let E=P.line+1;E<Math.min(r.length,P.line+4)&&!(Eo.test(r[E])||_o.test(r[E]));E++){let R=r[E].trim();if(!(!R||w1(r[E])||Wx.test(R))){P.desc=h1(R);break}}let d=l.filter(P=>!Wx.test(P.label));if(!d.length)return null;let p=d.some(P=>P.hasCheckbox),f=Math.max(0,d.findIndex(P=>P.cursor)),w=s>=0?s+1:0,m=[];for(let P=w;P<u;P++){let E=r[P].trim();E&&!_o.test(r[P])&&!/[☐☒]/.test(r[P])&&m.push(E)}let g=m.join(" ")||(s>=0?qx(r[s]):"")||"The agent is asking a question",b=s>=0?g1(r[s],g):null,x=b?.currentTabLabel||(s>=0?qx(r[s]):""),y=d.map(P=>({label:Io(P.label),description:P.desc})),$=y.map(P=>P.label).join("|"),M=`claude:${b?`q${b.questionIndex+1}/${b.questionTotal}`:"q1/1"}:${x}:${g}:${$}`.slice(0,240),H=b?`claude:ask:${b.tabs.map(P=>P.label).join("|")}`.slice(0,240):M;return{provider:"claude",box:t,multiSelect:p,cursorIndex:f,promptId:M,groupId:H,...b?{questionIndex:b.questionIndex,questionTotal:b.questionTotal,currentTabLabel:b.currentTabLabel,tabs:b.tabs}:{},questions:[{question:g,header:x,multiSelect:p,options:y}]}}function Ro(e,t){let n=String(t||"");return n?e==="claude"?Kx.test(n)&&lm.test(n)||Gx.test(n)||im.test(n)||zx.test(n.trimEnd().split(`
171
- `).pop()||"")?!0:$o.test(n)?!1:Vx.test(n)&&Jx.test(n)||Yx.test(n)||pm.test(n)||cm.test(n)||Xx.test(n)||Zx.test(n.trimEnd().split(`
172
- `).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 Br(e,t){return!e||!t?null:e.agent==="claude"?v1(t,e.name)||P1(t,e.name)||b1(t,e.name)||T1(t,e.name)||O1(t,e.name)||$1(t,e.name)||E1(t,e.name)||A1(t,e.name)||C1(t,e.name)||M1(t,e.name)||x1(t,e.name):e.agent==="cursor"||e.agent==="codex"?Vk(e.agent,t,e.name):null}async function fm(e){if(!e)return null;let t=await Gn(e.name).catch(()=>"");return Br(e,t)}function Qx(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 ev(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 Kx,lm,Eo,Wx,_o,um,Gx,zx,k1,im,S1,$o,Vx,Jx,Yx,pm,_1,cm,R1,Xx,Zx,mm=q(()=>{ct();Ul();Kx=/to navigate\b.*\bEsc to cancel|Enter to select\b/,lm=/Chat about this/i,Eo=/^\s*(❯)?\s*(\d+)\.\s+(?:\[([ xX✔])\]\s+)?(.+?)\s*$/,Wx=/^(type something|chat about this|submit)\b/i,_o=/^[─—-]{6,}\s*$/,um=/[\u2500-\u257F\u2550-\u256F┌┐└┘├┤│┬┴┼─✂]/;Gx=/^\s*Switch model\?\s*$/m;zx=/^\s*Enter to confirm\s*·\s*Esc to cancel\s*$/,k1=/^\s*[─—▔-]{6,}\s*$/;im=/Resume from summary/i,S1=/^\s*This session is\b/;$o=/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/;Vx=/Choose the text style that looks best with your terminal/,Jx=/Let's get started\./;Yx=/Select login method:/;pm=/Paste code here if prompted/,_1=/^[A-Za-z0-9%&=+._~#?/:\-]+$/;cm=/OAuth error:/,R1=/Press Enter to retry\./;Xx=/Quick safety check: Is this a project you created or one you trust/;Zx=/^(.{0,60}?)Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/});function cu(e,t,n){if(!e||!t)return null;for(let r of D1)if(r.provider===e.agent)try{if(r.match(t,n))return r}catch{}return null}function B1(e){let t=hm.get(e);return t||(t={sentAt:[],last:0,emitted:new Set},hm.set(e,t)),t}function rv(e,t,n=Date.now()){let r=B1(e);if(r.sentAt=r.sentAt.filter(s=>n-s<nv),r.sentAt.length>=tv)return{action:"give-up"};if(n-r.last<j1)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 ov(e,t=Date.now()){let n=hm.get(e);return n?n.sentAt.filter(r=>t-r<nv).length>=tv:!1}var D1,j1,tv,nv,hm,wm=q(()=>{D1=[{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||""}
173
- ${String(t||"")}`;return/Try the new fullscreen renderer|Flicker-free output/i.test(o)},keys:["Escape"]}];j1=5e3,tv=5,nv=3600*1e3,hm=new Map});function Fs(e){return typeof e=="string"?e.trim():""}var sv=q(()=>{});import{execFile as L1}from"node:child_process";import{promisify as F1}from"node:util";async function ze(e,t,{input:n}={}){let r=ym("git",["-C",e,...t],{maxBuffer:av});return n!==void 0&&r.child.stdin&&(r.child.stdin.on("error",()=>{}),r.child.stdin.end(n)),r}async function Us(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 iv(e){let{stdout:t}=await ze(e,["rev-parse","--show-toplevel"]);return t.trim()}async function U1(e){try{return await ze(e,["rev-parse","--verify","HEAD"]),!0}catch{return!1}}async function Hs(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)=>ym("git",["-C",e,...a],{maxBuffer:av,env:o,...i});try{let a=await U1(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 ym("rm",["-f",r])}catch{}}}async function bm(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 Ii(e,{ignorePlumbing:t=!1}={}){let{stdout:n}=await ze(e,["status","--porcelain"]),r=n.split(`
174
- `).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 $i(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 Ws(e,t,n,r){return await ze(e,["worktree","add","--no-track","-b",n,t,r]),t}async function cv(e,t){try{return await ze(e,["rev-parse","--verify","--quiet",`refs/heads/${t}`]),!0}catch{return!1}}async function lu(e,t,n){return await ze(e,["worktree","add","--end-of-options",t,n]),t}async function qs(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 km(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 Ot(e,t){try{await ze(e,["worktree","remove","--force",t])}catch{try{await ze(e,["worktree","prune"])}catch{}}}function H1(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 xm(e,t){return!t||!t.length?e:[...e,"--",".",...t.map(n=>`:(exclude)${n}`)]}async function vm(e,t,n,r){let{stdout:o}=await ze(e,xm(["diff","--shortstat",t,n],r));return H1(o)}async function Sm(e,t,n,r){let{stdout:o}=await ze(e,xm(["diff","--name-only",t,n],r));return o.split(`
175
- `).map(s=>s.trim()).filter(Boolean)}async function Tm(e,t,n,r){let{stdout:o}=await ze(e,xm(["diff","--binary",t,n],r));if(!o.trim())return{applied:!0,empty:!0,conflicts:[]};if((await gm(e,o,["--whitespace=nowarn"])).ok)return{applied:!0,empty:!1,conflicts:[]};let s=await gm(e,o,["--3way","--whitespace=nowarn"]),a=await W1(e);return a.length>0?{applied:!1,empty:!1,conflicts:a}:s.ok?{applied:!0,empty:!1,conflicts:[]}:(await gm(e,o,["--reject","--whitespace=nowarn"]),{applied:!1,empty:!1,conflicts:[`patch did not apply cleanly: ${s.err}`]})}async function gm(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 W1(e){try{let{stdout:t}=await ze(e,["diff","--name-only","--diff-filter=U"]);return t.split(`
176
- `).map(n=>n.trim()).filter(Boolean)}catch{return[]}}var ym,av,uu=q(()=>{ym=F1(L1),av=64*1024*1024});function du(e,{at:t=Date.now(),reason:n="node-transfer"}={}){let r=!1;for(let o of e?.boxes||[]){if(!o||typeof o!="object")continue;!q1.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 Ve,q1,An=q(()=>{Ve=e=>!!(e&&(e.archivedAt||e.transferredTo)),q1=new Set(["merged","conflict","canceled","failed","handed-off"])});import Am from"node:fs/promises";import uv from"node:path";import K1 from"node:os";function mv(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(t.getDate()-(t.getDay()+6)%7),t.getTime()}function hv(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(1),t.getTime()}function wv(e){let t=new Date(mv(e));return t.setDate(t.getDate()+7),t.getTime()}function gv(e){let t=new Date(hv(e));return t.setMonth(t.getMonth()+1),t.getTime()}function fu(e=Date.now()){for(let[t,n]of Object.entries(Ks)){let r=n.startOf(e);if(r!==Jn[t]){Jn[t]=r;for(let o of Oo.values())o[t]=0;for(let o of Gs)o.includes(`:${t}:`)&&!o.endsWith(`:${r}`)&&Gs.delete(o)}}}function yv(e,t){let n=on?.caps?.[e]?.[Ks[t].capKey];return Number.isFinite(n)&&n>0?n:null}function Co(e,t=Date.now()){if(!e||!_m||!on?.caps)return null;fu(t);let n=Oo.get(e);for(let r of Object.keys(Ks)){let o=yv(e,r);if(o==null)continue;let s=n?.[r]||0;if(s>=o)return{provider:e,window:r,limitUsd:o,spentUsd:pu(s),resetsAt:Ks[r].nextStart(t)}}return null}function bv(e,t){let n=`hit:${e}:${t.provider}:${t.window}:${Jn[t.window]}`;return Gs.has(n)?!1:(Gs.add(n),!0)}function lv(e,t,n,r=Date.now()){if(!e||!t)return;fu(r);let o=G1(e);for(let[s,a]of Object.entries(Ks))n>=Jn[s]&&n<a.nextStart(r)&&(o[s]+=t)}async function z1(e,t,n=Date.now()){if(!on?.caps||!Em)return;let r=Oo.get(e);if(r)for(let[o,s]of Object.entries(Ks)){let a=yv(e,o);if(a==null)continue;let i=r[o]||0;if(i<a*fv||i>=a)continue;let c=`warn:${e}:${o}:${Jn[o]}`;if(!Gs.has(c)){Gs.add(c);try{let l=await Em(t);if(!l)continue;await C(l,{type:"usage.cap.warning",actor:"system",provider:e,payload:{provider:e,window:o,limitUsd:a,spentUsd:pu(i),pct:Math.round(i/a*100),resetsAt:s.nextStart(n)}})}catch{}}}}function kv(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 mu(e,{source:t="local",updatedAt:n=Date.now()}={}){on={caps:kv(e),updatedAt:n,source:t};try{await Am.mkdir(dv,{recursive:!0}),await Am.writeFile(pv(),JSON.stringify(on,null,2))}catch{}return Ri()}function Ri(e=Date.now()){fu(e);let t=new Set([...Oo.keys(),...Object.keys(on?.caps||{})]),n={};for(let r of t){let o=Oo.get(r);n[r]={weeklyUsd:pu(o?.weekly||0),monthlyUsd:pu(o?.monthly||0)}}return{caps:on?.caps||{},configured:!!on,seeded:_m,updatedAt:on?.updatedAt??null,spent:n,windows:{weekly:{start:Jn.weekly,resetsAt:wv(e)},monthly:{start:Jn.monthly,resetsAt:gv(e)}},warnPct:fv}}async function xv({listTracks:e,getTrack:t}={}){Em=t||null,fu();try{let o=JSON.parse(await Am.readFile(pv(),"utf8"));on={caps:kv(o?.caps),updatedAt:o?.updatedAt??null,source:o?.source??"file"}}catch{on=null}let n=Date.now();ot.on("event",o=>{if(o?.type!=="cost.recorded")return;let{usd:s}=Wt(o);lv(o.provider||"unknown",s,o.ts??Date.now()),z1(o.provider||"unknown",o.trackId).catch(()=>{})});let r=Math.min(Jn.weekly,Jn.monthly);for(let o of await e?.()||[]){let s;try{s=await K(o)}catch{continue}for(let a of s){if(a.type!=="cost.recorded")continue;let i=a.ts??0;i<r||i>=n||lv(a.provider||"unknown",Wt(a).usd,i,n)}}return _m=!0,Ri()}var dv,pv,fv,Ks,on,_m,Jn,Oo,Gs,Em,G1,pu,hu=q(()=>{de();Pr();dv=process.env.BOSTRAT_STATE_DIR||uv.join(process.env.HOME||K1.tmpdir(),".bostrat"),pv=()=>uv.join(dv,"usage-caps.json"),fv=.8;Ks={weekly:{startOf:mv,nextStart:wv,capKey:"weeklyUsd"},monthly:{startOf:hv,nextStart:gv,capKey:"monthlyUsd"}},on=null,_m=!1,Jn={weekly:0,monthly:0},Oo=new Map,Gs=new Set,Em=null,G1=e=>{let t=Oo.get(e);return t||(t={weekly:0,monthly:0},Oo.set(e,t)),t};pu=e=>Math.round(e*1e4)/1e4});import V1 from"node:fs/promises";import J1 from"node:os";import vv from"node:path";function $v(e){return e==="codex"?Q1:e==="cursor"?Iv:Ev}function Sv(e){let t=String(e||"").split(`
155
+ [\u2026 brief truncated]`}var pD,fD,P0,mD,hD,gD,D0,B0,L0=q(()=>{Ql();pD=12,fD=2e3,P0=48e3,mD=30,hD=10;gD=(e,t)=>{let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1)}\u2026`},D0=(e,t)=>e&&t?Math.max(1,Math.round((e-t)/6e4)):null;B0={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 kD from"node:fs";import Rr from"node:fs/promises";import Or from"node:path";function z0(e){let t=go(String(e??"")),n=Buffer.byteLength(t,"utf8");return n<=F0?{content:t,bytes:n,truncated:!1}:{content:`${Buffer.from(t,"utf8").subarray(0,F0).toString("utf8").replace(/�+$/,"")}
156
+
157
+ [\u2026 truncated by bostrat at 32 KiB \u2014 full artifact in the workspace]`,bytes:n,truncated:!0}}function $D(e){let t=String(e||"").split(/\r?\n/).map(s=>s.trim()).filter(Boolean),n=[],r=[];for(let s of t)if(H0.test(s)){if(r.length>=Q0)continue;let a=ID(s.replace(H0,"").replace(/[.;,:]+$/,""),ex,ED);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>U0&&(o=`${o.slice(0,U0-1).trimEnd()}\u2026`),{text:o,items:r.length>1?r:[]}}async function tx(e,t,{timeoutMs:n=9e4}={}){let r=Or.join(t,TD),o=Or.join(r,AD);await Rr.mkdir(r,{recursive:!0});let s=await eu(o),a=await ke(e);if(!a)throw new Error(`session "${e}" not found`);return await tu(e,a,_D(o)),await cx(o,s,n),$D(await Rr.readFile(o,"utf8"))}function nx(e,t){let n=(t||"").trim();if(!n)return!1;if(e==="assistant")return n===J0||n===Z0;let r=n.replace(/^\/[a-z0-9:_-]+\s+/i,"");return r.startsWith(V0)||n===xD||r.startsWith(Y0)||r.startsWith(X0)}function rx(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-RD;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 ox(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 sx(e,{windows:t=[]}={}){if(nx(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 Wf.get(e)||null}async function ax(e){let t=Wf.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:Or.join(n.cwd,K0,G0)};return Wf.set(e,r),MD(r,n.cwd).catch(o=>{r.error=o?.message||String(o),r.finishedAt=Date.now()}),r}async function MD(e,t){e.step="summarize",await ix(e.name,t),e.step="clear";let n=await ke(e.name);await tu(e.name,n,"/clear"),await Gf(OD),e.step="resume",await tu(e.name,n,SD),e.step="done",e.finishedAt=Date.now()}async function ix(e,t,{timeoutMs:n=CD}={}){let r=Or.join(t,K0),o=Or.join(r,G0);await Rr.mkdir(r,{recursive:!0});let s=await eu(o),a=await ke(e);await le({flow:"checkpoint",phase:"summarize-start",sessionName:e,cwd:t,file:o,beforeMtime:s}),await tu(e,a,vD(o)),await cx(o,s,n),await le({flow:"checkpoint",phase:"summarize-done",sessionName:e,file:o,afterMtime:await eu(o)});let i=await h0(t,o,{exclude:u=>nx(u.role,u.text)});await le({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 Rr.readFile(o,"utf8");await C({id:c,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...z0(u),ts:Date.now()}})}catch{}}await qp(t);let l=await ND(r,o);return c&&await Jb(c,l||o,{box:e,agent:a?.agent??null}),o}async function qf(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 ix(e,n.cwd,t?{timeoutMs:t}:void 0)}async function Kf(e,t,{trackName:n="this Track"}={}){let r=await K({id:e,cwd:t}),o=j0(r,{trackName:n,now:Date.now(),mode:"in-place"});if(!o)return null;let s=Or.join(t,W0);return await Rr.mkdir(Or.dirname(s),{recursive:!0}),await Rr.writeFile(s,o,"utf8"),await C({id:e,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...z0(o),reconstructed:!0,ts:Date.now()}}).catch(()=>{}),W0}async function eu(e){try{return(await Rr.stat(e)).mtimeMs}catch{return 0}}async function cx(e,t,n){let r=Date.now()+n;for(;;){if(await eu(e)>t)return;if(Date.now()>r)throw new Error(`timed out waiting for the handoff file to be written (${e})`);await Gf(2e3)}}async function ND(e,t){try{if(!kD.existsSync(t))return null;let n=new Date().toISOString().replace(/[:.]/g,"-"),r=Or.join(e,`${n}.md`);return await Rr.copyFile(t,r),r}catch{return null}}function Gf(e){return new Promise(t=>setTimeout(t,e))}function q0(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 tu(e,t,n){if(t){let o=q0(t.agent);await $r({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 Ke(e,["Escape"],{kind:"drive-wipe"}),await Gf(150),await As(e,Pl,{kind:"drive-wipe"}),await nt(e,n,{kind:"orchestration-drive",...vn(r.agent,n)}),await ki({sessionName:e,agent:r.agent,agentCmd:q0(r.agent),text:n,flow:"orchestration-drive"})}var K0,G0,F0,V0,J0,Y0,xD,vD,SD,X0,Z0,TD,AD,U0,Q0,ex,ED,_D,H0,ID,RD,OD,CD,Wf,W0,zf=q(()=>{ct();hi();kn();wi();Of();w0();Va();de();El();L0();K0=".bostrat/handoff",G0="latest.md",F0=32*1024;V0="Checkpoint: write a work-in-progress handoff",J0="HANDOFF WRITTEN",Y0="Resume from .bostrat/handoff/latest.md",xD="/clear",vD=e=>`${V0} 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 ${J0} and take no further action.`,SD=`${Y0}: read it, restate the Objective and the single next step in one line, then continue the work from 'Next steps'.`,X0="Beat: write a",Z0="BEAT WRITTEN",TD=".bostrat/arc",AD="beat.txt",U0=200,Q0=4,ex=5,ED=36,_D=e=>`${X0} 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 ${Q0} further lines, each starting with "- " and naming ONE piece in at most ${ex} 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 ${Z0} and take no further action.`,H0=/^(?:[-–—*•·]|\d+[.)])\s+/,ID=(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};RD=6e5;OD=3500,CD=3e5,Wf=new Map;W0=".bostrat/handoff/status-latest.md"});function Mr(e,t,n){if(e==null)return t==="from"?-1/0:1/0;if(!ru.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 dx(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:Mr(o.from,"from",n),toMs:Mr(o.to,"to",n)}))}return t}function Jf(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 DD(e){if(!e)return null;let t=String(e).trim();return Cr[t]?t:lx[t]?lx[t]:Object.keys(Cr).find(r=>t.startsWith(r))||null}function BD(e){if(!e||e===Cr)return PD;let t=ux.get(e);return t||(t=dx(e),ux.set(e,t)),t}function px(e,t,n={}){let{table:r,speed:o}=n,s=BD(r),a=r&&r!==Cr?s[e]?e:null:DD(e);if(!a)return null;let i=Jf(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 Tn(e,t={},n,r){let o=px(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 jD(e=Cr){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:Mr(a.from,"from",n),toMs:Mr(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`),ru.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 FD({now:e=Date.now(),table:t=Cr,...n}={}){let{staleDays:r,leadDays:o,confirmDays:s}={...LD,...n},a=[],i=Jf(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:Mr(d.from,"from",c),toMs:Mr(d.to,"to",c),verifiedMs:ru.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*Vf;p&&i-d.verifiedMs>r*Vf&&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*Vf&&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 Ps({now:e=Date.now(),table:t=Cr,...n}={}){let r=Jf(e)??Date.now(),o=null,s=[];for(let[i,c]of Object.entries(t))for(let l of c){let u=Mr(l.from,"from",i),d=Mr(l.to,"to",i);r>=u&&r<=d&&ru.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=[...jD(t),...FD({now:r,table:t,...n})];return{tableVerifiedAt:o,upcomingChanges:s,problems:a,ok:a.length===0}}var Cr,lx,ru,PD,ux,fx,LD,Vf,Vn=q(()=>{Cr={"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)."}]},lx={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"},ru=/^\d{4}-\d{2}-\d{2}$/;PD=dx(Cr);ux=new WeakMap;fx=(e,t,n)=>px(e,t,n)!==null;LD=Object.freeze({staleDays:90,leadDays:14,confirmDays:30}),Vf=864e5});function UD(e){return e?{input:e.input||0,output:e.output||0,cacheRead:e.cacheRead||0,cacheWrite:e.cacheWrite??e.cacheCreation??0}:null}function hx(e,t){t&&(e.input+=t.input,e.output+=t.output,e.cacheRead+=t.cacheRead,e.cacheCreation+=t.cacheWrite)}function Wt(e){let t=e.payload?.model||"unknown",n=UD(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=Tn(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&&!fx(t,e.ts,o?{speed:o}:void 0);return{usd:a,model:t,tokens:n,repriced:i,unpriced:l,asRecorded:r}}function Nr(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=mx();for(let p of n){let{usd:f,model:w,tokens:m,repriced:g,unpriced:b,asRecorded:x}=Wt(p);i+=x;let y=p.provider||"unknown",$=p.boxId||"unattributed";if(g&&c++,b&&(l++,u.add(w)),a+=f,hx(d,m),r[w]||={usd:0,tokens:mx(),events:0},r[w].usd+=f,r[w].events+=1,hx(r[w].tokens,m),o[y]||={usd:0,events:0},o[y].usd+=f,o[y].events+=1,s[$]||={usd:0,events:0,provider:y,models:new Set,label:t[$]||$},s[$].usd+=f,s[$].events+=1,w!=="unknown"&&s[$].models.add(w),p.epoch!=null){let O=(s[$].epochs||={})[p.epoch]||={usd:0,events:0,provider:y,models:new Set};O.usd+=f,O.events+=1,O.provider=y,w!=="unknown"&&O.models.add(w)}}return{totalUsd:Ds(a),asRecordedUsd:Ds(i),totalTokens:d,turns:n.length,repricedTurns:c,unpricedTurns:l,unpricedModels:[...u],byModel:ou(r,p=>({...p,usd:Ds(p.usd)})),byProvider:ou(o,p=>({...p,usd:Ds(p.usd)})),byBox:ou(s,p=>({usd:Ds(p.usd),events:p.events,provider:p.provider,label:p.label,models:[...p.models],...p.epochs?{epochs:ou(p.epochs,f=>({usd:Ds(f.usd),events:f.events,provider:f.provider,models:[...f.models]}))}:{}}))}}var mx,Ds,ou,Pr=q(()=>{Vn();mx=()=>({input:0,output:0,cacheRead:0,cacheCreation:0});Ds=e=>Math.round(e*1e4)/1e4,ou=(e,t)=>Object.fromEntries(Object.entries(e).map(([n,r])=>[n,t(r)]))});function HD(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 wx(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(Yf(s,"PR")+" opened");let a=Object.keys(e?.subtasks||{}).length||r.filter(u=>u.type==="subtask-delegated").length;a&&n.push(Yf(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(`${Yf(i.length,"handoff")} ${u}${i.length>3?"\u2026":""}`)}let c=Nr(t);c.totalUsd>=.01&&n.push(`$${c.totalUsd.toFixed(2)}`);let l=Number.isFinite(e?.archivedAt)&&Number.isFinite(e?.createdAt)?HD(e.archivedAt-e.createdAt):null;return n.length&&l&&n.push(l),n.length?n.join(" \xB7 "):null}var Yf,gx=q(()=>{Pr();Yf=(e,t)=>`${e} ${t}${e===1?"":"s"}`});import{execFile as WD}from"node:child_process";import{promisify as qD}from"node:util";import{randomUUID as KD}from"node:crypto";async function Xf(e,t){let n=Date.now()+t;for(;;){if(await Kn(e))return!0;if(Date.now()>n)return!1;await Ei(zD)}}async function JD(e,t){let n=bx[t]||bx.default;n.escape&&(await Ke(e,["Escape"],{kind:"swap-exit"}),await Ei(150)),n.wipe&&await As(e,Pl,{kind:"swap-exit"}),await Dl(e,n.text,{perCharDelayMs:90,kind:"swap-exit"});let r=vn(t).submitDelayMs||0;await Ei(Math.max(r,250)),await Ke(e,["Enter"],{kind:"swap-exit"})}async function kx(e,t){try{let{stdout:n}=await To(X,Z("show-environment","-t",e,t));return!String(n||"").trimStart().startsWith("-")}catch{return!1}}async function xx(e){await To(X,Z("respawn-pane","-k","-t",e))}async function Zf(e,t={}){if(!je(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||Ar(n),a=Number(t.exitTimeoutMs)||GD;await le({flow:"swap",phase:"start",sessionName:e,from:o,to:s,cwd:r.cwd});let i=!1;if(!await Kn(e)&&(await JD(e,o),!await Xf(e,a)&&(i=!0,await le({flow:"swap",phase:"respawn-forced",sessionName:e,from:o}),await xx(e),!await Xf(e,yx))))throw new Error(`pane shell did not come back after respawn-pane in "${e}"`);let c=s==="claude"&&yo(n),l=c?al():null,u=await kx(e,"ANTHROPIC_API_KEY"),d=!1;try{l?(await To(X,Z("set-environment","-t",e,"ANTHROPIC_API_KEY",l)),d=!0):u&&(await To(X,Z("set-environment","-u","-t",e,"ANTHROPIC_API_KEY")),d=!0)}catch(g){throw l?$l(g,l):g}if(d&&!i&&(await xx(e),!await Xf(e,yx)))throw new Error(`pane shell did not come back after env respawn in "${e}"`);let p=!!t.resumeSessionId,f=t.resumeSessionId||KD(),w=p?n:oi(n,f,e),m=p?t.pinned===!0:/(^|\s)--session-id(\s|=)/.test(w);return c&&await yr(r.cwd),s==="codex"&&await ps(r.cwd),s==="cursor"&&await fs(r.cwd),await bo(e),await To(X,Z("set-option","-t",e,"@bostrat-sid",f)),await To(X,Z("set-option","-t",e,"@bostrat-agent",s)),await Ei(VD),c&&ri().length&&(await kx(e,ni)||await To(X,Z("set-environment","-t",e,ni,"1")).catch(()=>{}),await nt(e,`export ${ni}=1`,{kind:"swap-env"}),await Ei(150)),await nt(e,w,{kind:"swap-launch"}),await le({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 To,Ei,GD,yx,zD,VD,bx,vx=q(()=>{ct();Ua();cl();ll();wi();kn();To=qD(WD),Ei=e=>new Promise(t=>setTimeout(t,e)),GD=Number(process.env.BOSTRAT_SWAP_EXIT_TIMEOUT_MS)||15e3,yx=Number(process.env.BOSTRAT_SWAP_SHELL_TIMEOUT_MS)||8e3,zD=250,VD=400,bx={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 e1(e){if(e.type==="queue-operation"&&e.operation==="enqueue")return Sx.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"&&Sx.test(t)?t:null}async function Tx(e,t={}){return(await Ex(e,t)).launches}async function Ax(e,t={}){let{launches:n,done:r}=await Ex(e,t);return n.filter(o=>!r.has(o.id))}async function Ex(e,{maxBytes:t=2097152,limit:n=100}={}){let r;try{r=await _t(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(`
158
+ `)){let u=l.trim();if(!u||u[0]!=="{")continue;let d;try{d=JSON.parse(u)}catch{continue}if(d.isSidechain)continue;let p=e1(d);if(p){let m=p.match(QD)?.[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(),b={id:m.id,kind:"command",name:String(m.input?.description||"").trim()||(g?$s(g):null),detail:g?$s(g):null,ts:w,proven:m.input?.run_in_background===!0};b.proven?o.set(m.id,b):i.set(m.id,b)}}else if(m.type==="tool_result"&&m.tool_use_id){let g=t1(m.content);if(YD.test(g)&&s.add(m.tool_use_id),g.match(XD)){let x=i.get(m.tool_use_id);x&&(i.delete(m.tool_use_id),x.proven=!0,x.outputFile=g.match(ZD)?.[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 YD,XD,ZD,Sx,QD,t1,_x=q(()=>{nn();Rs();YD=/^Async (?:agent|task) launched/i,XD=/^Command did not complete within its [^\n]*?moved to the background \(ID: ([^)]+)\)/i,ZD=/Output is being written to:\s*(\S+)/i,Sx=/^\s*<task-notification>/i,QD=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i;t1=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 Dr(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 n1(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 Ix(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:rn(`read ${Dr(r,n)}${o?` (lines ${o}\u2013${s??"end"})`:""}`,140),description:o?`Read lines ${o}\u2013${s??"end"} of ${Bs(r)}`:`Read ${Bs(r)}`}}case"Grep":{let r=t?.pattern;if(!r)return null;let o=t?.path?Dr(t.path,n):null,s=t?.glob?` --glob ${Qf(t.glob)}`:"",a=rn(String(r),40);return{command:rn(`grep ${Qf(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?Dr(t.target_directory,n):null;return{command:rn(`glob ${Qf(r)}${o&&o!=="."?` ${o}`:""}`,140),description:`Find files matching \u201C${rn(String(r),40)}\u201D`}}case"StrReplace":return t?.path?{command:rn(`edit ${Dr(t.path,n)}`,140),description:`Edit ${Bs(t.path)}`}:null;case"Write":return t?.path?{command:rn(`write ${Dr(t.path,n)}`,140),description:`Write ${Bs(t.path)}`}:null;case"Delete":return t?.path?{command:rn(`delete ${Dr(t.path,n)}`,140),description:`Delete ${Bs(t.path)}`}:null;case"ReadLints":{let o=(Array.isArray(t?.paths)?t.paths:[]).map(s=>Dr(s,n)).filter(Boolean);return{command:rn(o.length?`lints ${o.join(" ")}`:"lints",140),description:"Check lints"}}case"ApplyPatch":{let r=n1(t);if(!r.length)return null;let o=r.length>1?` (+${r.length-1} more)`:"";return{command:rn(`apply_patch ${Dr(r[0],n)}${o}`,140),description:r.length>1?`Patch ${r.length} files`:`Patch ${Bs(r[0])}`}}case"Await":{let r=t?.shell_id??t?.task_id;return{command:rn(`await ${r??"background output"}`,140),description:"Wait for a background command"}}default:return null}}var su,rn,Bs,Qf,$x=q(()=>{su=new Set(["Shell","Read","Grep","Glob","StrReplace","Write","ReadLints","Delete","ApplyPatch","Await"]),rn=(e,t=88)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,Bs=e=>String(e).replace(/\/+$/,"").split("/").pop()||String(e);Qf=e=>`"${String(e).replace(/"/g,'\\"')}"`});import _i from"node:fs";import r1 from"node:fs/promises";import Ao from"node:path";import o1 from"node:os";import s1 from"node:crypto";import a1 from"node:zlib";function Cx(e){let t=s1.createHash("md5").update(String(e)).digest("hex");return Ao.join(i1,t)}function Mx(e){try{let t=JSON.parse(_i.readFileSync(Ao.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 c1(e){let t=Cx(e),n;try{n=_i.readdirSync(t,{withFileTypes:!0}).filter(o=>o.isDirectory())}catch{return null}let r=null;for(let o of n){let s=Ao.join(t,o.name),a=Ao.join(s,"store.db");if(!_i.existsSync(a))continue;let i=Mx(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 au(e,t){if(!e)return null;if(t){let n=Ao.join(Cx(e),t),r=Ao.join(n,"store.db");if(_i.existsSync(r))return{id:t,dir:n,store:r,...Mx(n)||{createdAtMs:null,updatedAtMs:null}}}return c1(e)}function Rx(e,t){let n=e.prepare("SELECT data FROM blobs WHERE id = ?").get(t);return n?Buffer.from(n.data):null}function l1(e){if(!e)return null;let t=e;if(t.length>1&&t[0]===31&&t[1]===139)try{t=a1.gunzipSync(t)}catch{}try{return JSON.parse(t.toString("utf8"))}catch{return null}}function u1(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 d1(e,t){if(!Array.isArray(e))return[];let n=[];for(let r of e){if(!r||r.type!=="tool-call"||!su.has(r.toolName))continue;let o=Ix(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 em(e,t){if(!Ox)return js;let{DatabaseSync:n}=Ox,r;try{r=new n(e,{readOnly:!0})}catch{return js}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 js;let s;try{s=JSON.parse(Buffer.from(String(o.value),"hex").toString("utf8"))}catch{return js}let a=s.lastUsedModel||null,i=s.latestRootBlobId?Rx(r,s.latestRootBlobId):null;if(!i)return{...js,model:a};let c=[],l=[],u=[],d=null,p=[];for(let f of u1(i)){let w=l1(Rx(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 y=x?.providerOptions?.cursor?.modelName;y&&(d=y)}l.push(...d1(w.content,t).map((x,y)=>({...x,id:x.id||`${f}:${y}`}))),u.push(...f1(w.content));let g=p1(w.content);if(!g)continue;let b=[...new Set(u)];u=[],c.push({id:f,text:g,tools:b.length?b:void 0,commands:l,model:d}),l=[]}return{turns:c,trailingCommands:l,model:a,requestIds:p}}catch{return js}finally{try{r.close()}catch{}}}function Nx(e,t){let n=e.updatedAtMs;if(!n)try{n=Math.round(_i.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 Px(e,t,{limit:n=80}={}){let r=au(e,t);if(!r)return[];let{turns:o,model:s}=await em(r.store,e);if(!o.length)return[];let a=o.slice(-n),{tsAt:i}=Nx(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 Dx(e,t){let n=au(e,t);if(!n)return null;let{turns:r,requestIds:o,model:s}=await em(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 Bx(e,t,{limit:n=80}={}){let r=au(e,t);if(!r)return[];let{turns:o,trailingCommands:s}=await em(r.store,e);if(!o.length&&!s.length)return[];let a=o.slice(-n),{end:i,tsAt:c}=Nx(r,a.length||1),l=[];a.forEach((u,d)=>{for(let p of u.commands)l.push({...p,summary:Ir(p.command,p.description),ts:c(d)})});for(let u of s)l.push({...u,summary:Ir(u.command,u.description),ts:i+1});return l}async function jx(e,t){let n=au(e,t);if(!n)return null;if(n.updatedAtMs)return n.updatedAtMs;try{return Math.round((await r1.stat(n.store)).mtimeMs)}catch{return null}}var i1,p1,f1,Ox,js,tm=q(()=>{Rs();$x();i1=process.env.BOSTRAT_CURSOR_CHATS||Ao.join(o1.homedir(),".cursor","chats");p1=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(`
159
+ `).trim():"",f1=e=>Array.isArray(e)?e.filter(t=>t&&t.type==="tool-call"&&t.toolName).map(t=>t.toolName):[],Ox=process.getBuiltinModule?.("node:sqlite"),js={turns:[],trailingCommands:[],model:null,requestIds:[]}});import m1 from"node:fs/promises";function sm(e){return Lx.set(e.agent,e),e}function Br(e){return Lx.get(e)||h1}async function am(e,t={}){return(await Br(e.agent).readMessages(e,t)).map(iu(e))}async function Fx(e,t={}){return(await Br(e.agent).readCommands(e,t)).map(iu(e))}async function Ux(e,t={}){return(await Br(e.agent).readJobs(e,t)).map(iu(e))}async function Hx(e,t={}){return(await Br(e.agent).readOpenJobs(e,t)).map(iu(e))}var Ls,nm,rm,om,h1,Lx,iu,im=q(()=>{nn();Ll();Rs();_x();tm();vo();Ls=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}},nm=class extends Ls{transcript(t){return!t?.cwd||!t?.sessionId?null:tn(t.cwd,t.sessionId)}async readMessages(t,n){let r=this.transcript(t);return r?yf(r,n):[]}async readCommands(t,n){let r=this.transcript(t);return r?_k(r,n):[]}async readJobs(t,n){let r=this.transcript(t);return r?Tx(r,n):[]}async readOpenJobs(t,n){let r=this.transcript(t);return r?Ax(r,n):[]}async updatedAt(t){let n=this.transcript(t);if(!n)return null;try{return Math.round((await m1.stat(n)).mtimeMs)}catch{return null}}},rm=class extends Ls{async readMessages(t,n){return Px(t.cwd,t.sessionId,n)}async readCommands(t,n){return Bx(t.cwd,t.sessionId,n)}async updatedAt(t){return jx(t.cwd,t.sessionId)}},om=class extends Ls{sessionId(t){return t?.pinned?t.sessionId:null}async readMessages(t,n){return Ok(t.cwd,this.sessionId(t),n)}async readCommands(t,n){return Ck(t.cwd,this.sessionId(t),n)}async updatedAt(t){return Mk(t.cwd,this.sessionId(t))}},h1=new Ls("unknown"),Lx=new Map;sm(new nm("claude",ff));sm(new rm("cursor",su));sm(new om("codex",di));iu=e=>t=>({...t,box:e.name,agent:e.agent,boxRole:e.role})});function Io(e){let t=e.search(dm);return(t>=0?e.slice(0,t):e).trim()}function w1(e){if(!e)return"";let t=e.replace(/[│┌└├─┘┤┬┴┼─✂].*$/,"").trim();return!t||/hidden|\d+\s+lines?/i.test(t)?"":t}function g1(e){let t=String(e).trim();return!!(!t||_o.test(e)||dm.test(t)||/hidden|\d+\s+lines?/i.test(t)||/notespress|press n to add/i.test(t)||/^\s*notes?\s*$/i.test(t))}function y1(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=b1(n,t);return n.forEach((a,i)=>{a.current=i===s}),{tabs:n,questionIndex:s,questionTotal:n.length,currentTabLabel:n[s].label}}function b1(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 qx(e){return e.replace(/[←→✔☐☒●▶]/g," ").replace(/\bSubmit\b/g," ").replace(/\s+/g," ").trim()}function k1(e,t=""){let n=String(e);if(!Gx.test(n))return null;let r=n.replace(/\r/g,"").split(`
160
+ `),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(Eo);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&&!_o.test(r[u])&&a.push(p)}}if(s.length<2)return null;let i=s.map(u=>({label:Io(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 v1(e,t=""){let n=String(e).replace(/\r/g,"").split(`
161
+ `),r=n.length-1;for(;r>=0&&n[r].trim()==="";)r--;if(r<0||!zx.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(Eo);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&&!(x1.test(n[c])||_o.test(n[c]));c--){let l=n[c].trim();l&&a.unshift(l)}let i=s.map(c=>({label:Io(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 S1(e,t=""){let n=String(e);if(!/ready to submit your answers/i.test(n))return null;let r=n.replace(/\r/g,"").split(`
162
+ `),o=[];for(let c=0;c<r.length;c++){let l=r[c].match(Eo);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 A1(e,t=""){let n=String(e);if(!cm.test(n))return null;let r=n.replace(/\r/g,"").split(`
163
+ `),o=-1;for(let u=r.length-1;u>=0;u--)if(T1.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(Eo);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&&!_o.test(r[u])&&a.push(p)}}if(s.length<2||!s.some(u=>cm.test(u.label)))return null;let i=s.map(u=>({label:Io(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 pm(e){let t=[];for(let r=0;r<e.length;r++){let o=e[r].match(Eo);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 E1(e,t=""){let n=String(e);if(!Vx.test(n)||!Jx.test(n)||$o.test(n))return null;let r=n.replace(/\r/g,"").split(`
164
+ `),o=pm(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:Io(s.label),description:""}))}]}:null}function _1(e,t=""){let n=String(e);if(!Yx.test(n)||$o.test(n))return null;let r=n.replace(/\r/g,"").split(`
165
+ `),o=pm(r);if(!o)return null;let s=o.map(a=>{let[i,...c]=a.label.split("\xB7");return{label:Io(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 $1(e,t){let n=e[t].trim();for(let r=t+1;r<e.length;r++){let o=e[r].trim();if(!o||!I1.test(o)||fm.test(e[r]))break;n+=o}return n}function R1(e,t=""){let n=String(e);if(!fm.test(n)||$o.test(n))return null;let r=n.replace(/\r/g,"").split(`
166
+ `),o="";for(let s=0;s<r.length;s++)if(/^\s*https:\/\//.test(r[s])){o=$1(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 C1(e,t=""){let n=String(e);if(!lm.test(n)||!O1.test(n)||$o.test(n))return null;let s=([...n.replace(/\r/g,"").split(`
167
+ `)].reverse().find(a=>lm.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 M1(e,t=""){let n=String(e);if(!Xx.test(n)||$o.test(n))return null;let r=n.replace(/\r/g,"").split(`
168
+ `),o=pm(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:Io(s.label),description:""}))}]}:null}function N1(e,t=""){let n=String(e);if($o.test(n))return null;let r=n.replace(/\r/g,"").split(`
169
+ `),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(Zx);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(_o.test(r[l])||dm.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 P1(e){let t=-1;for(let r=e.length-1;r>=0;r--)if(um.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 D1(e,t=""){let n=String(e);if(!Kx.test(n)||!um.test(n))return null;let r=n.replace(/\r/g,"").split(`
170
+ `),o=P1(r);if(!o)return null;let{headerLine:s,chatLine:a,optStart:i,optEnd:c}=o,l=[],u=-1;for(let P=i;P<c;P++){let E=r[P].match(Eo);E&&(u<0&&(u=P),l.push({line:P,cursor:!!E[1],checked:E[3]!=null&&E[3]!==" ",hasCheckbox:E[3]!=null,label:E[4].trim(),desc:""}))}if(!l.length)return null;for(let P of l)for(let E=P.line+1;E<Math.min(r.length,P.line+4)&&!(Eo.test(r[E])||_o.test(r[E]));E++){let R=r[E].trim();if(!(!R||g1(r[E])||Wx.test(R))){P.desc=w1(R);break}}let d=l.filter(P=>!Wx.test(P.label));if(!d.length)return null;let p=d.some(P=>P.hasCheckbox),f=Math.max(0,d.findIndex(P=>P.cursor)),w=s>=0?s+1:0,m=[];for(let P=w;P<u;P++){let E=r[P].trim();E&&!_o.test(r[P])&&!/[☐☒]/.test(r[P])&&m.push(E)}let g=m.join(" ")||(s>=0?qx(r[s]):"")||"The agent is asking a question",b=s>=0?y1(r[s],g):null,x=b?.currentTabLabel||(s>=0?qx(r[s]):""),y=d.map(P=>({label:Io(P.label),description:P.desc})),$=y.map(P=>P.label).join("|"),M=`claude:${b?`q${b.questionIndex+1}/${b.questionTotal}`:"q1/1"}:${x}:${g}:${$}`.slice(0,240),H=b?`claude:ask:${b.tabs.map(P=>P.label).join("|")}`.slice(0,240):M;return{provider:"claude",box:t,multiSelect:p,cursorIndex:f,promptId:M,groupId:H,...b?{questionIndex:b.questionIndex,questionTotal:b.questionTotal,currentTabLabel:b.currentTabLabel,tabs:b.tabs}:{},questions:[{question:g,header:x,multiSelect:p,options:y}]}}function Ro(e,t){let n=String(t||"");return n?e==="claude"?Kx.test(n)&&um.test(n)||Gx.test(n)||cm.test(n)||zx.test(n.trimEnd().split(`
171
+ `).pop()||"")?!0:$o.test(n)?!1:Vx.test(n)&&Jx.test(n)||Yx.test(n)||fm.test(n)||lm.test(n)||Xx.test(n)||Zx.test(n.trimEnd().split(`
172
+ `).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 jr(e,t){return!e||!t?null:e.agent==="claude"?S1(t,e.name)||D1(t,e.name)||k1(t,e.name)||A1(t,e.name)||C1(t,e.name)||R1(t,e.name)||_1(t,e.name)||E1(t,e.name)||M1(t,e.name)||N1(t,e.name)||v1(t,e.name):e.agent==="cursor"||e.agent==="codex"?Vk(e.agent,t,e.name):null}async function mm(e){if(!e)return null;let t=await Gn(e.name).catch(()=>"");return jr(e,t)}function Qx(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 ev(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 Kx,um,Eo,Wx,_o,dm,Gx,zx,x1,cm,T1,$o,Vx,Jx,Yx,fm,I1,lm,O1,Xx,Zx,hm=q(()=>{ct();Ul();Kx=/to navigate\b.*\bEsc to cancel|Enter to select\b/,um=/Chat about this/i,Eo=/^\s*(❯)?\s*(\d+)\.\s+(?:\[([ xX✔])\]\s+)?(.+?)\s*$/,Wx=/^(type something|chat about this|submit)\b/i,_o=/^[─—-]{6,}\s*$/,dm=/[\u2500-\u257F\u2550-\u256F┌┐└┘├┤│┬┴┼─✂]/;Gx=/^\s*Switch model\?\s*$/m;zx=/^\s*Enter to confirm\s*·\s*Esc to cancel\s*$/,x1=/^\s*[─—▔-]{6,}\s*$/;cm=/Resume from summary/i,T1=/^\s*This session is\b/;$o=/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/;Vx=/Choose the text style that looks best with your terminal/,Jx=/Let's get started\./;Yx=/Select login method:/;fm=/Paste code here if prompted/,I1=/^[A-Za-z0-9%&=+._~#?/:\-]+$/;lm=/OAuth error:/,O1=/Press Enter to retry\./;Xx=/Quick safety check: Is this a project you created or one you trust/;Zx=/^(.{0,60}?)Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/});function cu(e,t,n){if(!e||!t)return null;for(let r of B1)if(r.provider===e.agent)try{if(r.match(t,n))return r}catch{}return null}function L1(e){let t=wm.get(e);return t||(t={sentAt:[],last:0,emitted:new Set},wm.set(e,t)),t}function rv(e,t,n=Date.now()){let r=L1(e);if(r.sentAt=r.sentAt.filter(s=>n-s<nv),r.sentAt.length>=tv)return{action:"give-up"};if(n-r.last<j1)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 ov(e,t=Date.now()){let n=wm.get(e);return n?n.sentAt.filter(r=>t-r<nv).length>=tv:!1}var B1,j1,tv,nv,wm,gm=q(()=>{B1=[{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||""}
173
+ ${String(t||"")}`;return/Try the new fullscreen renderer|Flicker-free output/i.test(o)},keys:["Escape"]}];j1=5e3,tv=5,nv=3600*1e3,wm=new Map});function Fs(e){return typeof e=="string"?e.trim():""}var sv=q(()=>{});import{execFile as F1}from"node:child_process";import{promisify as U1}from"node:util";async function ze(e,t,{input:n}={}){let r=bm("git",["-C",e,...t],{maxBuffer:av});return n!==void 0&&r.child.stdin&&(r.child.stdin.on("error",()=>{}),r.child.stdin.end(n)),r}async function Us(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 iv(e){let{stdout:t}=await ze(e,["rev-parse","--show-toplevel"]);return t.trim()}async function H1(e){try{return await ze(e,["rev-parse","--verify","HEAD"]),!0}catch{return!1}}async function Hs(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)=>bm("git",["-C",e,...a],{maxBuffer:av,env:o,...i});try{let a=await H1(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 bm("rm",["-f",r])}catch{}}}async function km(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 Ii(e,{ignorePlumbing:t=!1}={}){let{stdout:n}=await ze(e,["status","--porcelain"]),r=n.split(`
174
+ `).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 $i(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 Ws(e,t,n,r){return await ze(e,["worktree","add","--no-track","-b",n,t,r]),t}async function cv(e,t){try{return await ze(e,["rev-parse","--verify","--quiet",`refs/heads/${t}`]),!0}catch{return!1}}async function lu(e,t,n){return await ze(e,["worktree","add","--end-of-options",t,n]),t}async function qs(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 xm(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 Ot(e,t){try{await ze(e,["worktree","remove","--force",t])}catch{try{await ze(e,["worktree","prune"])}catch{}}}function W1(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 vm(e,t){return!t||!t.length?e:[...e,"--",".",...t.map(n=>`:(exclude)${n}`)]}async function Sm(e,t,n,r){let{stdout:o}=await ze(e,vm(["diff","--shortstat",t,n],r));return W1(o)}async function Tm(e,t,n,r){let{stdout:o}=await ze(e,vm(["diff","--name-only",t,n],r));return o.split(`
175
+ `).map(s=>s.trim()).filter(Boolean)}async function Am(e,t,n,r){let{stdout:o}=await ze(e,vm(["diff","--binary",t,n],r));if(!o.trim())return{applied:!0,empty:!0,conflicts:[]};if((await ym(e,o,["--whitespace=nowarn"])).ok)return{applied:!0,empty:!1,conflicts:[]};let s=await ym(e,o,["--3way","--whitespace=nowarn"]),a=await q1(e);return a.length>0?{applied:!1,empty:!1,conflicts:a}:s.ok?{applied:!0,empty:!1,conflicts:[]}:(await ym(e,o,["--reject","--whitespace=nowarn"]),{applied:!1,empty:!1,conflicts:[`patch did not apply cleanly: ${s.err}`]})}async function ym(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 q1(e){try{let{stdout:t}=await ze(e,["diff","--name-only","--diff-filter=U"]);return t.split(`
176
+ `).map(n=>n.trim()).filter(Boolean)}catch{return[]}}var bm,av,uu=q(()=>{bm=U1(F1),av=64*1024*1024});function du(e,{at:t=Date.now(),reason:n="node-transfer"}={}){let r=!1;for(let o of e?.boxes||[]){if(!o||typeof o!="object")continue;!K1.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 Ve,K1,An=q(()=>{Ve=e=>!!(e&&(e.archivedAt||e.transferredTo)),K1=new Set(["merged","conflict","canceled","failed","handed-off"])});import Em from"node:fs/promises";import uv from"node:path";import G1 from"node:os";function mv(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(t.getDate()-(t.getDay()+6)%7),t.getTime()}function hv(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(1),t.getTime()}function wv(e){let t=new Date(mv(e));return t.setDate(t.getDate()+7),t.getTime()}function gv(e){let t=new Date(hv(e));return t.setMonth(t.getMonth()+1),t.getTime()}function fu(e=Date.now()){for(let[t,n]of Object.entries(Ks)){let r=n.startOf(e);if(r!==Jn[t]){Jn[t]=r;for(let o of Oo.values())o[t]=0;for(let o of Gs)o.includes(`:${t}:`)&&!o.endsWith(`:${r}`)&&Gs.delete(o)}}}function yv(e,t){let n=on?.caps?.[e]?.[Ks[t].capKey];return Number.isFinite(n)&&n>0?n:null}function Co(e,t=Date.now()){if(!e||!Im||!on?.caps)return null;fu(t);let n=Oo.get(e);for(let r of Object.keys(Ks)){let o=yv(e,r);if(o==null)continue;let s=n?.[r]||0;if(s>=o)return{provider:e,window:r,limitUsd:o,spentUsd:pu(s),resetsAt:Ks[r].nextStart(t)}}return null}function bv(e,t){let n=`hit:${e}:${t.provider}:${t.window}:${Jn[t.window]}`;return Gs.has(n)?!1:(Gs.add(n),!0)}function lv(e,t,n,r=Date.now()){if(!e||!t)return;fu(r);let o=z1(e);for(let[s,a]of Object.entries(Ks))n>=Jn[s]&&n<a.nextStart(r)&&(o[s]+=t)}async function V1(e,t,n=Date.now()){if(!on?.caps||!_m)return;let r=Oo.get(e);if(r)for(let[o,s]of Object.entries(Ks)){let a=yv(e,o);if(a==null)continue;let i=r[o]||0;if(i<a*fv||i>=a)continue;let c=`warn:${e}:${o}:${Jn[o]}`;if(!Gs.has(c)){Gs.add(c);try{let l=await _m(t);if(!l)continue;await C(l,{type:"usage.cap.warning",actor:"system",provider:e,payload:{provider:e,window:o,limitUsd:a,spentUsd:pu(i),pct:Math.round(i/a*100),resetsAt:s.nextStart(n)}})}catch{}}}}function kv(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 mu(e,{source:t="local",updatedAt:n=Date.now()}={}){on={caps:kv(e),updatedAt:n,source:t};try{await Em.mkdir(dv,{recursive:!0}),await Em.writeFile(pv(),JSON.stringify(on,null,2))}catch{}return Ri()}function Ri(e=Date.now()){fu(e);let t=new Set([...Oo.keys(),...Object.keys(on?.caps||{})]),n={};for(let r of t){let o=Oo.get(r);n[r]={weeklyUsd:pu(o?.weekly||0),monthlyUsd:pu(o?.monthly||0)}}return{caps:on?.caps||{},configured:!!on,seeded:Im,updatedAt:on?.updatedAt??null,spent:n,windows:{weekly:{start:Jn.weekly,resetsAt:wv(e)},monthly:{start:Jn.monthly,resetsAt:gv(e)}},warnPct:fv}}async function xv({listTracks:e,getTrack:t}={}){_m=t||null,fu();try{let o=JSON.parse(await Em.readFile(pv(),"utf8"));on={caps:kv(o?.caps),updatedAt:o?.updatedAt??null,source:o?.source??"file"}}catch{on=null}let n=Date.now();ot.on("event",o=>{if(o?.type!=="cost.recorded")return;let{usd:s}=Wt(o);lv(o.provider||"unknown",s,o.ts??Date.now()),V1(o.provider||"unknown",o.trackId).catch(()=>{})});let r=Math.min(Jn.weekly,Jn.monthly);for(let o of await e?.()||[]){let s;try{s=await K(o)}catch{continue}for(let a of s){if(a.type!=="cost.recorded")continue;let i=a.ts??0;i<r||i>=n||lv(a.provider||"unknown",Wt(a).usd,i,n)}}return Im=!0,Ri()}var dv,pv,fv,Ks,on,Im,Jn,Oo,Gs,_m,z1,pu,hu=q(()=>{de();Pr();dv=process.env.BOSTRAT_STATE_DIR||uv.join(process.env.HOME||G1.tmpdir(),".bostrat"),pv=()=>uv.join(dv,"usage-caps.json"),fv=.8;Ks={weekly:{startOf:mv,nextStart:wv,capKey:"weeklyUsd"},monthly:{startOf:hv,nextStart:gv,capKey:"monthlyUsd"}},on=null,Im=!1,Jn={weekly:0,monthly:0},Oo=new Map,Gs=new Set,_m=null,z1=e=>{let t=Oo.get(e);return t||(t={weekly:0,monthly:0},Oo.set(e,t)),t};pu=e=>Math.round(e*1e4)/1e4});import J1 from"node:fs/promises";import Y1 from"node:os";import vv from"node:path";function $v(e){return e==="codex"?eB:e==="cursor"?Iv:Ev}function Sv(e){let t=String(e||"").split(`
177
177
  `),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 Tv(e){let t=String(e||"").split(`
178
- `),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 ej(e){let t=String(e||"").split(`
178
+ `),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 tB(e){let t=String(e||"").split(`
179
179
  `);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 Av(e){let t=String(e||"").split(`
180
- `),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 Rv(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&&!_v.has(o))throw new Error(`unknown codex effort "${o}" (low | medium | high | xhigh)`);return{model:r,effort:o||null}}if(e==="cursor"){let r=Iv.find(o=>o.alias===n);return{model:n,filter:r?r.label:n}}if(!Z1.has(n))throw new Error(`unknown model "${n}"`);return{model:n}}async function Oi(e,t,{timeoutMs:n=Y1}={}){let r=Date.now()+n;for(;;){let o=await je(e,{lines:80}).catch(()=>""),s=t(o);if(s)return s;if(Date.now()>r)return null;await wu(X1)}}async function tj(e,t){return await nt(e,`/model ${t.model}`,vn("claude")),{verified:!1,note:"confirmed when the next turn's transcript model flips"}}async function nj(e,t){await Nl(e),await nt(e,"/model",{enter:!1}),await wu(250),await Ke(e,["Enter"],{kind:"model-switch"});let n=await Oi(e,Sv);if(!n)throw new Error("codex model picker didn't open");let r=n.find(i=>i.id===t.model);if(!r)throw await Ke(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=ej(i);return!c||c.model!==t.model||t.effort&&c.effort&&c.effort.toLowerCase()!==t.effort.toLowerCase()?null:c};await nt(e,String(r.n),{enter:!1,kind:"model-switch"});let s=await Oi(e,i=>Tv(i)||!Sv(i)&&o(i)&&{done:o(i)});if(!s)throw await Ke(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error("codex reasoning-level picker didn't open");if(!s.done){let i=t.effort?_v.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 Ke(e,["Escape","Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`codex doesn't offer effort "${t.effort}" for ${t.model}`);await nt(e,String(c.n),{enter:!1,kind:"model-switch"})}let a=s.done||await Oi(e,i=>!Tv(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 rj(){let e=vv.join(process.env.CURSOR_CONFIG_DIR||vv.join(J1.homedir(),".cursor"),"cli-config.json");try{return JSON.parse(await V1.readFile(e,"utf8"))?.model||null}catch{return null}}async function oj(e,t){await Nl(e),await Dl(e,`/model ${t.filter}`,{kind:"model-switch"});let n=await Oi(e,Av),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 Oi(e,Av,{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 Ke(e,["Down"],{kind:"model-switch"}),await wu(250)}if(!n||!s||!o(s)){await Ke(e,["Escape"],{kind:"model-switch"}).catch(()=>{});let c=Array(`/model ${t.filter}`.length).fill("BSpace");throw await Ke(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 Ke(e,["Enter"],{kind:"model-switch"}),await wu(800);let a=await rj();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 Ov(e,t,n){return e==="codex"?nj(t,n):e==="cursor"?oj(t,n):tj(t,n)}var wu,Y1,X1,Ev,Z1,Q1,_v,Iv,Cv=q(()=>{ct();wi();wu=e=>new Promise(t=>setTimeout(t,e)),Y1=Number(process.env.BOSTRAT_MODEL_PICKER_TIMEOUT_MS)||8e3,X1=300,Ev=[{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"},{alias:"opusplan",label:"Opus Plan"}],Z1=new Set([...Ev.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"]),Q1=[{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"}],_v=new Map([["low","Low"],["medium","Medium"],["high","High"],["xhigh","Extra high"]]),Iv=[{alias:"auto",label:"Auto"},{alias:"composer-2.5",label:"Composer 2.5"},{alias:"claude-opus-5",label:"Opus 5"},{alias:"claude-fable-5",label:"Fable 5"},{alias:"claude-sonnet-5",label:"Sonnet 5"},{alias:"claude-sonnet-4-6",label:"Sonnet 4.6"},{alias:"gpt-5.6-sol",label:"GPT-5.6 Sol"},{alias:"gpt-5.3-codex",label:"Codex 5.3"}]});function yu(e){let t=e||{},n=sj(t);return n&&(n.payload={ts:t.at,...n.payload}),n}function sj(e){switch(e.type){case"said":return{type:"turn.user",actor:"user",source:"orchestrator",boxId:e.box,provider:bt(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:bt(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:bt(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:bt(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}};case"lead-handoff-failed":return{type:"handoff.failed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:bt(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:bt(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:bt(e.agent),payload:{...Lr(e)}};case"subtask-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box||e.to,provider:bt(e.agent||e.toAgent),payload:{kind:"subtask-failed",...Lr(e)}};case"subtask-resumed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:bt(e.agent),payload:{change:"subtask-resumed",...Lr(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",...Lr(e)}};case"opened":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:e.box,payload:{change:"opened",...Lr(e)}};case"archived":case"unarchived":case"track-deleted":case"renamed":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:e.type,...Lr(e)}};case"rehydrated":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:bt(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:bt(e.agent),payload:{change:"lead-refreshed",box:e.box,agent:e.agent,fromSessionId:e.fromSessionId,toSessionId:e.toSessionId,epoch:e.epoch,reason:e.reason}};case"transferred-in":return{type:e.mode==="recover"?"track.recovered":"track.transferred",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:bt(e.agent),payload:{...Lr(e)}};case"transferred-out":return null;case"retagged":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:"retagged",...Lr(e)}};case"rehydrate-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:bt(e.agent),payload:{kind:"rehydrate-failed",reason:e.reason}};default:return null}}function Pv(e,t){let n=yu(t);if(!n)return;let r=t?.type==="track-deleted"?{id:e.id}:e;$m(()=>C(r,n))}async function Dv(e){if(!(!e?.id||Mv.has(e.id))){Mv.add(e.id);try{let t=await K(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=yu(r);!o||n.has(`${o.type}|${o.payload?.ts??"?"}`)||await C(e,o)}}catch{}}}function Lr(e){let{type:t,at:n,...r}=e;return r}function jv(e,t,n){!n?.promptId||Im.get(e.id)===n.promptId||(Im.set(e.id,n.promptId),$m(()=>C(e,{type:"prompt.raised",actor:"agent",source:"pane",boxId:t?.name,provider:bt(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 Rm(e,t,n,r={}){Im.delete(e.id),$m(()=>C(e,{type:"prompt.answered",actor:"user",source:"orchestrator",boxId:t?.name,provider:bt(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}var bt,gu,$m,Nv,Mv,Im,Om=q(()=>{de();bt=e=>e||null;gu=Promise.resolve(),$m=e=>(gu=gu.then(e).catch(()=>{}),gu),Nv=()=>gu;Mv=new Set;Im=new Map});function uj(e){return String(e).split(/(?<=[.?!])\s+|\n+/).map(t=>t.trim()).filter(Boolean)}function Wv(e){let t=String(e||"").trim();if(!t)return null;let n=t.slice(-600);for(let r of uj(n).reverse()){if(!aj.test(r))continue;let o=r.endsWith("?")&&r.length<=lj&&cj.test(r);if(ij.test(r)||o)return r.length>200?r.slice(0,197)+"\u2026":r}return null}function Kv(e){let t=String(e||""),n=[];dj.test(t)&&n.push("commit"),qv.test(t)&&n.push("rebase"),pj.test(t)&&n.push("push");let r=mj.test(t);!r&&fj.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 Gv(e){return qv.test(String(e||""))}function zs(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 zv(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 Vv(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<=hj&&n.push({box:r.box,from:r.from,to:t+1e12}),n}function Jv(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+wj||(!o||s.ts>=o.ts)&&(o=s);o&&n.add(o)}return n}function Yv(e){let t=(Array.isArray(e)?e:[]).filter(r=>Bv[r]).map(r=>Bv[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 Lv,Fv,Uv,Hv,aj,ij,cj,lj,Fr,dj,qv,pj,fj,mj,hj,wj,Bv,Mo=q(()=>{Lv=/(?<!\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,Fv=/(?<!\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,Uv=/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,Hv=/(?<!\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,aj=new RegExp(`\\b(?:${Lv}|${Fv}|${Uv}|${Hv})\\b`,"i"),ij=/\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,cj=/^(?:commit|push|open|create|raise|rebase|ready|ok(?:ay)?\s+to|good\s+to)\b/i,lj=90;Fr=["commit","rebase","push","pr"],dj=new RegExp(`\\b(?:${Lv})\\b`,"i"),qv=new RegExp(`\\b(?:${Hv})\\b`,"i"),pj=new RegExp(`\\b(?:${Fv})\\b`,"i"),fj=new RegExp(`\\b(?:${Uv})\\b`,"i"),mj=/\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;hj=3e4;wj=2500;Bv={commit:"commit",rebase:"rebase",push:"push",pr:"open a PR"}});import gj from"node:crypto";import bu from"node:fs/promises";import Xv from"node:path";import yj from"node:os";async function We(){return Ur||(Cm??=bu.readFile(Nm,"utf8").then(e=>({links:JSON.parse(e)?.links??{},existed:!0})).catch(()=>({links:{},existed:!1})).then(async({links:e,existed:t})=>{if(Ur=e,!t&&Fe()){let{records:n,source:r}=await st("prlinks").catch(()=>({records:[],source:"error"}));if(r==="plane"){for(let o of n){if(o.deletedAt||!o.data?.repo||o.data?.number==null)continue;let{id:s,updatedAt:a,...i}=o.data;Ur[se(i.repo,i.number)]=i}Object.keys(Ur).length&&await Pm().catch(()=>{})}}return Ur}).finally(()=>Cm=null),Cm)}async function Pm(){let e=JSON.stringify({links:Ur},null,2),t=`${Nm}.${process.pid}.tmp`;await bu.mkdir(Zv,{recursive:!0}),await bu.writeFile(t,e),await bu.rename(t,Nm)}async function Xe(e){Mm=Mm.then(Pm,Pm),await Mm.catch(()=>{});let t=Ur?.[e];t&&yt("prlinks",{id:Qv(e),updatedAt:Date.now(),...t},{trackId:t.trackId??null}).catch(()=>{})}async function Ct({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 We(),c=se(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:bj.has(a),firstSeen:Date.now()},await Xe(se(e,t)),{link:i[c],created:!0})}async function Yn(e,t){if(!e||t==null)return null;let n=(await We())[se(e,t)];return!n||n.announced?null:(n.announced=!0,await Xe(se(e,t)),n)}async function eS(e,t){if(!e||t==null)return!1;let n=(await We())[se(e,t)];return n?.notifyOnMerge?(delete n.notifyOnMerge,await Xe(se(e,t)),!0):!1}async function at(e,t){return!e||t==null?null:(await We())[se(e,t)]??null}async function Hr(e,t,n){if(!e||t==null)return null;let r=(await We())[se(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 Xe(se(e,t)),r):null}async function tS(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await We())[se(e,t)];return o?(o.ciFix={delegatedAt:Date.now(),headSha:n,trackId:r},await Xe(se(e,t)),o):null}async function nS(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await We())[se(e,t)];return o?(o.reconcile={delegatedAt:Date.now(),headSha:n,trackId:r},await Xe(se(e,t)),o):null}async function ku(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await We())[se(e,t)];return!r||!r.ciFix?null:(r.ciFixAwait={since:Date.now(),trackId:r.ciFix.trackId??null,headSha:n},delete r.ciFix,await Xe(se(e,t)),r)}async function xu(e,t){if(!e||t==null)return null;let n=(await We())[se(e,t)];return!n||!n.ciFixAwait?null:(delete n.ciFixAwait,await Xe(se(e,t)),n)}async function vu(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await We())[se(e,t)];return!r||!r.reconcile?null:(r.reconcileAwait={since:Date.now(),trackId:r.reconcile.trackId??null,headSha:n},delete r.reconcile,await Xe(se(e,t)),r)}async function Su(e,t){if(!e||t==null)return null;let n=(await We())[se(e,t)];return!n||!n.reconcileAwait?null:(delete n.reconcileAwait,await Xe(se(e,t)),n)}async function rS(e,t,{at:n=Date.now()}={}){if(!e||t==null)return null;let r=(await We())[se(e,t)];return r?(r.baseFoldAt=n,await Xe(se(e,t)),r):null}async function oS(e,t){if(!e||t==null)return null;let n=(await We())[se(e,t)];return!n||!n.baseFoldAt?null:(delete n.baseFoldAt,await Xe(se(e,t)),n)}async function sS(e,t,n){if(!e||t==null||!n)return null;let r=(await We())[se(e,t)];return r?(r.lastHeadSha=n,await Xe(se(e,t)),r):null}async function aS(e,t,n){if(!e||t==null||!n)return{prev:null,link:null};let r=(await We())[se(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 Xe(se(e,t))),{prev:o,link:r}}async function Ci(e,t,{merge:n=null}={}){if(!e||t==null)return null;let r=(await We())[se(e,t)];return r?(r.armedAt=Date.now(),n&&(r.autoMerge={method:n.method||"merge",armedAt:r.armedAt}),await Xe(se(e,t)),r):null}async function No(e,t,n=!0){if(!e||t==null)return null;let r=(await We())[se(e,t)];return r?(n?r.archiveOnMerge=!0:delete r.archiveOnMerge,await Xe(se(e,t)),r):null}async function Po(e,t,n=!0){if(!e||t==null)return null;let r=(await We())[se(e,t)];return r?(n?r.notifyOnMerge=!0:delete r.notifyOnMerge,await Xe(se(e,t)),r):null}async function iS(e,t,n){if(!e||t==null)return null;let r=(await We())[se(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 Xe(se(e,t)),r}async function cS(e,t,n){if(!e||t==null)return null;let r=(await We())[se(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 Xe(se(e,t)),r}async function Mi(e,t){if(!e||t==null)return null;let n=(await We())[se(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 Xe(se(e,t)),n)}async function lS(){return Object.values(await We()).filter(e=>!kj.has(e.state))}async function Xn(){return Object.values(await We()).sort((e,t)=>t.firstSeen-e.firstSeen)}async function uS(){if(!Fe())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("prlinks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await We(),r=0;for(let[o,s]of Object.entries(n))await yt("prlinks",{id:Qv(o),updatedAt:Date.now(),...s},{trackId:s.trackId??null}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}var Zv,Nm,se,Qv,Ur,Cm,Mm,bj,kj,Zn=q(()=>{Tr();Zv=process.env.BOSTRAT_STATE_DIR||Xv.join(process.env.HOME||yj.tmpdir(),".bostrat"),Nm=Xv.join(Zv,"pr-links.json"),se=(e,t)=>`${e}#${Number(t)}`,Qv=e=>{let t=e.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^[^A-Za-z0-9]+/,"").slice(0,55),n=gj.createHash("sha256").update(e).digest("hex").slice(0,8);return`${t||"pr"}-${n}`},Ur=null,Cm=null,Mm=Promise.resolve();bj=new Set(["api","observed","reconciled"]);kj=new Set(["merged","closed","lost"])});import xj from"node:fs";import Dm from"node:fs/promises";import mS from"node:path";import vj from"node:os";function gS(e,t=!1){if(!t&&e-pS<Sj)return;pS=e;let n=JSON.stringify({windowStart:Vs,byCaller:Object.fromEntries(Qn),lastHour:Wr});fS=fS.then(()=>Dm.mkdir(hS,{recursive:!0})).then(()=>Dm.writeFile(`${Tu}.tmp`,n)).then(()=>Dm.rename(`${Tu}.tmp`,Tu)).catch(()=>{})}function yS(e){e-Vs<wS||(Wr={start:Vs,total:Au(Qn),byCaller:Object.fromEntries(Qn)},Wr.total&&console.log(`[github] ${Wr.total} calls last hour`,Wr.byCaller),Vs=e,Qn=new Map,gS(e,!0))}function er(e="other",t=Date.now()){yS(t),Qn.set(e,(Qn.get(e)||0)+1),gS(t)}function bS(e=Date.now()){return yS(e),{windowStart:Vs,total:Au(Qn),byCaller:Object.fromEntries(Qn),lastHour:Wr,backoffUntil:Do>e?Do:null}}function qr(e){return Tj.test(String(e?.message||e||""))}function Kr(e,t=Date.now()){return Do<=t&&console.warn(`[github] rate limited \u2014 backing off ${dS/6e4} min:`,String(e?.message||e||"").slice(0,200)),Do=Math.max(Do,t+dS),Do}function Eu(e=Date.now()){return Math.max(0,Do-e)}var hS,Tu,wS,dS,Sj,Vs,Qn,Wr,Do,pS,Au,fS,Tj,Ni=q(()=>{hS=process.env.BOSTRAT_STATE_DIR||mS.join(process.env.HOME||vj.tmpdir(),".bostrat"),Tu=mS.join(hS,"github-metrics.json"),wS=60*6e4,dS=5*6e4,Sj=6e4,Vs=Date.now(),Qn=new Map,Wr=null,Do=0,pS=0,Au=e=>[...e.values()].reduce((t,n)=>t+n,0);try{let e=JSON.parse(xj.readFileSync(Tu,"utf8"));e?.windowStart&&(Date.now()-e.windowStart<wS?(Vs=e.windowStart,Qn=new Map(Object.entries(e.byCaller||{})),Wr=e.lastHour||null):Au(new Map(Object.entries(e.byCaller||{})))&&(Wr={start:e.windowStart,total:Au(new Map(Object.entries(e.byCaller||{}))),byCaller:e.byCaller||{}}))}catch{}fS=Promise.resolve();Tj=/rate limit|too quickly|abuse detection|HTTP 429/i});import kS from"node:fs/promises";import xS from"node:path";import Aj from"node:os";function Iu({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};_u.push(l),_u.length>_j&&_u.shift();let u=jm.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)),jm.set(e,u),Ij(l),l}async function Ij(e){try{await kS.mkdir(vS,{recursive:!0}),await kS.appendFile(Ej,JSON.stringify(e)+`
181
- `)}catch{}}function SS(){let e={};for(let[t,n]of jm)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:_u.slice(-20)}}var vS,Ej,_j,_u,jm,$u=q(()=>{vS=process.env.BOSTRAT_STATE_DIR||xS.join(process.env.HOME||Aj.tmpdir(),".bostrat"),Ej=xS.join(vS,"github-latency.ndjson"),_j=100,_u=[],jm=new Map});import{execFile as $j}from"node:child_process";import{promisify as Rj}from"node:util";async function Oj(e){let t=/workspaces[/\\]([0-9a-f]{8})(?:[/\\]|$)/.exec(e||"")?.[1];if(t)try{let[{stdout:n},{stdout:r}]=await Promise.all([Ys("git",["-C",e,"rev-parse","HEAD"]),Ys("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 yn({cwd:e});er(r);try{let{stdout:a}=await Ys("gh",t,{cwd:e,...Cj,...o,env:{...process.env,...s,...o.env||{}}});return String(a||"")}catch(a){throw qr(a)&&Kr(a),a}}async function Fm(){if(Ru&&Date.now()-Ru.at<6e4)return Ru.data;let e;try{er("auth");let t=await Ys("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 qa();t.configured&&(e={installed:!0,authenticated:!0,login:t.username,via:"broker"})}catch{}return Ru={at:Date.now(),data:e},e}async function Mj(e){try{let{stdout:t}=await Ys("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});return/github\.com/.test(t)}catch{return!1}}function AS(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 Bm(e){let t=(e||[]).map(AS),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 _S(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 IS(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 $S(e,t){let n=await _S(e,t);return n===null?{...Bm([]),unavailable:!0}:Bm(IS(n))}function Ou(e,t=Bm(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 Pj(e,t,n){let r=new Set;for(let o of t){let s=`${e}#${o.number}`;if(o.mergeable!=="UNKNOWN"&&o.mergeStateStatus!=="UNKNOWN"){Js.delete(s);continue}r.add(s),Js.has(s)||Js.set(s,n),o.mergeabilityPending=n-Js.get(s)<Nj}for(let o of Js.keys())o.startsWith(`${e}#`)&&!r.has(o)&&Js.delete(o);return t}async function Xs(e,t){let n=await tr(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 Ou(JSON.parse(o))}catch(o){if(!Hm(o))throw o;let s=await qt(n.path,["pr","view",String(r),"--json",ES]),a=JSON.parse(s);return Ou(a,await $S(n.path,a.headRefOid))}}async function En(e,{caller:t="prs"}={}){try{let n=await qt(e,["pr","list","--json",Um,"--limit","50"],{caller:t});return JSON.parse(n||"[]").map(r=>Ou(r)).sort(TS)}catch(n){if(!Hm(n))throw n;let r=await qt(e,["pr","list","--json",ES,"--limit","50"],{caller:t});return(await Promise.all(JSON.parse(r||"[]").map(async o=>Ou(o,await $S(e,o.headRefOid))))).sort(TS)}}function Kt(){Pi.clear()}async function Bj(e,t){if(!e)return t;for(let n of t){let r=await at(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 ku(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.ciFix={delegatedAt:r.ciFix.delegatedAt,trackId:r.ciFix.trackId??null}),r.reconcile&&(o(r.reconcile)?await vu(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.reconcile={delegatedAt:r.reconcile.delegatedAt,trackId:r.reconcile.trackId??null})}return t}async function RS(){let e=await Fm();if(!e.authenticated)return{auth:e,repos:[]};let t=[];for(let a of await Wn())await Mj(a.path)&&t.push(a);let n=Date.now(),r=Eu(n)>0,o=await Promise.all(t.map(async a=>{let i=Pi.get(a.path),c=i?.pending?jj:Dj;if(i&&(r||n-i.at<c))return i.entry;try{let l=await _e(a.path).catch(()=>null),u=Pj(a.path,await En(a.path,{caller:"tab"}),n);if(await Bj(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&&Iu({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 Pi.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:_n(l)}}})),s=new Set(t.map(a=>a.path));for(let a of Pi.keys())s.has(a)||Pi.delete(a);return{auth:e,repos:o}}async function tr(e){let t=(await Wn()).find(n=>n.path===e);if(!t)throw new Error(`unknown repo: ${e}`);return t}async function jo(e){return ms(e)}async function Zs(e,t,{method:n="squash"}={}){let r=await tr(e);if(!Di.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 yn({cwd:r.path})).GH_TOKEN){let a=await Cp().catch(()=>null);a&&s.push("--body",`Merged by bostrat on behalf of @${a}`)}try{await qt(r.path,s)}catch(a){throw new Error(_n(a))}finally{Kt()}return{ok:!0,number:o}}async function ji(e,t){let n=await tr(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(_n(s))}finally{Kt()}let o=await _e(n.path).catch(()=>null);return o&&await rS(o,r).catch(()=>{}),{ok:!0,number:r}}async function Wm(e,t){let n=await tr(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(_n(o))}finally{Kt()}return{ok:!0,number:r}}function qm(e){return e.green&&!e.isDraft}function Hj(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 OS(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 CS(e){return[...e.filter(t=>t.plan.action!=="merge"),...e.filter(t=>t.plan.action==="merge")]}function Bi(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 MS(e){let t=new Map;for(let n of[...e].filter(r=>r?.autoMerge&&r?.trackId).sort(Bi))t.has(n.trackId)||t.set(n.trackId,`${n.repo}#${n.number}`);return t}function NS(){let e={};for(let[t,n]of Lm)e[t]={...n};return e}async function PS(e,{method:t="merge",onMerged:n=null}={}){let r=await tr(e);if(!Di.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 En(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),qj(s,o,{listPrs:()=>En(r.path),merge:a=>Zs(r.path,a,{method:t}),sleep:Uj,onMerged:n}).catch(()=>{}),{ok:!0,repo:r.path,total:s.total,queue:o.map(a=>a.number)}}async function Wj(e,t){let n=Date.now()+(t.settleMaxMs??Fj),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(Lj)}}async function qj(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 Wj(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: ${_n(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:Hj(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:_n(i)})}}}finally{e.current=null,e.running=!1,e.finishedAt=Date.now(),Kt()}}async function Km(e,{title:t,body:n="",base:r=null}={}){if(typeof t!="string"||!t.trim())throw new Error("title required");try{await Ys("git",["-C",e,"push","-u","origin","HEAD"],{timeout:12e4,maxBuffer:4*1024*1024})}catch(l){throw new Error(`push failed: ${_n(l)}`)}await Oj(e);let o=n||"";if((await yn({cwd:e})).GH_TOKEN){let l=await Cp().catch(()=>null);l&&(o=`${o?`${o}
180
+ `),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 Rv(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&&!_v.has(o))throw new Error(`unknown codex effort "${o}" (low | medium | high | xhigh)`);return{model:r,effort:o||null}}if(e==="cursor"){let r=Iv.find(o=>o.alias===n);return{model:n,filter:r?r.label:n}}if(!Q1.has(n))throw new Error(`unknown model "${n}"`);return{model:n}}async function Oi(e,t,{timeoutMs:n=X1}={}){let r=Date.now()+n;for(;;){let o=await Be(e,{lines:80}).catch(()=>""),s=t(o);if(s)return s;if(Date.now()>r)return null;await wu(Z1)}}async function nB(e,t){return await nt(e,`/model ${t.model}`,vn("claude")),{verified:!1,note:"confirmed when the next turn's transcript model flips"}}async function rB(e,t){await Nl(e),await nt(e,"/model",{enter:!1}),await wu(250),await Ke(e,["Enter"],{kind:"model-switch"});let n=await Oi(e,Sv);if(!n)throw new Error("codex model picker didn't open");let r=n.find(i=>i.id===t.model);if(!r)throw await Ke(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=tB(i);return!c||c.model!==t.model||t.effort&&c.effort&&c.effort.toLowerCase()!==t.effort.toLowerCase()?null:c};await nt(e,String(r.n),{enter:!1,kind:"model-switch"});let s=await Oi(e,i=>Tv(i)||!Sv(i)&&o(i)&&{done:o(i)});if(!s)throw await Ke(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error("codex reasoning-level picker didn't open");if(!s.done){let i=t.effort?_v.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 Ke(e,["Escape","Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`codex doesn't offer effort "${t.effort}" for ${t.model}`);await nt(e,String(c.n),{enter:!1,kind:"model-switch"})}let a=s.done||await Oi(e,i=>!Tv(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 oB(){let e=vv.join(process.env.CURSOR_CONFIG_DIR||vv.join(Y1.homedir(),".cursor"),"cli-config.json");try{return JSON.parse(await J1.readFile(e,"utf8"))?.model||null}catch{return null}}async function sB(e,t){await Nl(e),await Dl(e,`/model ${t.filter}`,{kind:"model-switch"});let n=await Oi(e,Av),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 Oi(e,Av,{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 Ke(e,["Down"],{kind:"model-switch"}),await wu(250)}if(!n||!s||!o(s)){await Ke(e,["Escape"],{kind:"model-switch"}).catch(()=>{});let c=Array(`/model ${t.filter}`.length).fill("BSpace");throw await Ke(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 Ke(e,["Enter"],{kind:"model-switch"}),await wu(800);let a=await oB();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 Ov(e,t,n){return e==="codex"?rB(t,n):e==="cursor"?sB(t,n):nB(t,n)}var wu,X1,Z1,Ev,Q1,eB,_v,Iv,Cv=q(()=>{ct();wi();wu=e=>new Promise(t=>setTimeout(t,e)),X1=Number(process.env.BOSTRAT_MODEL_PICKER_TIMEOUT_MS)||8e3,Z1=300,Ev=[{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"},{alias:"opusplan",label:"Opus Plan"}],Q1=new Set([...Ev.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"]),eB=[{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"}],_v=new Map([["low","Low"],["medium","Medium"],["high","High"],["xhigh","Extra high"]]),Iv=[{alias:"auto",label:"Auto"},{alias:"composer-2.5",label:"Composer 2.5"},{alias:"claude-opus-5",label:"Opus 5"},{alias:"claude-fable-5",label:"Fable 5"},{alias:"claude-sonnet-5",label:"Sonnet 5"},{alias:"claude-sonnet-4-6",label:"Sonnet 4.6"},{alias:"gpt-5.6-sol",label:"GPT-5.6 Sol"},{alias:"gpt-5.3-codex",label:"Codex 5.3"}]});function yu(e){let t=e||{},n=aB(t);return n&&(n.payload={ts:t.at,...n.payload}),n}function aB(e){switch(e.type){case"said":return{type:"turn.user",actor:"user",source:"orchestrator",boxId:e.box,provider:bt(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:bt(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:bt(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:bt(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}};case"lead-handoff-failed":return{type:"handoff.failed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:bt(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:bt(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:bt(e.agent),payload:{...Lr(e)}};case"subtask-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box||e.to,provider:bt(e.agent||e.toAgent),payload:{kind:"subtask-failed",...Lr(e)}};case"subtask-resumed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:bt(e.agent),payload:{change:"subtask-resumed",...Lr(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",...Lr(e)}};case"opened":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:e.box,payload:{change:"opened",...Lr(e)}};case"archived":case"unarchived":case"track-deleted":case"renamed":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:e.type,...Lr(e)}};case"rehydrated":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:bt(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:bt(e.agent),payload:{change:"lead-refreshed",box:e.box,agent:e.agent,fromSessionId:e.fromSessionId,toSessionId:e.toSessionId,epoch:e.epoch,reason:e.reason}};case"transferred-in":return{type:e.mode==="recover"?"track.recovered":"track.transferred",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:bt(e.agent),payload:{...Lr(e)}};case"transferred-out":return null;case"retagged":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:"retagged",...Lr(e)}};case"rehydrate-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:bt(e.agent),payload:{kind:"rehydrate-failed",reason:e.reason}};default:return null}}function Pv(e,t){let n=yu(t);if(!n)return;let r=t?.type==="track-deleted"?{id:e.id}:e;Rm(()=>C(r,n))}async function Dv(e){if(!(!e?.id||Mv.has(e.id))){Mv.add(e.id);try{let t=await K(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=yu(r);!o||n.has(`${o.type}|${o.payload?.ts??"?"}`)||await C(e,o)}}catch{}}}function Lr(e){let{type:t,at:n,...r}=e;return r}function Bv(e,t,n){!n?.promptId||$m.get(e.id)===n.promptId||($m.set(e.id,n.promptId),Rm(()=>C(e,{type:"prompt.raised",actor:"agent",source:"pane",boxId:t?.name,provider:bt(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 Om(e,t,n,r={}){$m.delete(e.id),Rm(()=>C(e,{type:"prompt.answered",actor:"user",source:"orchestrator",boxId:t?.name,provider:bt(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}var bt,gu,Rm,Nv,Mv,$m,Cm=q(()=>{de();bt=e=>e||null;gu=Promise.resolve(),Rm=e=>(gu=gu.then(e).catch(()=>{}),gu),Nv=()=>gu;Mv=new Set;$m=new Map});function dB(e){return String(e).split(/(?<=[.?!])\s+|\n+/).map(t=>t.trim()).filter(Boolean)}function Wv(e){let t=String(e||"").trim();if(!t)return null;let n=t.slice(-600);for(let r of dB(n).reverse()){if(!iB.test(r))continue;let o=r.endsWith("?")&&r.length<=uB&&lB.test(r);if(cB.test(r)||o)return r.length>200?r.slice(0,197)+"\u2026":r}return null}function Kv(e){let t=String(e||""),n=[];pB.test(t)&&n.push("commit"),qv.test(t)&&n.push("rebase"),fB.test(t)&&n.push("push");let r=hB.test(t);!r&&mB.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 Gv(e){return qv.test(String(e||""))}function zs(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 zv(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 Vv(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<=wB&&n.push({box:r.box,from:r.from,to:t+1e12}),n}function Jv(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+gB||(!o||s.ts>=o.ts)&&(o=s);o&&n.add(o)}return n}function Yv(e){let t=(Array.isArray(e)?e:[]).filter(r=>jv[r]).map(r=>jv[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 Lv,Fv,Uv,Hv,iB,cB,lB,uB,Fr,pB,qv,fB,mB,hB,wB,gB,jv,Mo=q(()=>{Lv=/(?<!\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,Fv=/(?<!\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,Uv=/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,Hv=/(?<!\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,iB=new RegExp(`\\b(?:${Lv}|${Fv}|${Uv}|${Hv})\\b`,"i"),cB=/\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,lB=/^(?:commit|push|open|create|raise|rebase|ready|ok(?:ay)?\s+to|good\s+to)\b/i,uB=90;Fr=["commit","rebase","push","pr"],pB=new RegExp(`\\b(?:${Lv})\\b`,"i"),qv=new RegExp(`\\b(?:${Hv})\\b`,"i"),fB=new RegExp(`\\b(?:${Fv})\\b`,"i"),mB=new RegExp(`\\b(?:${Uv})\\b`,"i"),hB=/\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;wB=3e4;gB=2500;jv={commit:"commit",rebase:"rebase",push:"push",pr:"open a PR"}});import yB from"node:crypto";import bu from"node:fs/promises";import Xv from"node:path";import bB from"node:os";async function We(){return Ur||(Mm??=bu.readFile(Pm,"utf8").then(e=>({links:JSON.parse(e)?.links??{},existed:!0})).catch(()=>({links:{},existed:!1})).then(async({links:e,existed:t})=>{if(Ur=e,!t&&Fe()){let{records:n,source:r}=await st("prlinks").catch(()=>({records:[],source:"error"}));if(r==="plane"){for(let o of n){if(o.deletedAt||!o.data?.repo||o.data?.number==null)continue;let{id:s,updatedAt:a,...i}=o.data;Ur[se(i.repo,i.number)]=i}Object.keys(Ur).length&&await Dm().catch(()=>{})}}return Ur}).finally(()=>Mm=null),Mm)}async function Dm(){let e=JSON.stringify({links:Ur},null,2),t=`${Pm}.${process.pid}.tmp`;await bu.mkdir(Zv,{recursive:!0}),await bu.writeFile(t,e),await bu.rename(t,Pm)}async function Xe(e){Nm=Nm.then(Dm,Dm),await Nm.catch(()=>{});let t=Ur?.[e];t&&yt("prlinks",{id:Qv(e),updatedAt:Date.now(),...t},{trackId:t.trackId??null}).catch(()=>{})}async function Ct({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 We(),c=se(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:kB.has(a),firstSeen:Date.now()},await Xe(se(e,t)),{link:i[c],created:!0})}async function Yn(e,t){if(!e||t==null)return null;let n=(await We())[se(e,t)];return!n||n.announced?null:(n.announced=!0,await Xe(se(e,t)),n)}async function eS(e,t){if(!e||t==null)return!1;let n=(await We())[se(e,t)];return n?.notifyOnMerge?(delete n.notifyOnMerge,await Xe(se(e,t)),!0):!1}async function at(e,t){return!e||t==null?null:(await We())[se(e,t)]??null}async function Hr(e,t,n){if(!e||t==null)return null;let r=(await We())[se(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 Xe(se(e,t)),r):null}async function tS(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await We())[se(e,t)];return o?(o.ciFix={delegatedAt:Date.now(),headSha:n,trackId:r},await Xe(se(e,t)),o):null}async function nS(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await We())[se(e,t)];return o?(o.reconcile={delegatedAt:Date.now(),headSha:n,trackId:r},await Xe(se(e,t)),o):null}async function ku(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await We())[se(e,t)];return!r||!r.ciFix?null:(r.ciFixAwait={since:Date.now(),trackId:r.ciFix.trackId??null,headSha:n},delete r.ciFix,await Xe(se(e,t)),r)}async function xu(e,t){if(!e||t==null)return null;let n=(await We())[se(e,t)];return!n||!n.ciFixAwait?null:(delete n.ciFixAwait,await Xe(se(e,t)),n)}async function vu(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await We())[se(e,t)];return!r||!r.reconcile?null:(r.reconcileAwait={since:Date.now(),trackId:r.reconcile.trackId??null,headSha:n},delete r.reconcile,await Xe(se(e,t)),r)}async function Su(e,t){if(!e||t==null)return null;let n=(await We())[se(e,t)];return!n||!n.reconcileAwait?null:(delete n.reconcileAwait,await Xe(se(e,t)),n)}async function rS(e,t,{at:n=Date.now()}={}){if(!e||t==null)return null;let r=(await We())[se(e,t)];return r?(r.baseFoldAt=n,await Xe(se(e,t)),r):null}async function oS(e,t){if(!e||t==null)return null;let n=(await We())[se(e,t)];return!n||!n.baseFoldAt?null:(delete n.baseFoldAt,await Xe(se(e,t)),n)}async function sS(e,t,n){if(!e||t==null||!n)return null;let r=(await We())[se(e,t)];return r?(r.lastHeadSha=n,await Xe(se(e,t)),r):null}async function aS(e,t,n){if(!e||t==null||!n)return{prev:null,link:null};let r=(await We())[se(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 Xe(se(e,t))),{prev:o,link:r}}async function Ci(e,t,{merge:n=null}={}){if(!e||t==null)return null;let r=(await We())[se(e,t)];return r?(r.armedAt=Date.now(),n&&(r.autoMerge={method:n.method||"merge",armedAt:r.armedAt}),await Xe(se(e,t)),r):null}async function No(e,t,n=!0){if(!e||t==null)return null;let r=(await We())[se(e,t)];return r?(n?r.archiveOnMerge=!0:delete r.archiveOnMerge,await Xe(se(e,t)),r):null}async function Po(e,t,n=!0){if(!e||t==null)return null;let r=(await We())[se(e,t)];return r?(n?r.notifyOnMerge=!0:delete r.notifyOnMerge,await Xe(se(e,t)),r):null}async function iS(e,t,n){if(!e||t==null)return null;let r=(await We())[se(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 Xe(se(e,t)),r}async function cS(e,t,n){if(!e||t==null)return null;let r=(await We())[se(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 Xe(se(e,t)),r}async function Mi(e,t){if(!e||t==null)return null;let n=(await We())[se(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 Xe(se(e,t)),n)}async function lS(){return Object.values(await We()).filter(e=>!xB.has(e.state))}async function Xn(){return Object.values(await We()).sort((e,t)=>t.firstSeen-e.firstSeen)}async function uS(){if(!Fe())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("prlinks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await We(),r=0;for(let[o,s]of Object.entries(n))await yt("prlinks",{id:Qv(o),updatedAt:Date.now(),...s},{trackId:s.trackId??null}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}var Zv,Pm,se,Qv,Ur,Mm,Nm,kB,xB,Zn=q(()=>{Tr();Zv=process.env.BOSTRAT_STATE_DIR||Xv.join(process.env.HOME||bB.tmpdir(),".bostrat"),Pm=Xv.join(Zv,"pr-links.json"),se=(e,t)=>`${e}#${Number(t)}`,Qv=e=>{let t=e.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^[^A-Za-z0-9]+/,"").slice(0,55),n=yB.createHash("sha256").update(e).digest("hex").slice(0,8);return`${t||"pr"}-${n}`},Ur=null,Mm=null,Nm=Promise.resolve();kB=new Set(["api","observed","reconciled"]);xB=new Set(["merged","closed","lost"])});import vB from"node:fs";import Bm from"node:fs/promises";import mS from"node:path";import SB from"node:os";function gS(e,t=!1){if(!t&&e-pS<TB)return;pS=e;let n=JSON.stringify({windowStart:Vs,byCaller:Object.fromEntries(Qn),lastHour:Wr});fS=fS.then(()=>Bm.mkdir(hS,{recursive:!0})).then(()=>Bm.writeFile(`${Tu}.tmp`,n)).then(()=>Bm.rename(`${Tu}.tmp`,Tu)).catch(()=>{})}function yS(e){e-Vs<wS||(Wr={start:Vs,total:Au(Qn),byCaller:Object.fromEntries(Qn)},Wr.total&&console.log(`[github] ${Wr.total} calls last hour`,Wr.byCaller),Vs=e,Qn=new Map,gS(e,!0))}function er(e="other",t=Date.now()){yS(t),Qn.set(e,(Qn.get(e)||0)+1),gS(t)}function bS(e=Date.now()){return yS(e),{windowStart:Vs,total:Au(Qn),byCaller:Object.fromEntries(Qn),lastHour:Wr,backoffUntil:Do>e?Do:null}}function qr(e){return AB.test(String(e?.message||e||""))}function Kr(e,t=Date.now()){return Do<=t&&console.warn(`[github] rate limited \u2014 backing off ${dS/6e4} min:`,String(e?.message||e||"").slice(0,200)),Do=Math.max(Do,t+dS),Do}function Eu(e=Date.now()){return Math.max(0,Do-e)}var hS,Tu,wS,dS,TB,Vs,Qn,Wr,Do,pS,Au,fS,AB,Ni=q(()=>{hS=process.env.BOSTRAT_STATE_DIR||mS.join(process.env.HOME||SB.tmpdir(),".bostrat"),Tu=mS.join(hS,"github-metrics.json"),wS=60*6e4,dS=5*6e4,TB=6e4,Vs=Date.now(),Qn=new Map,Wr=null,Do=0,pS=0,Au=e=>[...e.values()].reduce((t,n)=>t+n,0);try{let e=JSON.parse(vB.readFileSync(Tu,"utf8"));e?.windowStart&&(Date.now()-e.windowStart<wS?(Vs=e.windowStart,Qn=new Map(Object.entries(e.byCaller||{})),Wr=e.lastHour||null):Au(new Map(Object.entries(e.byCaller||{})))&&(Wr={start:e.windowStart,total:Au(new Map(Object.entries(e.byCaller||{}))),byCaller:e.byCaller||{}}))}catch{}fS=Promise.resolve();AB=/rate limit|too quickly|abuse detection|HTTP 429/i});import kS from"node:fs/promises";import xS from"node:path";import EB from"node:os";function Iu({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};_u.push(l),_u.length>IB&&_u.shift();let u=jm.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)),jm.set(e,u),$B(l),l}async function $B(e){try{await kS.mkdir(vS,{recursive:!0}),await kS.appendFile(_B,JSON.stringify(e)+`
181
+ `)}catch{}}function SS(){let e={};for(let[t,n]of jm)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:_u.slice(-20)}}var vS,_B,IB,_u,jm,$u=q(()=>{vS=process.env.BOSTRAT_STATE_DIR||xS.join(process.env.HOME||EB.tmpdir(),".bostrat"),_B=xS.join(vS,"github-latency.ndjson"),IB=100,_u=[],jm=new Map});import{execFile as RB}from"node:child_process";import{promisify as OB}from"node:util";async function CB(e){let t=/workspaces[/\\]([0-9a-f]{8})(?:[/\\]|$)/.exec(e||"")?.[1];if(t)try{let[{stdout:n},{stdout:r}]=await Promise.all([Ys("git",["-C",e,"rev-parse","HEAD"]),Ys("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 yn({cwd:e});er(r);try{let{stdout:a}=await Ys("gh",t,{cwd:e,...MB,...o,env:{...process.env,...s,...o.env||{}}});return String(a||"")}catch(a){throw qr(a)&&Kr(a),a}}async function Um(){if(Ru&&Date.now()-Ru.at<6e4)return Ru.data;let e;try{er("auth");let t=await Ys("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 qa();t.configured&&(e={installed:!0,authenticated:!0,login:t.username,via:"broker"})}catch{}return Ru={at:Date.now(),data:e},e}async function NB(e){try{let{stdout:t}=await Ys("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});return/github\.com/.test(t)}catch{return!1}}function AS(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 Lm(e){let t=(e||[]).map(AS),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 Wm(e){return/Resource not accessible by personal access token/.test(String(e?.stderr||e?.message||""))}async function _S(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 IS(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 $S(e,t){let n=await _S(e,t);return n===null?{...Lm([]),unavailable:!0}:Lm(IS(n))}function Ou(e,t=Lm(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 DB(e,t,n){let r=new Set;for(let o of t){let s=`${e}#${o.number}`;if(o.mergeable!=="UNKNOWN"&&o.mergeStateStatus!=="UNKNOWN"){Js.delete(s);continue}r.add(s),Js.has(s)||Js.set(s,n),o.mergeabilityPending=n-Js.get(s)<PB}for(let o of Js.keys())o.startsWith(`${e}#`)&&!r.has(o)&&Js.delete(o);return t}async function Xs(e,t){let n=await tr(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",Hm]);return Ou(JSON.parse(o))}catch(o){if(!Wm(o))throw o;let s=await qt(n.path,["pr","view",String(r),"--json",ES]),a=JSON.parse(s);return Ou(a,await $S(n.path,a.headRefOid))}}async function En(e,{caller:t="prs"}={}){try{let n=await qt(e,["pr","list","--json",Hm,"--limit","50"],{caller:t});return JSON.parse(n||"[]").map(r=>Ou(r)).sort(TS)}catch(n){if(!Wm(n))throw n;let r=await qt(e,["pr","list","--json",ES,"--limit","50"],{caller:t});return(await Promise.all(JSON.parse(r||"[]").map(async o=>Ou(o,await $S(e,o.headRefOid))))).sort(TS)}}function Kt(){Pi.clear()}async function LB(e,t){if(!e)return t;for(let n of t){let r=await at(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 ku(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.ciFix={delegatedAt:r.ciFix.delegatedAt,trackId:r.ciFix.trackId??null}),r.reconcile&&(o(r.reconcile)?await vu(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.reconcile={delegatedAt:r.reconcile.delegatedAt,trackId:r.reconcile.trackId??null})}return t}async function RS(){let e=await Um();if(!e.authenticated)return{auth:e,repos:[]};let t=[];for(let a of await Wn())await NB(a.path)&&t.push(a);let n=Date.now(),r=Eu(n)>0,o=await Promise.all(t.map(async a=>{let i=Pi.get(a.path),c=i?.pending?jB:BB;if(i&&(r||n-i.at<c))return i.entry;try{let l=await _e(a.path).catch(()=>null),u=DB(a.path,await En(a.path,{caller:"tab"}),n);if(await LB(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&&Iu({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 Pi.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:_n(l)}}})),s=new Set(t.map(a=>a.path));for(let a of Pi.keys())s.has(a)||Pi.delete(a);return{auth:e,repos:o}}async function tr(e){let t=(await Wn()).find(n=>n.path===e);if(!t)throw new Error(`unknown repo: ${e}`);return t}async function Bo(e){return ms(e)}async function Zs(e,t,{method:n="squash"}={}){let r=await tr(e);if(!Di.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 yn({cwd:r.path})).GH_TOKEN){let a=await Mp().catch(()=>null);a&&s.push("--body",`Merged by bostrat on behalf of @${a}`)}try{await qt(r.path,s)}catch(a){throw new Error(_n(a))}finally{Kt()}return{ok:!0,number:o}}async function Bi(e,t){let n=await tr(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(_n(s))}finally{Kt()}let o=await _e(n.path).catch(()=>null);return o&&await rS(o,r).catch(()=>{}),{ok:!0,number:r}}async function qm(e,t){let n=await tr(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(_n(o))}finally{Kt()}return{ok:!0,number:r}}function Km(e){return e.green&&!e.isDraft}function WB(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 OS(e,{update:t=!0}={}){return e.isDraft?{action:"skip",reason:"draft"}:Km(e)?{action:"merge"}:t&&e.mergeStateStatus==="BEHIND"&&e.mergeable!=="CONFLICTING"&&e.checks.failed===0?{action:"update-arm"}:{action:"arm"}}function CS(e){return[...e.filter(t=>t.plan.action!=="merge"),...e.filter(t=>t.plan.action==="merge")]}function ji(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 MS(e){let t=new Map;for(let n of[...e].filter(r=>r?.autoMerge&&r?.trackId).sort(ji))t.has(n.trackId)||t.set(n.trackId,`${n.repo}#${n.number}`);return t}function NS(){let e={};for(let[t,n]of Fm)e[t]={...n};return e}async function PS(e,{method:t="merge",onMerged:n=null}={}){let r=await tr(e);if(!Di.has(t))throw new Error(`invalid merge method: ${t}`);if(Fm.get(r.path)?.running)throw new Error("a merge-all is already running for this repo");let o=(await En(r.path)).filter(Km).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 Fm.set(r.path,s),KB(s,o,{listPrs:()=>En(r.path),merge:a=>Zs(r.path,a,{method:t}),sleep:HB,onMerged:n}).catch(()=>{}),{ok:!0,repo:r.path,total:s.total,queue:o.map(a=>a.number)}}async function qB(e,t){let n=Date.now()+(t.settleMaxMs??UB),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(FB)}}async function KB(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 qB(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: ${_n(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(!Km(a)){e.skipped.push({number:a.number,title:a.title,reason:WB(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:_n(i)})}}}finally{e.current=null,e.running=!1,e.finishedAt=Date.now(),Kt()}}async function Gm(e,{title:t,body:n="",base:r=null}={}){if(typeof t!="string"||!t.trim())throw new Error("title required");try{await Ys("git",["-C",e,"push","-u","origin","HEAD"],{timeout:12e4,maxBuffer:4*1024*1024})}catch(l){throw new Error(`push failed: ${_n(l)}`)}await CB(e);let o=n||"";if((await yn({cwd:e})).GH_TOKEN){let l=await Mp().catch(()=>null);l&&(o=`${o?`${o}
182
182
 
183
- `:""}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(_n(l))}finally{Kt()}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 DS(e,t){let n=await tr(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(_n(c))}o=JSON.parse(i||"[]").filter(c=>c.bucket==="fail")}catch(i){if(!Hm(i))throw i;let c=await qt(n.path,["pr","view",String(r),"--json","headRefOid"]),l=await _S(n.path,JSON.parse(c).headRefOid);if(l===null)throw new Error(_n(i));o=IS(l).map(AS).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=Kj(i.link),l=null;c&&!s.has(c)&&(s.add(c),l=await qt(n.path,["run","view",c,"--log-failed"]).then(u=>Gj(u)).catch(()=>null)),a.push({name:i.name,link:i.link||null,log:l})}return a}function Kj(e){return String(e||"").match(/\/actions\/runs\/(\d+)/)?.[1]??null}function Gj(e,{maxLines:t=400,maxBytes:n=64*1024}={}){let r=String(e||""),o=r.split(`
183
+ `:""}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(_n(l))}finally{Kt()}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 DS(e,t){let n=await tr(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(_n(c))}o=JSON.parse(i||"[]").filter(c=>c.bucket==="fail")}catch(i){if(!Wm(i))throw i;let c=await qt(n.path,["pr","view",String(r),"--json","headRefOid"]),l=await _S(n.path,JSON.parse(c).headRefOid);if(l===null)throw new Error(_n(i));o=IS(l).map(AS).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=GB(i.link),l=null;c&&!s.has(c)&&(s.add(c),l=await qt(n.path,["run","view",c,"--log-failed"]).then(u=>zB(u)).catch(()=>null)),a.push({name:i.name,link:i.link||null,log:l})}return a}function GB(e){return String(e||"").match(/\/actions\/runs\/(\d+)/)?.[1]??null}function zB(e,{maxLines:t=400,maxBytes:n=64*1024}={}){let r=String(e||""),o=r.split(`
184
184
  `);return o.length>t&&(r=`\u2026 (${o.length-t} earlier lines truncated)
185
185
  `+o.slice(-t).join(`
186
186
  `)),Buffer.byteLength(r)>n&&(r=`\u2026 (truncated)
187
187
  `+r.slice(-n)),r}function _n(e){return String(e?.stderr||e?.message||e||"").trim().split(`
188
- `).find(n=>n.trim())||"gh failed"}var Ys,Cj,Ru,Um,ES,Nj,Js,TS,Dj,jj,Pi,Di,Lj,Fj,Uj,Lm,Bo=q(()=>{kr();pt();Zn();Ni();$u();de();Ys=Rj($j),Cj={timeout:3e4,maxBuffer:8*1024*1024};Ru=null;Um="number,title,url,headRefName,headRefOid,baseRefName,isDraft,author,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup,autoMergeRequest,additions,deletions,createdAt,updatedAt,state,mergedAt,closedAt",ES=Um.replace("statusCheckRollup,","");Nj=9e4,Js=new Map;TS=(e,t)=>e.number-t.number;Dj=3e4,jj=1500,Pi=new Map;Di=new Set(["squash","merge","rebase"]);Lj=2500,Fj=9e4,Uj=e=>new Promise(t=>setTimeout(t,e));Lm=new Map});import{execFile as zj}from"node:child_process";import{promisify as Vj}from"node:util";async function Yj(e,t){try{let{stdout:n}=await Jj("git",["-C",e,"rev-list","--count",t]);return Number(n.trim())||0}catch{return null}}async function Xj(e,t,n,{rebase:r=!1,listPrs:o=En}={}){let s=await Ii(e.dir,{ignorePlumbing:!0}).catch(()=>!1),a=await $i(e.dir,n).catch(()=>0),i=t?await Yj(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:Cu.filter(w=>p.includes(w)),defaults:Cu.filter(w=>f.includes(w))}}async function Mu(e,{branch:t,rebase:n=!1,listPrs:r=En}={}){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 Us(s[0].dir).catch(()=>!1))return null;let a=[];for(let p of s)a.push(await Xj(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=Cu.filter(p=>c.some(f=>f.available.includes(p))),u=Cu.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 Jj,Cu,Gm=q(()=>{uu();Bo();Jj=Vj(zj),Cu=["commit","rebase","push","pr"]});function Nu(e,t,n){let{state:r,reason:o}=Sf(t,n);if(r!=="unknown"){if(e){let a=Date.now();for(let[i,c]of Li)a-c.at>=jS()&&Li.delete(i);Li.set(e,{busy:r==="busy",at:a})}return r==="busy"}if(o!=="narrow"||!e)return!1;let s=Li.get(e);return s?Date.now()-s.at>=jS()?(Li.delete(e),!1):s.busy:!1}async function zm(e,t){let n={working:!1,prompted:!1};if(!e)return n;let r=await je(e,{lines:tt}).catch(()=>"");if(!Nu(e,t,r))return e0(t,r)?{working:!0,prompted:!1}:n;if(Ro(t,r)){let o=await Gn(e).catch(()=>r),s=Br({name:e,agent:t},o);if(s)return!cu({name:e,agent:t},s,o)||ov(e)?{working:!1,prompted:!0}:{working:!1,prompted:!1}}return{working:!0,prompted:!1}}async function Lo(e,t){return(await zm(e,t)).working}var jS,Li,Fi=q(()=>{ct();hi();mm();wm();jS=()=>Number(process.env.BOSTRAT_NARROW_CARRY_MS)||9e4,Li=new Map});import{execFile as Zj}from"node:child_process";import{promisify as Qj}from"node:util";async function Gr(e){if(!e)return null;let t=BS.get(e);if(t&&Date.now()-t.at<tB)return t.branch;let n=null;try{let{stdout:r}=await eB("git",["-C",e,"symbolic-ref","--short","-q","HEAD"],{timeout:5e3});n=r.trim()||null}catch{n=null}return BS.set(e,{at:Date.now(),branch:n}),n}function LS(e){return String(e||"").match(nB)?.[1]??null}function rB(e,t){let n=LS(e);return!!n&&!!t&&n===t}function FS(e,t){let n=LS(e);return!!n&&n!==t}function oB(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 Qs(e){let t=[],n=r=>{r&&!t.includes(r)&&t.push(r)};n(e?.workspace?.branch??null);for(let r of oB(e))n(await Gr(r));return t}async function Pu(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=>rB(t,a.id));if(s)return s;for(let a of r)if(!Ve(a)&&(await Qs(a)).includes(t))return a;return null}var eB,tB,BS,nB,Fo=q(()=>{An();eB=Qj(Zj),tB=5e3,BS=new Map;nB=/^track\/.+-([0-9a-f]{8})$/});import{execFile as sB}from"node:child_process";import{promisify as aB}from"node:util";function ea({trackId:e,boxId:t,epoch:n}){return`${e}/${t}/${Number.isFinite(Number(n))?Number(n):0}`}function ju(e){let t=/^([^/\s]+)\/([^/\s]+)\/(\d+)$/.exec(String(e||"").trim());return t?{trackId:t[1],boxId:t[2],epoch:Number(t[3])}:null}function Lu({trackId:e,boxId:t,epoch:n=0,provider:r=null,model:o=null}){let s=[],a=r?pB[r]:null;return a&&s.push(a),s.push(`${KS}: ${ea({trackId:e,boxId:t,epoch:n})}`),o&&s.push(`${GS}: ${String(o).trim()}`),s}function US(e){let t={epoch:null,model:null,provider:null,cause:null};for(let n of String(e||"").split(`
189
- `)){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===KS.toLowerCase()&&!t.epoch)t.epoch=ju(a);else if(s===GS.toLowerCase()&&!t.model)t.model=a;else if(s===zS.toLowerCase()&&!t.cause){let i=a.toLowerCase();Ui.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 fB(e,t=zr){return e<=t?"rework":"drift"}function mB(e,{window:t=zr,end:n=Zm}={}){return!Number.isFinite(e)||e<=t?1:e>=n?0:1-(e-t)/(n-t)}function Fu({subject:e="",trailerCause:t=null,wallReason:n=null,fixerCategory:r=null,ciFix:o=!1}={}){let s=String(e||"");return hB.test(s)?{cause:"defect",level:"A",basis:"revert"}:o?{cause:"defect",level:"A",basis:"ci-fix"}:t?{cause:t,level:"E",basis:`${zS} trailer`}:gB.test(s)&&!HS.test(s)?{cause:"style",level:"C",basis:"subject"}:HS.test(s)?{cause:"defect",level:"C",basis:"subject"}:wB.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 eh({heuristic:e=null,subject:t="",ref:n=null,promptKind:r=null,fixerCategory:o=null,ticketKind:s=null}={}){let a=String(t||""),i=yB.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&&bB.has(c)?{intent:"fix",basis:`subject prefix: ${c}:`}:c&&kB.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"}:WS.test(String(n||""))||WS.test(a)?{intent:"planned",basis:"blueprint item"}:o&&xB.has(o)?{intent:"planned",basis:`prompt: ${o}`}:{intent:"unknown",basis:null}}function AB(e){let t=String(e||"");return vB.some(n=>n.test(t))?"excluded":SB.some(n=>n.test(t))?"docs":TB.some(n=>n.test(t))?"config":"code"}function EB(e){let t=[],n=null,r=null;for(let o of String(e||"").split(`
190
- `)){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 _B(e,t){let n=Xm(e),r=Xm(t);if(n===r)return 1;if(!n.length||!r.length)return 0;n.length>Du&&(n=n.slice(0,Du)),r.length>Du&&(r=r.slice(0,Du));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 IB(e,t=VS){let n=new Set,r=e?.del||[],o=e?.add||[];for(let s=0;s<r.length;s++){let a=e.oldStart+s;if(!Xm(r[s]).length){n.add(a);continue}s<o.length&&_B(r[s],o[s])>=t&&n.add(a)}return n}function $B(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 RB(e){let t=new Map,n=null;for(let r of String(e||"").split(`
191
- `)){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 qS(e,t){let{stdout:n}=await Ym(e,["show","-s","--format=%H%n%P%n%ct%n%s%n%B",t]),[r,o,s,a,...i]=n.split(`
188
+ `).find(n=>n.trim())||"gh failed"}var Ys,MB,Ru,Hm,ES,PB,Js,TS,BB,jB,Pi,Di,FB,UB,HB,Fm,jo=q(()=>{kr();pt();Zn();Ni();$u();de();Ys=OB(RB),MB={timeout:3e4,maxBuffer:8*1024*1024};Ru=null;Hm="number,title,url,headRefName,headRefOid,baseRefName,isDraft,author,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup,autoMergeRequest,additions,deletions,createdAt,updatedAt,state,mergedAt,closedAt",ES=Hm.replace("statusCheckRollup,","");PB=9e4,Js=new Map;TS=(e,t)=>e.number-t.number;BB=3e4,jB=1500,Pi=new Map;Di=new Set(["squash","merge","rebase"]);FB=2500,UB=9e4,HB=e=>new Promise(t=>setTimeout(t,e));Fm=new Map});import{execFile as VB}from"node:child_process";import{promisify as JB}from"node:util";async function XB(e,t){try{let{stdout:n}=await YB("git",["-C",e,"rev-list","--count",t]);return Number(n.trim())||0}catch{return null}}async function ZB(e,t,n,{rebase:r=!1,listPrs:o=En}={}){let s=await Ii(e.dir,{ignorePlumbing:!0}).catch(()=>!1),a=await $i(e.dir,n).catch(()=>0),i=t?await XB(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:Cu.filter(w=>p.includes(w)),defaults:Cu.filter(w=>f.includes(w))}}async function Mu(e,{branch:t,rebase:n=!1,listPrs:r=En}={}){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 Us(s[0].dir).catch(()=>!1))return null;let a=[];for(let p of s)a.push(await ZB(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=Cu.filter(p=>c.some(f=>f.available.includes(p))),u=Cu.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 YB,Cu,zm=q(()=>{uu();jo();YB=JB(VB),Cu=["commit","rebase","push","pr"]});function Nu(e,t,n){let{state:r,reason:o}=Tf(t,n);if(r!=="unknown"){if(e){let a=Date.now();for(let[i,c]of Li)a-c.at>=BS()&&Li.delete(i);Li.set(e,{busy:r==="busy",at:a})}return r==="busy"}if(o!=="narrow"||!e)return!1;let s=Li.get(e);return s?Date.now()-s.at>=BS()?(Li.delete(e),!1):s.busy:!1}async function Vm(e,t){let n={working:!1,prompted:!1};if(!e)return n;let r=await Be(e,{lines:tt}).catch(()=>"");if(!Nu(e,t,r))return e0(t,r)?{working:!0,prompted:!1}:n;if(Ro(t,r)){let o=await Gn(e).catch(()=>r),s=jr({name:e,agent:t},o);if(s)return!cu({name:e,agent:t},s,o)||ov(e)?{working:!1,prompted:!0}:{working:!1,prompted:!1}}return{working:!0,prompted:!1}}async function Lo(e,t){return(await Vm(e,t)).working}var BS,Li,Fi=q(()=>{ct();hi();hm();gm();BS=()=>Number(process.env.BOSTRAT_NARROW_CARRY_MS)||9e4,Li=new Map});import{execFile as QB}from"node:child_process";import{promisify as ej}from"node:util";async function Gr(e){if(!e)return null;let t=jS.get(e);if(t&&Date.now()-t.at<nj)return t.branch;let n=null;try{let{stdout:r}=await tj("git",["-C",e,"symbolic-ref","--short","-q","HEAD"],{timeout:5e3});n=r.trim()||null}catch{n=null}return jS.set(e,{at:Date.now(),branch:n}),n}function LS(e){return String(e||"").match(rj)?.[1]??null}function FS(e,t){let n=LS(e);return!!n&&!!t&&n===t}function US(e,t){let n=LS(e);return!!n&&n!==t}function oj(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 Qs(e){let t=[],n=r=>{r&&!t.includes(r)&&t.push(r)};n(e?.workspace?.branch??null);for(let r of oj(e))n(await Gr(r));return t}async function Pu(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=>FS(t,a.id));if(s)return s;for(let a of r)if(!Ve(a)&&(await Qs(a)).includes(t))return a;return null}function sj(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 Du(e,{branch:t=null,repo:n=null,slug:r=null}={}){return FS(t,e?.id)?!0:sj(e,n,r)}var tj,nj,jS,rj,Fo=q(()=>{An();tj=ej(QB),nj=5e3,jS=new Map;rj=/^track\/.+-([0-9a-f]{8})$/});import{execFile as aj}from"node:child_process";import{promisify as ij}from"node:util";function ea({trackId:e,boxId:t,epoch:n}){return`${e}/${t}/${Number.isFinite(Number(n))?Number(n):0}`}function ju(e){let t=/^([^/\s]+)\/([^/\s]+)\/(\d+)$/.exec(String(e||"").trim());return t?{trackId:t[1],boxId:t[2],epoch:Number(t[3])}:null}function Fu({trackId:e,boxId:t,epoch:n=0,provider:r=null,model:o=null}){let s=[],a=r?fj[r]:null;return a&&s.push(a),s.push(`${GS}: ${ea({trackId:e,boxId:t,epoch:n})}`),o&&s.push(`${zS}: ${String(o).trim()}`),s}function HS(e){let t={epoch:null,model:null,provider:null,cause:null};for(let n of String(e||"").split(`
189
+ `)){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===GS.toLowerCase()&&!t.epoch)t.epoch=ju(a);else if(s===zS.toLowerCase()&&!t.model)t.model=a;else if(s===VS.toLowerCase()&&!t.cause){let i=a.toLowerCase();Ui.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 mj(e,t=zr){return e<=t?"rework":"drift"}function hj(e,{window:t=zr,end:n=Qm}={}){return!Number.isFinite(e)||e<=t?1:e>=n?0:1-(e-t)/(n-t)}function Uu({subject:e="",trailerCause:t=null,wallReason:n=null,fixerCategory:r=null,ciFix:o=!1}={}){let s=String(e||"");return wj.test(s)?{cause:"defect",level:"A",basis:"revert"}:o?{cause:"defect",level:"A",basis:"ci-fix"}:t?{cause:t,level:"E",basis:`${VS} trailer`}:yj.test(s)&&!WS.test(s)?{cause:"style",level:"C",basis:"subject"}:WS.test(s)?{cause:"defect",level:"C",basis:"subject"}:gj.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 th({heuristic:e=null,subject:t="",ref:n=null,promptKind:r=null,fixerCategory:o=null,ticketKind:s=null}={}){let a=String(t||""),i=bj.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&&kj.has(c)?{intent:"fix",basis:`subject prefix: ${c}:`}:c&&xj.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"}:qS.test(String(n||""))||qS.test(a)?{intent:"planned",basis:"blueprint item"}:o&&vj.has(o)?{intent:"planned",basis:`prompt: ${o}`}:{intent:"unknown",basis:null}}function Ej(e){let t=String(e||"");return Sj.some(n=>n.test(t))?"excluded":Tj.some(n=>n.test(t))?"docs":Aj.some(n=>n.test(t))?"config":"code"}function _j(e){let t=[],n=null,r=null;for(let o of String(e||"").split(`
190
+ `)){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 Ij(e,t){let n=Zm(e),r=Zm(t);if(n===r)return 1;if(!n.length||!r.length)return 0;n.length>Bu&&(n=n.slice(0,Bu)),r.length>Bu&&(r=r.slice(0,Bu));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 $j(e,t=JS){let n=new Set,r=e?.del||[],o=e?.add||[];for(let s=0;s<r.length;s++){let a=e.oldStart+s;if(!Zm(r[s]).length){n.add(a);continue}s<o.length&&Ij(r[s],o[s])>=t&&n.add(a)}return n}function Rj(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 Oj(e){let t=new Map,n=null;for(let r of String(e||"").split(`
191
+ `)){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 KS(e,t){let{stdout:n}=await Xm(e,["show","-s","--format=%H%n%P%n%ct%n%s%n%B",t]),[r,o,s,a,...i]=n.split(`
192
192
  `);return{sha:r.trim(),parents:o.trim()?o.trim().split(" "):[],ts:Number(s)*1e3,subject:a??"",message:i.join(`
193
- `)}}async function JS(e,t,{fixKey:n=null,window:r=zr,resolveOrigin:o=null,context:s={}}={}){let a=await qS(e,t);if(a.parents.length!==1)return null;let i=a.parents[0],c=US(a.message),l=n?ju(n):c.epoch,u=l?ea(l):null,{stdout:d}=await Ym(e,["diff","-U0","--no-color","-M","-C",i,t]),p=EB(d),f=0,w=0,m=0,g=0,b=0,x=0,y=0,$=new Map;for(let R of p){if(R.binary)continue;let G=R.oldPath||R.newPath||"",V=R.deleted.reduce((z,[,ue])=>z+ue,0),A=AB(G);if(A==="excluded"){m+=V;continue}if(A==="docs"){g+=V,b+=R.added;continue}if(A==="config"){x+=V;continue}f+=R.added;let _=new Set;for(let z of R.hunks||[])for(let ue of IB(z))_.add(ue);y+=_.size;let N=[];for(let[z,ue]of R.deleted)for(let pe=z;pe<z+ue;pe++)_.has(pe)||N.push(pe);if(w+=N.length,!R.oldPath||!N.length)continue;let U;try{let z=["blame","-w","-M","-C","--line-porcelain"];for(let[ue,pe]of $B(N))z.push("-L",`${ue},${ue+pe-1}`);z.push(i,"--",R.oldPath),U=RB((await Ym(e,z)).stdout)}catch{continue}for(let{sha:z,time:ue}of U.values()){let pe=$.get(z)??{lines:0,time:ue};pe.lines+=1,$.set(z,pe)}}let O=[],M=0,H=new Map;for(let[R,{lines:G,time:V}]of $){let A=H.get(R);if(!A){try{A=await qS(e,R)}catch{A=null}H.set(R,A)}let _=A?US(A.message):{epoch:null},N=_.epoch,U=_.provider,z=_.model;if(!N&&o){let W=await o(R,A);W?.trackId&&W?.boxId!=null&&(N={trackId:W.trackId,boxId:W.boxId,epoch:W.epoch??0},U=U??W.provider??null,z=z??W.model??null)}if(!N){M+=G;continue}let ue=Number.isFinite(V)?V:A?.ts??a.ts,pe=Math.max(0,(a.ts-ue)/lB),Se=ea(N),Ae=Se===u?"self":fB(pe,r);O.push({sha:R,key:Se,trackId:N.trackId,boxId:N.boxId,epoch:N.epoch,provider:U??null,model:z??null,lines:G,ageDays:Math.round(pe*100)/100,class:Ae,decay:Ae==="rework"?1:Ae==="drift"?Math.round(mB(pe,{window:r})*1e3)/1e3:0})}O.sort((R,G)=>G.lines-R.lines);let P=Fu({subject:a.subject,trailerCause:c.cause,wallReason:s.wallReason??null,fixerCategory:s.fixerCategory??null,ciFix:s.ciFix===!0}),E=eh({heuristic:P,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:y,docsDeleted:g,docsAdded:b,configDeleted:x,codeDelta:f+w+y>0,origins:O,unattributedLines:M,ghost:w===0&&f>0,heuristic:P,intent:E}}function YS(e,{minLines:t=Qm}={}){if(!e)return!1;let n=e.intent?.intent??"unknown";return ta.has(n)?Hi(e)>=t:!1}function Hi(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:sn(t),reworkChargedUsd:sn(e.reworkChargedUsd),reworkPendingUsd:sn(e.reworkPendingUsd),trueUsd:sn(t+e.reworkChargedUsd),multiplier:t>0?sn((t+e.reworkChargedUsd)/t):null}}function XS(e,{window:t=zr,boxMeta:n={}}={}){let r=e||[],o=r.filter(E=>E.type==="cost.recorded"),s=r.filter(E=>E.type==="code.committed"),a=r.filter(E=>E.type==="code.rework"),i=E=>Array.isArray(E?.shas)&&E.shas.length?E.shas:E?.sha?[E.sha]:[],c=new Map,l=new Set;for(let E of r)if(E.type==="rework.cause.offered")for(let R of i(E.payload))l.add(R);else if(E.type==="rework.cause.answered"&&E.payload?.cause)for(let R of i(E.payload))c.set(R,E.payload.cause);else if(E.type==="rework.cause.retracted")for(let R of i(E.payload))c.delete(R);let u={},d=(E,R,G)=>ea({trackId:E,boxId:R,epoch:G??0}),p=(E,R={})=>{if(!u[E]){let V=ju(E)||{};u[E]={key:E,...V,provider:null,model:null,...Vm()}}let G=u[E];return R.provider&&!G.provider&&(G.provider=R.provider),R.model&&!G.model&&(G.model=R.model),G};for(let E of o){if(!E.boxId)continue;let R=d(E.trackId,E.boxId,E.epoch),{usd:G,model:V}=Wt(E),A=p(R,{provider:E.provider,model:V!=="unknown"?V:null});A.genUsd+=G}let f=new Map;for(let E of s){let R=`${E.trackId}/${E.boxId}`;(f.get(R)??f.set(R,[]).get(R)).push({...E,ts:E.payload?.ts??E.ts})}for(let E of f.values())E.sort((R,G)=>R.ts-G.ts);let w=(E,R,G,V)=>{let A=f.get(`${E}/${R}`)||[],_=-1/0;for(let z of A)z.ts<V&&(_=z.ts);let N=0,U=0;for(let z of o)z.trackId!==E||z.boxId!==R||(z.epoch??0)===(G??0)&&(z.ts<=_||z.ts>V||(N+=Wt(z).usd,U++));return{usd:N,turns:U,from:Number.isFinite(_)?_: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},b={fix:0,"likely-fix":0,planned:0,unknown:0},x=0,y=[],$=[],O={},M={},H=new Set;for(let E of a){let R=E.payload||{};if(!R.sha||H.has(R.sha))continue;if(H.add(R.sha),R.codeDelta===!1){x++;continue}let G=ju(R.fixKey)||{trackId:E.trackId,boxId:E.boxId,epoch:E.epoch??0},{usd:V,turns:A}=w(G.trackId,G.boxId,G.epoch,R.ts??E.ts),_=dB.includes(R.intent?.intent)?R.intent.intent:"unknown";b[_]+=1;let N=null;c.has(R.sha)?N={cause:c.get(R.sha),level:"B",basis:"operator"}:(R.heuristic?.level&&R.heuristic.level!=="C"||R.heuristic)&&(N=R.heuristic);let U=N?.level??"none";g[U]=(g[U]||0)+1;let z=uB.has(U),ue=Number(R.deleted)||0,pe=Array.isArray(R.origins)?R.origins:[],Se=pe.filter(W=>W.class==="rework").reduce((W,te)=>W+te.lines,0),Ae={sha:R.sha,subject:R.subject??"",ts:R.ts??E.ts,trackId:E.trackId,fixKey:R.fixKey??null,fixProvider:R.fixProvider??E.provider??null,fixUsd:sn(V),fixTurns:A,linesReworked:Se,unattributedLines:Number(R.unattributedLines)||0,ghost:R.ghost===!0,intent:{intent:_,basis:R.intent?.basis??null},verdict:N?{cause:N.cause,level:U,basis:N.basis??null}:null,charged:sn(0),origins:[]};if(_==="planned"||N?.cause===Bu){m.planned+=V;for(let W of pe)W.class==="rework"&&Ae.origins.push({key:W.key,provider:W.provider??null,model:W.model??null,lines:W.lines,ageDays:W.ageDays,class:W.class,usd:0})}else if(R.ghost||ue===0)m.ghost+=V;else{let W=0;for(let ie of pe){let J=ie.lines/ue,ge=V*J;if(W+=ge,ie.class==="self"){m.self+=ge;continue}let Oe=ie.class==="rework"?1:Number(ie.decay)||0,Me=ge*Oe;if(m.decayed+=ge-Me,Me<=0)continue;let I=p(ie.key,{provider:ie.provider,model:ie.model});I.fixes+=1,I.linesReworked+=ie.class==="rework"?ie.lines:0;let j=N?.cause&&Ui.includes(N.cause)?N.cause:"unclassified";I.causes[j]+=1,z?(I.reworkChargedUsd+=Me,m.charged+=Me,Ae.charged=sn(Ae.charged+Me)):(I.reworkPendingUsd+=Me,m.pending+=Me),Ae.origins.push({key:ie.key,provider:I.provider,model:I.model,lines:ie.lines,ageDays:ie.ageDays,class:ie.class,usd:sn(Me)})}let te=Math.max(0,V-W);m.unattributed+=te}y.push(Ae),!c.has(R.sha)&&l.has(R.sha)&&$.push(R.sha)}for(let E of Object.values(u)){let R=E.provider||"unknown",G=E.model||"unknown",V=A=>{A.genUsd+=E.genUsd,A.reworkChargedUsd+=E.reworkChargedUsd,A.reworkPendingUsd+=E.reworkPendingUsd,A.linesReworked+=E.linesReworked,A.fixes+=E.fixes;for(let _ of Object.keys(A.causes))A.causes[_]+=E.causes[_]};V(O[R]||=Vm()),V(M[G]||=Vm())}y.sort((E,R)=>R.ts-E.ts);let P=Object.values(u).map(E=>{let R=n[`${E.trackId}/${E.boxId}`]||{};return Jm({...E,trackName:R.trackName??null,label:R.label??null})}).sort((E,R)=>R.reworkChargedUsd+R.reworkPendingUsd-(E.reworkChargedUsd+E.reworkPendingUsd)||R.genUsd-E.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${VS} 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:b,noCodeDelta:x,byEpoch:Object.fromEntries(P.map(E=>[E.key,E])),epochs:P,byProvider:Object.fromEntries(Object.entries(O).map(([E,R])=>[E,Jm(R)])),byModel:Object.fromEntries(Object.entries(M).map(([E,R])=>[E,Jm(R)])),buckets:Object.fromEntries(Object.entries(m).map(([E,R])=>[E,sn(R)])),fixUsdTotal:sn(Object.values(m).reduce((E,R)=>E+R,0)),fixes:y,verdicts:g,pendingTaps:$,commits:s.length}}var iB,cB,Ym,KS,GS,zS,lB,zr,Zm,Qm,Ui,Bu,uB,dB,ta,VS,pB,hB,HS,wB,gB,yB,bB,kB,WS,xB,vB,SB,TB,Xm,Du,sn,Vm,Uu=q(()=>{Pr();iB=aB(sB),cB=64*1024*1024,Ym=(e,t)=>iB("git",["-C",e,...t],{maxBuffer:cB,timeout:6e4}),KS="Bostrat-Epoch",GS="Bostrat-Model",zS="Bostrat-Fix-Cause",lB=24*36e5,zr=Number(process.env.BOSTRAT_REWORK_WINDOW_DAYS)||21,Zm=90,Qm=3,Ui=Object.freeze(["defect","design","requirements","style"]),Bu="not-a-fix",uB=new Set(["A","B","E"]),dB=Object.freeze(["fix","likely-fix","planned","unknown"]),ta=new Set(["fix","likely-fix"]),VS=.8;pB={claude:"Co-Authored-By: Claude <noreply@anthropic.com>",codex:"Co-authored-by: Codex <noreply@openai.com>",cursor:"Made-with: Cursor"};hB=/^revert\b|^revert "/i,HS=/\b(fix(es|ed)?|bug|hotfix|regression|crash|broken|npe|null ?pointer|off[- ]by[- ]one|leak)\b/i,wB=/\b(refactor|rearchitect|re-architect|restructure|rework|rewrite|redesign|simplif(y|ied)|clean ?up)\b/i,gB=/\b(lint|format(ting)?|prettier|typo|whitespace|rename)\b/i;yB=/^([a-z]+)(\([^)]*\))?!?:\s/i,bB=new Set(["fix","hotfix","bugfix","revert"]),kB=new Set(["feat","feature","docs","doc","test","tests","build","ci","chore"]),WS=/\bBP-[A-Z]*\d+\b/i,xB=new Set(["feature-build","docs-writing","research","design","ops-infra","orchestration"]);vB=[/(^|\/)\.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)\//],SB=[/\.(md|mdx|markdown|rst|txt|adoc|asciidoc)$/i,/(^|\/)(docs?|notes|business|design)\//i,/(^|\/)(README|CHANGELOG|CHANGES|LICENSE|CONTRIBUTING|AUTHORS|NOTICE)(\.[a-z]+)?$/i],TB=[/\.(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(),Du=400;sn=e=>Math.round(e*1e4)/1e4,Vm=()=>({genUsd:0,reworkChargedUsd:0,reworkPendingUsd:0,linesReworked:0,fixes:0,causes:{defect:0,design:0,requirements:0,style:0,unclassified:0}})});import{execFile as OB}from"node:child_process";import{promisify as CB}from"node:util";function ZS(e,t=Date.now()){return jp(e,t)??0}function NB(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 QS(e,t,{now:n=Date.now()}={}){let r=ZS(t,n),o=await K(e);return Lu({trackId:e.id,boxId:t.name,epoch:r,provider:t.agent??null,model:NB(o,t.name,r)})}function PB(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 DB(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=PB(n,t.name),c=i?zn(i.text)?.category??null:null;return{wallReason:a,fixerCategory:c,promptKind:i?.kind??null}}async function jB(e,t){try{let{stdout:n}=await th(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 BB(e){try{let{stdout:t}=await th(e,["rev-parse","--abbrev-ref","HEAD"]);return t.trim()||null}catch{return null}}async function eT(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 K(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 th(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=ZS(t,i),l=await jB(r,n),u=await BB(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 JS(r,n,{fixKey:ea({trackId:e.id,boxId:t.name,epoch:c}),window:zr,context:{...DB(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)&&YS(w))){let g=Hi(w),b=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:b.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 nT(e,t,n){if(!Ui.includes(n)&&n!==Bu)throw new Error(`bad cause "${n}" (${Ui.join("|")}|${Bu})`);let r=await K(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 rT(e,t){let n=await K(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 Hu(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 K(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 y of Array.isArray(x.payload?.shas)?x.payload.shas:[x.payload?.sha])y&&l.add(y);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=eh({heuristic:Fu({subject:r}),subject:r,ref:o}),p=[];for(let x of c){if(x.type!=="code.rework")continue;let y=x.payload||{};if(!y.sha||l.has(y.sha)||y.codeDelta===!1||o&&u.has(y.sha)&&u.get(y.sha)!==o)continue;let $=y.intent?.intent??"unknown";(ta.has($)||$==="unknown"&&ta.has(d.intent))&&Hi(y)!==0&&p.push(y)}let f=p.reduce((x,y)=>x+Hi(y),0);if(f<Qm)return{offered:!1,reason:"below-threshold"};let w=new Map;for(let x of p)for(let y of x.origins??[]){if(y.class!=="rework")continue;let $=w.get(y.key)??{key:y.key,provider:y.provider??null,model:y.model??null,lines:0,ageDays:y.ageDays};$.lines+=y.lines,$.ageDays=Math.min($.ageDays,y.ageDays),w.set(y.key,$)}let m=p.map(x=>x.sha),g=p.map(x=>x.heuristic).find(x=>x&&x.level!=="C")??Fu({subject:r})??p.map(x=>x.heuristic).find(Boolean)??null,b=ta.has(d.intent)?d:p.find(x=>ta.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,y)=>y.lines-x.lines).slice(0,3),heuristic:g,intent:b,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 MB,th,Wu=q(()=>{de();Gl();Uu();MB=CB(OB),th=(e,t)=>MB("git",["-C",e,...t],{maxBuffer:16*1024*1024,timeout:3e4})});import{execFile as LB}from"node:child_process";import{promisify as FB}from"node:util";async function nh(e,t,{midTurn:n=Lo,pollMs:r=UB,capMs:o=HB}={}){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 lT(e){let t=String(e||""),n=0;for(let r=0;r<64;r++){oT.lastIndex=n;let o=oT.exec(t);if(!o)break;n=o.index+o[0].length;let s=o[1]==="-",a=o[2]??o[3]??o[4],i=t.indexOf(`
194
- `,o.index);if(i<0)break;let l=new RegExp("^"+(s?"\\t*":"")+JB(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 rh(e,t){return e.slice(t).replace(/^[\s;&|)]+/,"").replace(/"[^"]*"|'[^']*'/g,'""').split(/[;&|\n]/)[0]}function dT(e){let t=lT(e),n=t.match(GB);if(!n)return null;let r=rh(t,n.index);return VB.test(r)?null:{repo:r.match(uT)?.[1]??null,head:r.match(YB)?.[1]??null}}function pT(e){let t=lT(e),n=t.match(zB);if(!n)return null;let r=rh(t,n.index),o=rh(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("-")){ZB.has(c)&&i++;continue}s=c.replace(/^["']+|["']+$/g,"")||null;break}return{repo:r.match(uT)?.[1]??null,selector:s,auto:/\s--auto\b/.test(r)}}async function eL(e,t,{exclude:n=()=>!1}={}){let r=async i=>{er("observer");let{stdout:c}=await sT("gh",["pr","list","--repo",e,"--author","@me","--state","all","--limit","10","--json",QB],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...i}}).catch(l=>{throw qr(l)&&Kr(l),l});return JSON.parse(c||"[]")},o=i=>(i||[]).filter(c=>Date.parse(c.createdAt)>=t-WB&&!n(c)),s=await yn({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 tL(e,t){if(t)return[t];let n=[];for(let r of fT(e)){let o=await _e(r).catch(()=>null);o&&!n.includes(o)&&n.push(o)}for(let r of await Wn().catch(()=>[])){let o=await _e(r.path).catch(()=>null);o&&!n.includes(o)&&n.push(o)}return n}function fT(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 nL(e,t,n){let r=await Qs(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)||XB(c.headRefName,e.id),i=[];for(let c of await tL(e,t?.repo??null)){let l;try{l=await eL(c,n,{exclude:a})}catch{continue}for(let u of l){let d=await at(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 mT(){for(let e of[...oh])e()}function hT(e,t,{delays:n=aT,turnEnd:r}={}){let o=dT(t.command);if(!o)return null;let s=!!pT(t.command),a=`${e.id}|${t.id??t.ts??t.command}`;if(Vr.has(a))return null;Vr.add(a);let i=t.ts??Date.now(),c=(async()=>{try{for(let l of n){await new Promise(m=>{let g=()=>{clearTimeout(b),oh.delete(g),m()},b=setTimeout(g,l);oh.add(g)});let u=await nL(e,o,i).catch(()=>null);if(u?.settled)return null;if(!u)continue;let{slug:d,pr:p}=u,{link:f,created:w}=await Ct({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 Yn(d,p.number))?null:(await nh(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{Vr.delete(a)}})();return c.catch(()=>Vr.delete(a)),c}function wT(e,t,{delays:n=aT,turnEnd:r,openedWait:o}={}){let s=pT(t.command);if(!s)return null;let a=`merge|${e.id}|${t.id??t.ts??t.command}`;if(Vr.has(a))return null;Vr.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=fT(e);if(w.length>1&&/^\d+$/.test(String(s.selector??"")))return null;for(let m of w){let g=await _e(m).catch(()=>null);g&&!d.includes(g)&&d.push(g)}}if(l||=(await Qs(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 at(c,w.number);return g&&g.trackId!==e.id?null:(g||await Ct({repo:c,number:w.number,trackId:e.id,url:w.url,headRef:w.headRefName,title:w.title,source:"merge-observed"}),await Ci(c,w.number),m&&((await K(e).catch(()=>[])).some(y=>y.type==="pr.state.changed"&&(y.payload?.change==="auto-armed"||y.payload?.change==="merged")&&y.payload?.number===w.number)||(await nh(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(M=>setTimeout(M,w));let m=[];for(let M of d)try{er("observer");let{stdout:H}=await sT("gh",["pr","view",String(l),"--repo",M,"--json",rL],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...await yn({slug:M})}}),P=JSON.parse(H||"null");P?.number&&m.push({slug:M,pr:P})}catch(H){qr(H)&&Kr(H)}let g=m.find(M=>M.pr.state==="MERGED")??(m.length===1?m[0]:null);if(!g)continue;c=g.slug;let b=g.pr;if(!b?.number)continue;if(b.state==="CLOSED")return null;if(b.state!=="MERGED"){if(f=b,s.auto)return p(b,!0);continue}let x=await at(c,b.number);if(x&&x.trackId!==e.id)return null;x||await Ct({repo:c,number:b.number,trackId:e.id,url:b.url,headRef:b.headRefName,title:b.title,source:"merge-observed"}),await nh(t.box,t.agent,r);let y=await K(e).catch(()=>[]);if(y.some(M=>M.type==="pr.state.changed"&&M.payload?.change==="merged"&&M.payload?.number===b.number))return null;let $=M=>M.some(H=>H.type==="pr.state.changed"&&H.payload?.change==="opened"&&H.payload?.number===b.number),O=0;if(!$(y)){if(dT(t.command)&&await Yn(c,b.number)){let M=Date.now();O=M+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:M,change:"opened",number:b.number,url:b.url,title:b.title,branch:b.headRefName,repo:c,selfMerge:!0}})}else if((await at(c,b.number))?.announced){let M=o?.capMs??qB,H=o?.pollMs??KB,P=Date.now()+M;for(;Date.now()<P&&(await new Promise(E=>setTimeout(E,H)),!$(await K(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(),O),change:"merged",number:b.number,url:b.url,title:b.title,branch:b.headRefName,repo:c}}),await Hu(e,{repo:c,number:b.number,title:b.title,branch:b.headRefName,url:b.url}).catch(()=>{}),await rr(c,b.number).catch(()=>{}),await nr(c,b.number).catch(()=>{}),await Hr(c,b.number,"merged"),b}return f?p(f,!1):null}finally{Vr.delete(a)}})();return i.catch(()=>Vr.delete(a)),i}var sT,aT,UB,HB,WB,qB,KB,iT,cT,GB,zB,VB,oT,JB,uT,YB,XB,ZB,QB,Vr,oh,rL,sh=q(()=>{de();kr();pt();Ni();Zn();or();Fi();Fo();Wu();sT=FB(LB),aT=[4e3,15e3,45e3],UB=2500,HB=5*6e4;WB=15e3,qB=9e4,KB=2e3,iT=/(?:^|[;&|\n({`]\s*|\)\s*)(?:(?:then|do|else|elif|if|while|until|time)\s+)?/.source,cT=/gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+/.source,GB=new RegExp(`${iT}${cT}create\\b`),zB=new RegExp(`${iT}${cT}merge\\b`),VB=/\s--web\b/,oT=/<<(-?)\s*(?:'([^'\n]+)'|"([^"\n]+)"|\\?([A-Za-z_][\w-]*))/g,JB=e=>e.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");uT=/(?:--repo|-R)[\s=]+([\w.-]+\/[\w.-]+)/,YB=/(?:--head|-H)[\s=]+([^\s"'`;&|]+)/,XB=FS;ZB=new Set(["--subject","-t","--body","-b","--body-file","-F","--match-head-commit","--author-email","-A","--repo","-R"]);QB="number,url,title,headRefName,createdAt";Vr=new Set,oh=new Set;rL="number,url,title,headRefName,state"});import oL from"node:fs/promises";import ih from"node:path";import sL from"node:os";function ah(e,t){let n=new RegExp(`\\b${t}="([^"]*)"`).exec(e);return n?n[1]:null}function qu(e){let t=aL.exec(String(e||""));if(!t)return null;let[,n,r]=t,o=ah(n,"from"),s=o?o.replace(/^uds:/,""):null,a=gT(s);return{socket:s,pid:a,name:ah(n,"from-name"),mode:ah(n,"from-mode"),text:r.trim()}}function gT(e){let t=/(\d+)\.sock$/.exec(String(e||""));return t?Number(t[1]):null}function iL(){return process.env.CLAUDE_CONFIG_DIR?ih.join(process.env.CLAUDE_CONFIG_DIR,"sessions"):ih.join(sL.homedir(),".claude","sessions")}async function cL(e){let t=gT(e);if(!t)return null;try{let n=await oL.readFile(ih.join(iL(),`${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 yT(e,t){let n=await cL(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 aL,ch=q(()=>{aL=/<cross-session-message\b([^>]*)>([\s\S]*?)<\/cross-session-message>/});function lh(e=process.env){return!!($e(e)&&e.BOSTRAT_PLANE_TOKEN)}async function uh({loopId:e,outcome:t,note:n=null,env:r=process.env}={}){if(!lh(r))return{ok:!1,source:"unconfigured"};let o=new AbortController,s=setTimeout(()=>o.abort(),bT);try{let a=await kT(`${$e(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 xT(e,{provider:t=null,cls:n="other",status:r=null,text:o=""}={},{env:s=process.env,now:a=Date.now}={}){if(!e?.id||!String(e.name||"").startsWith("\u21BB"))return{ok:!1,source:"not-a-loop-track"};if(!lh(s))return{ok:!1,source:"unconfigured"};let i=Ku.get(e.id)||0;if(a()-i<lL)return{ok:!1,source:"debounced"};Ku.set(e.id,a());let c=await Wi({env:s}),l=c.loops.find(p=>p.trackId===e.id);if(!l)return Ku.delete(e.id),{ok:!1,source:c.source==="plane"?"no-loop":c.source};let u=`${t||"provider"} ${r?r+" ":""}${n}: ${String(o||"").replace(/\s+/g," ").trim()}`.slice(0,500),d=await uh({loopId:l.id,outcome:"errored",note:u,env:s});return d.ok||Ku.delete(e.id),{...d,loop:{id:l.id,name:l.name}}}async function Wi({env:e=process.env}={}){if(!lh(e))return{loops:[],source:"unconfigured"};let t=new AbortController,n=setTimeout(()=>t.abort(),bT);try{let r=await kT(`${$e(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 bT,kT,lL,Ku,dh=q(()=>{pt();bT=1e4,kT=(...e)=>fetch(...e);lL=10*6e4,Ku=new Map});function vT(e=process.env){return!!($e(e)&&e.BOSTRAT_PLANE_TOKEN)}async function ST(e,t,n=ph){let r=new AbortController,o=setTimeout(()=>r.abort(),n);try{return await dL(`${$e(t)}${e}`,{headers:pL(t),signal:r.signal})}finally{clearTimeout(o)}}async function qi({env:e=process.env,force:t=!1,timeoutMs:n=ph}={}){if(!vT(e))return{followups:[],source:"unconfigured"};if(!t&&Uo&&Date.now()-Uo.at<uL)return{followups:Uo.followups,source:"cache"};try{let r=await ST("/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 Uo={at:Date.now(),followups:s},{followups:s,source:"plane"}}catch(r){return Uo?{followups:Uo.followups,source:"stale",error:r?.message}:{followups:[],source:"unreachable",error:r?.message}}}async function TT(e,{env:t=process.env,timeoutMs:n=ph}={}){if(!e)return{followup:null,source:"unconfigured"};if(!vT(t))return{followup:null,source:"unconfigured"};try{let r=await ST(`/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=Uo?.followups.find(s=>s.id===e)??null;return o?{followup:o,source:"stale",error:r?.message}:{followup:null,source:"unreachable",error:r?.message}}}var uL,ph,Uo,dL,pL,AT=q(()=>{pt();uL=6e4,ph=5e3,Uo=null,dL=(...e)=>fetch(...e);pL=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});async function Jr(e,t){if(fh.has(e)){let n=new Error("offer already answered (answer in flight)");throw n.code="answer-in-flight",n}fh.add(e);try{return await t()}finally{fh.delete(e)}}var fh,Ki=q(()=>{fh=new Set});import{randomUUID as ra,createHash as fL}from"node:crypto";function $T(e){return String(e||"").toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}function yL(e){for(let[t,n]of gL)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 RT(e,{standing:t=!1}={}){let n=e&&typeof e=="object"?e:{},r=na(n.label).replace(/\s+/g," ");if(!r)throw new Error('label required (\u226460 chars, e.g. "Deploy to Pi")');if(r.length>ET)throw new Error(`label must be \u2264${ET} characters`);let o=na(n.trigger)||(n.ship?"now":""),s=t?hL:IT.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"?kL(n.ship):null,i=na(n.prompt);if(!a&&!i)throw new Error("prompt required \u2014 the full instruction a fresh session could execute");if(Buffer.byteLength(i,"utf8")>_T)throw new Error(`prompt must be \u2264${_T} bytes`);if(t){let u=yL(i);if(u)throw new Error(u)}let c=na(n.why).slice(0,mL)||null,l=t?bL(n.repo):null;return{label:r,prompt:i,trigger:o,why:c,...l?{repo:l}:{},...a?{ship:a}:{}}}function bL(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 kL(e){let t=e&&typeof e=="object"?e:{},n=Array.isArray(t.actions)?t.actions.map(i=>String(i).trim().toLowerCase()):mh.slice();for(let i of n)if(!mh.includes(i))throw new Error(`ship.actions may only contain ${mh.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=na(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=>na(i)).filter(Boolean),a.length||(a=null)}return{actions:[...new Set(n)],rebase:r,toPr:o,base:s,repos:a}}function Gu(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 OT(e,t,{pull:n=qi,ship:r={}}={}){if(gh(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=RT(t);if(o.ship)return{kind:"ship",...await TL(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=ra(),b=ra();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:b,trigger:"now",repo:e.workspace?.repo||null,context:{},rows:[{armId:g,label:o.label,prompt:o.prompt,promptHash:hh(o.prompt),origin:"agent",why:o.why}]}}),{kind:"now",armId:g,offerId:b,...o}}let c=e.workspace?.repo||null,{followups:l}=await n().catch(()=>({followups:[]})),u=$T(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 K(s),f=Gu(p,{trigger:o.trigger}),w=f.length?f[f.length-1].armId:null,m=ra();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 CT(e,t){if(!t)throw new Error("armId required");let n={id:e.id,cwd:e.cwd},r=await K(n);if(!Gu(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 MT(e,t,{pull:n=qi}={}){if(gh(e))throw new Error("propose from a lead Track, not a loop's run Track");let r=RT(t,{standing:!0}),o=r.repo??e.workspace?.repo??null,s={id:e.id,cwd:e.cwd};if((await K(s)).reduce((g,b)=>b.type==="followup.create.offered"?b.payload?.proposalId??g:b.type==="followup.create.answered"&&b.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=$T(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}" (${wh[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=ra(),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 NT(e,t,n,{followupId:r=null}={}){if(!t)throw new Error("proposalId required");let o={id:e.id,cwd:e.cwd},s=await K(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 Gi(e,t,n={},{pull:r=qi}={}){if(!e||gh(e))return null;let o={id:e.id,cwd:e.cwd},s=await K(o).catch(()=>[]),a=n.repo??e.workspace?.repo??null;if(t==="pr.merged"){let p=m=>{let g=(m?.prs||[]).filter(b=>Number.isFinite(Number(b?.number))).map(b=>`${b?.repo??m?.repo??""}#${Number(b.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=Gu(s,{trigger:t}).map(p=>({armId:p.armId,label:p.label,prompt:p.prompt,promptHash:hh(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:xL(f.prompt),promptHash:hh(f.prompt),origin:f.origin,repo:f.repo??null}))}let l=[...i,...c].slice(0,wL);if(!l.length)return null;let u=ra(),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 vL(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 PT(e,{offerId:t,followupId:n=null,armId:r=null,promoted:o=null}={},s={}){if(!t)throw new Error("offerId required");return Jr(`fu:${e.id}:${t}`,()=>SL(e,{offerId:t,followupId:n,armId:r,promoted:o},s))}async function SL(e,{offerId:t,followupId:n,armId:r,promoted:o},s){let{sayToLead:a,unarchiveTrack:i,getFollowup:c=TT}=s,l={id:e.id,cwd:e.cwd},u=await K(l),d=u.find(y=>y.type==="followup.offered"&&y.payload?.offerId===t);if(!d)throw new Error("unknown offer");if(u.some(y=>y.type==="followup.answered"&&y.payload?.offerId===t))throw new Error("offer already answered");let p=d.payload.rows||[],f=y=>C(l,{type:"followup.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,...y}});if(!n&&!r)return await f({action:"dismiss",followupIds:p.map(y=>y.followupId).filter(Boolean),armIds:p.map(y=>y.armId).filter(Boolean)}),{offerId:t,action:"dismiss"};let w=null,m=null;if(n){if(!p.some(O=>O.followupId===n))throw new Error("that follow-up is not on this card");let{followup:y,source:$}=await c(n);if($==="unreachable")throw new Error("plane unreachable \u2014 the follow-up's current prompt can't be read; try again shortly");if(!y||y.status!=="active"){await f({action:"removed",followupId:n});let O=new Error("removed in Settings since it was offered");throw O.code="removed",O}w=y.prompt,m=y.label}else{let y=p.find(O=>O.armId===r);if(!y)throw new Error("that arm is not on this card");if(w=u.find(O=>O.type==="followup.armed"&&O.payload?.armId===r)?.payload?.prompt??y.prompt,m=y.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 b=`${vL(d.payload)}
193
+ `)}}async function YS(e,t,{fixKey:n=null,window:r=zr,resolveOrigin:o=null,context:s={}}={}){let a=await KS(e,t);if(a.parents.length!==1)return null;let i=a.parents[0],c=HS(a.message),l=n?ju(n):c.epoch,u=l?ea(l):null,{stdout:d}=await Xm(e,["diff","-U0","--no-color","-M","-C",i,t]),p=_j(d),f=0,w=0,m=0,g=0,b=0,x=0,y=0,$=new Map;for(let R of p){if(R.binary)continue;let G=R.oldPath||R.newPath||"",V=R.deleted.reduce((z,[,ue])=>z+ue,0),A=Ej(G);if(A==="excluded"){m+=V;continue}if(A==="docs"){g+=V,b+=R.added;continue}if(A==="config"){x+=V;continue}f+=R.added;let _=new Set;for(let z of R.hunks||[])for(let ue of $j(z))_.add(ue);y+=_.size;let N=[];for(let[z,ue]of R.deleted)for(let pe=z;pe<z+ue;pe++)_.has(pe)||N.push(pe);if(w+=N.length,!R.oldPath||!N.length)continue;let U;try{let z=["blame","-w","-M","-C","--line-porcelain"];for(let[ue,pe]of Rj(N))z.push("-L",`${ue},${ue+pe-1}`);z.push(i,"--",R.oldPath),U=Oj((await Xm(e,z)).stdout)}catch{continue}for(let{sha:z,time:ue}of U.values()){let pe=$.get(z)??{lines:0,time:ue};pe.lines+=1,$.set(z,pe)}}let O=[],M=0,H=new Map;for(let[R,{lines:G,time:V}]of $){let A=H.get(R);if(!A){try{A=await KS(e,R)}catch{A=null}H.set(R,A)}let _=A?HS(A.message):{epoch:null},N=_.epoch,U=_.provider,z=_.model;if(!N&&o){let W=await o(R,A);W?.trackId&&W?.boxId!=null&&(N={trackId:W.trackId,boxId:W.boxId,epoch:W.epoch??0},U=U??W.provider??null,z=z??W.model??null)}if(!N){M+=G;continue}let ue=Number.isFinite(V)?V:A?.ts??a.ts,pe=Math.max(0,(a.ts-ue)/uj),Se=ea(N),Ae=Se===u?"self":mj(pe,r);O.push({sha:R,key:Se,trackId:N.trackId,boxId:N.boxId,epoch:N.epoch,provider:U??null,model:z??null,lines:G,ageDays:Math.round(pe*100)/100,class:Ae,decay:Ae==="rework"?1:Ae==="drift"?Math.round(hj(pe,{window:r})*1e3)/1e3:0})}O.sort((R,G)=>G.lines-R.lines);let P=Uu({subject:a.subject,trailerCause:c.cause,wallReason:s.wallReason??null,fixerCategory:s.fixerCategory??null,ciFix:s.ciFix===!0}),E=th({heuristic:P,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:y,docsDeleted:g,docsAdded:b,configDeleted:x,codeDelta:f+w+y>0,origins:O,unattributedLines:M,ghost:w===0&&f>0,heuristic:P,intent:E}}function XS(e,{minLines:t=eh}={}){if(!e)return!1;let n=e.intent?.intent??"unknown";return ta.has(n)?Hi(e)>=t:!1}function Hi(e){return(e?.origins||[]).filter(t=>t.class==="rework").reduce((t,n)=>t+n.lines,0)}function Ym(e){let t=e.genUsd;return{...e,genUsd:sn(t),reworkChargedUsd:sn(e.reworkChargedUsd),reworkPendingUsd:sn(e.reworkPendingUsd),trueUsd:sn(t+e.reworkChargedUsd),multiplier:t>0?sn((t+e.reworkChargedUsd)/t):null}}function ZS(e,{window:t=zr,boxMeta:n={}}={}){let r=e||[],o=r.filter(E=>E.type==="cost.recorded"),s=r.filter(E=>E.type==="code.committed"),a=r.filter(E=>E.type==="code.rework"),i=E=>Array.isArray(E?.shas)&&E.shas.length?E.shas:E?.sha?[E.sha]:[],c=new Map,l=new Set;for(let E of r)if(E.type==="rework.cause.offered")for(let R of i(E.payload))l.add(R);else if(E.type==="rework.cause.answered"&&E.payload?.cause)for(let R of i(E.payload))c.set(R,E.payload.cause);else if(E.type==="rework.cause.retracted")for(let R of i(E.payload))c.delete(R);let u={},d=(E,R,G)=>ea({trackId:E,boxId:R,epoch:G??0}),p=(E,R={})=>{if(!u[E]){let V=ju(E)||{};u[E]={key:E,...V,provider:null,model:null,...Jm()}}let G=u[E];return R.provider&&!G.provider&&(G.provider=R.provider),R.model&&!G.model&&(G.model=R.model),G};for(let E of o){if(!E.boxId)continue;let R=d(E.trackId,E.boxId,E.epoch),{usd:G,model:V}=Wt(E),A=p(R,{provider:E.provider,model:V!=="unknown"?V:null});A.genUsd+=G}let f=new Map;for(let E of s){let R=`${E.trackId}/${E.boxId}`;(f.get(R)??f.set(R,[]).get(R)).push({...E,ts:E.payload?.ts??E.ts})}for(let E of f.values())E.sort((R,G)=>R.ts-G.ts);let w=(E,R,G,V)=>{let A=f.get(`${E}/${R}`)||[],_=-1/0;for(let z of A)z.ts<V&&(_=z.ts);let N=0,U=0;for(let z of o)z.trackId!==E||z.boxId!==R||(z.epoch??0)===(G??0)&&(z.ts<=_||z.ts>V||(N+=Wt(z).usd,U++));return{usd:N,turns:U,from:Number.isFinite(_)?_: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},b={fix:0,"likely-fix":0,planned:0,unknown:0},x=0,y=[],$=[],O={},M={},H=new Set;for(let E of a){let R=E.payload||{};if(!R.sha||H.has(R.sha))continue;if(H.add(R.sha),R.codeDelta===!1){x++;continue}let G=ju(R.fixKey)||{trackId:E.trackId,boxId:E.boxId,epoch:E.epoch??0},{usd:V,turns:A}=w(G.trackId,G.boxId,G.epoch,R.ts??E.ts),_=pj.includes(R.intent?.intent)?R.intent.intent:"unknown";b[_]+=1;let N=null;c.has(R.sha)?N={cause:c.get(R.sha),level:"B",basis:"operator"}:(R.heuristic?.level&&R.heuristic.level!=="C"||R.heuristic)&&(N=R.heuristic);let U=N?.level??"none";g[U]=(g[U]||0)+1;let z=dj.has(U),ue=Number(R.deleted)||0,pe=Array.isArray(R.origins)?R.origins:[],Se=pe.filter(W=>W.class==="rework").reduce((W,te)=>W+te.lines,0),Ae={sha:R.sha,subject:R.subject??"",ts:R.ts??E.ts,trackId:E.trackId,fixKey:R.fixKey??null,fixProvider:R.fixProvider??E.provider??null,fixUsd:sn(V),fixTurns:A,linesReworked:Se,unattributedLines:Number(R.unattributedLines)||0,ghost:R.ghost===!0,intent:{intent:_,basis:R.intent?.basis??null},verdict:N?{cause:N.cause,level:U,basis:N.basis??null}:null,charged:sn(0),origins:[]};if(_==="planned"||N?.cause===Lu){m.planned+=V;for(let W of pe)W.class==="rework"&&Ae.origins.push({key:W.key,provider:W.provider??null,model:W.model??null,lines:W.lines,ageDays:W.ageDays,class:W.class,usd:0})}else if(R.ghost||ue===0)m.ghost+=V;else{let W=0;for(let ie of pe){let J=ie.lines/ue,ge=V*J;if(W+=ge,ie.class==="self"){m.self+=ge;continue}let Oe=ie.class==="rework"?1:Number(ie.decay)||0,Me=ge*Oe;if(m.decayed+=ge-Me,Me<=0)continue;let I=p(ie.key,{provider:ie.provider,model:ie.model});I.fixes+=1,I.linesReworked+=ie.class==="rework"?ie.lines:0;let B=N?.cause&&Ui.includes(N.cause)?N.cause:"unclassified";I.causes[B]+=1,z?(I.reworkChargedUsd+=Me,m.charged+=Me,Ae.charged=sn(Ae.charged+Me)):(I.reworkPendingUsd+=Me,m.pending+=Me),Ae.origins.push({key:ie.key,provider:I.provider,model:I.model,lines:ie.lines,ageDays:ie.ageDays,class:ie.class,usd:sn(Me)})}let te=Math.max(0,V-W);m.unattributed+=te}y.push(Ae),!c.has(R.sha)&&l.has(R.sha)&&$.push(R.sha)}for(let E of Object.values(u)){let R=E.provider||"unknown",G=E.model||"unknown",V=A=>{A.genUsd+=E.genUsd,A.reworkChargedUsd+=E.reworkChargedUsd,A.reworkPendingUsd+=E.reworkPendingUsd,A.linesReworked+=E.linesReworked,A.fixes+=E.fixes;for(let _ of Object.keys(A.causes))A.causes[_]+=E.causes[_]};V(O[R]||=Jm()),V(M[G]||=Jm())}y.sort((E,R)=>R.ts-E.ts);let P=Object.values(u).map(E=>{let R=n[`${E.trackId}/${E.boxId}`]||{};return Ym({...E,trackName:R.trackName??null,label:R.label??null})}).sort((E,R)=>R.reworkChargedUsd+R.reworkPendingUsd-(E.reworkChargedUsd+E.reworkPendingUsd)||R.genUsd-E.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${JS} 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:b,noCodeDelta:x,byEpoch:Object.fromEntries(P.map(E=>[E.key,E])),epochs:P,byProvider:Object.fromEntries(Object.entries(O).map(([E,R])=>[E,Ym(R)])),byModel:Object.fromEntries(Object.entries(M).map(([E,R])=>[E,Ym(R)])),buckets:Object.fromEntries(Object.entries(m).map(([E,R])=>[E,sn(R)])),fixUsdTotal:sn(Object.values(m).reduce((E,R)=>E+R,0)),fixes:y,verdicts:g,pendingTaps:$,commits:s.length}}var cj,lj,Xm,GS,zS,VS,uj,zr,Qm,eh,Ui,Lu,dj,pj,ta,JS,fj,wj,WS,gj,yj,bj,kj,xj,qS,vj,Sj,Tj,Aj,Zm,Bu,sn,Jm,Hu=q(()=>{Pr();cj=ij(aj),lj=64*1024*1024,Xm=(e,t)=>cj("git",["-C",e,...t],{maxBuffer:lj,timeout:6e4}),GS="Bostrat-Epoch",zS="Bostrat-Model",VS="Bostrat-Fix-Cause",uj=24*36e5,zr=Number(process.env.BOSTRAT_REWORK_WINDOW_DAYS)||21,Qm=90,eh=3,Ui=Object.freeze(["defect","design","requirements","style"]),Lu="not-a-fix",dj=new Set(["A","B","E"]),pj=Object.freeze(["fix","likely-fix","planned","unknown"]),ta=new Set(["fix","likely-fix"]),JS=.8;fj={claude:"Co-Authored-By: Claude <noreply@anthropic.com>",codex:"Co-authored-by: Codex <noreply@openai.com>",cursor:"Made-with: Cursor"};wj=/^revert\b|^revert "/i,WS=/\b(fix(es|ed)?|bug|hotfix|regression|crash|broken|npe|null ?pointer|off[- ]by[- ]one|leak)\b/i,gj=/\b(refactor|rearchitect|re-architect|restructure|rework|rewrite|redesign|simplif(y|ied)|clean ?up)\b/i,yj=/\b(lint|format(ting)?|prettier|typo|whitespace|rename)\b/i;bj=/^([a-z]+)(\([^)]*\))?!?:\s/i,kj=new Set(["fix","hotfix","bugfix","revert"]),xj=new Set(["feat","feature","docs","doc","test","tests","build","ci","chore"]),qS=/\bBP-[A-Z]*\d+\b/i,vj=new Set(["feature-build","docs-writing","research","design","ops-infra","orchestration"]);Sj=[/(^|\/)\.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)\//],Tj=[/\.(md|mdx|markdown|rst|txt|adoc|asciidoc)$/i,/(^|\/)(docs?|notes|business|design)\//i,/(^|\/)(README|CHANGELOG|CHANGES|LICENSE|CONTRIBUTING|AUTHORS|NOTICE)(\.[a-z]+)?$/i],Aj=[/\.(json|jsonc|json5|ya?ml|toml|ini|cfg|conf|properties|env|example)$/i,/(^|\/)\.[^/]+$/,/(^|\/)\.github\//,/(^|\/)(Dockerfile|Makefile|Procfile|fly\.toml)$/];Zm=e=>String(e??"").replace(/\s+/g," ").trim(),Bu=400;sn=e=>Math.round(e*1e4)/1e4,Jm=()=>({genUsd:0,reworkChargedUsd:0,reworkPendingUsd:0,linesReworked:0,fixes:0,causes:{defect:0,design:0,requirements:0,style:0,unclassified:0}})});import{execFile as Cj}from"node:child_process";import{promisify as Mj}from"node:util";function QS(e,t=Date.now()){return jp(e,t)??0}function Pj(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 eT(e,t,{now:n=Date.now()}={}){let r=QS(t,n),o=await K(e);return Fu({trackId:e.id,boxId:t.name,epoch:r,provider:t.agent??null,model:Pj(o,t.name,r)})}function Dj(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 Bj(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=Dj(n,t.name),c=i?zn(i.text)?.category??null:null;return{wallReason:a,fixerCategory:c,promptKind:i?.kind??null}}async function jj(e,t){try{let{stdout:n}=await nh(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 Lj(e){try{let{stdout:t}=await nh(e,["rev-parse","--abbrev-ref","HEAD"]);return t.trim()||null}catch{return null}}async function tT(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 K(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 nh(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=QS(t,i),l=await jj(r,n),u=await Lj(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 YS(r,n,{fixKey:ea({trackId:e.id,boxId:t.name,epoch:c}),window:zr,context:{...Bj(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)&&XS(w))){let g=Hi(w),b=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:b.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 nT(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 rT(e,t,n){if(!Ui.includes(n)&&n!==Lu)throw new Error(`bad cause "${n}" (${Ui.join("|")}|${Lu})`);let r=await K(e),o=r.find(s=>s.type==="rework.cause.offered"&&s.payload?.sha===t);if(!o)throw new Error("unknown rework offer");if(nT(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 oT(e,t){let n=await K(e);if(!nT(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 Wu(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 K(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 y of Array.isArray(x.payload?.shas)?x.payload.shas:[x.payload?.sha])y&&l.add(y);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=th({heuristic:Uu({subject:r}),subject:r,ref:o}),p=[];for(let x of c){if(x.type!=="code.rework")continue;let y=x.payload||{};if(!y.sha||l.has(y.sha)||y.codeDelta===!1||o&&u.has(y.sha)&&u.get(y.sha)!==o)continue;let $=y.intent?.intent??"unknown";(ta.has($)||$==="unknown"&&ta.has(d.intent))&&Hi(y)!==0&&p.push(y)}let f=p.reduce((x,y)=>x+Hi(y),0);if(f<eh)return{offered:!1,reason:"below-threshold"};let w=new Map;for(let x of p)for(let y of x.origins??[]){if(y.class!=="rework")continue;let $=w.get(y.key)??{key:y.key,provider:y.provider??null,model:y.model??null,lines:0,ageDays:y.ageDays};$.lines+=y.lines,$.ageDays=Math.min($.ageDays,y.ageDays),w.set(y.key,$)}let m=p.map(x=>x.sha),g=p.map(x=>x.heuristic).find(x=>x&&x.level!=="C")??Uu({subject:r})??p.map(x=>x.heuristic).find(Boolean)??null,b=ta.has(d.intent)?d:p.find(x=>ta.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,y)=>y.lines-x.lines).slice(0,3),heuristic:g,intent:b,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 Nj,nh,qu=q(()=>{de();Gl();Hu();Nj=Mj(Cj),nh=(e,t)=>Nj("git",["-C",e,...t],{maxBuffer:16*1024*1024,timeout:3e4})});import{execFile as Fj}from"node:child_process";import{promisify as Uj}from"node:util";async function rh(e,t,{midTurn:n=Lo,pollMs:r=Hj,capMs:o=Wj}={}){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 uT(e){let t=String(e||""),n=0;for(let r=0;r<64;r++){sT.lastIndex=n;let o=sT.exec(t);if(!o)break;n=o.index+o[0].length;let s=o[1]==="-",a=o[2]??o[3]??o[4],i=t.indexOf(`
194
+ `,o.index);if(i<0)break;let l=new RegExp("^"+(s?"\\t*":"")+Yj(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 oh(e,t){return e.slice(t).replace(/^[\s;&|)]+/,"").replace(/"[^"]*"|'[^']*'/g,'""').split(/[;&|\n]/)[0]}function pT(e){let t=uT(e),n=t.match(zj);if(!n)return null;let r=oh(t,n.index);return Jj.test(r)?null:{repo:r.match(dT)?.[1]??null,head:r.match(Xj)?.[1]??null}}function fT(e){let t=uT(e),n=t.match(Vj);if(!n)return null;let r=oh(t,n.index),o=oh(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("-")){Qj.has(c)&&i++;continue}s=c.replace(/^["']+|["']+$/g,"")||null;break}return{repo:r.match(dT)?.[1]??null,selector:s,auto:/\s--auto\b/.test(r)}}async function tL(e,t,{exclude:n=()=>!1}={}){let r=async i=>{er("observer");let{stdout:c}=await aT("gh",["pr","list","--repo",e,"--author","@me","--state","all","--limit","10","--json",eL],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...i}}).catch(l=>{throw qr(l)&&Kr(l),l});return JSON.parse(c||"[]")},o=i=>(i||[]).filter(c=>Date.parse(c.createdAt)>=t-qj&&!n(c)),s=await yn({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 nL(e,t){if(t)return[t];let n=[];for(let r of mT(e)){let o=await _e(r).catch(()=>null);o&&!n.includes(o)&&n.push(o)}for(let r of await Wn().catch(()=>[])){let o=await _e(r.path).catch(()=>null);o&&!n.includes(o)&&n.push(o)}return n}function mT(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 rL(e,t,n){let r=await Qs(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)||Zj(c.headRefName,e.id),i=[];for(let c of await nL(e,t?.repo??null)){let l;try{l=await tL(c,n,{exclude:a})}catch{continue}for(let u of l){let d=await at(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 hT(){for(let e of[...sh])e()}function wT(e,t,{delays:n=iT,turnEnd:r}={}){let o=pT(t.command);if(!o)return null;let s=!!fT(t.command),a=`${e.id}|${t.id??t.ts??t.command}`;if(Vr.has(a))return null;Vr.add(a);let i=t.ts??Date.now(),c=(async()=>{try{for(let l of n){await new Promise(m=>{let g=()=>{clearTimeout(b),sh.delete(g),m()},b=setTimeout(g,l);sh.add(g)});let u=await rL(e,o,i).catch(()=>null);if(u?.settled)return null;if(!u)continue;let{slug:d,pr:p}=u,{link:f,created:w}=await Ct({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 Yn(d,p.number))?null:(await rh(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{Vr.delete(a)}})();return c.catch(()=>Vr.delete(a)),c}function gT(e,t,{delays:n=iT,turnEnd:r,openedWait:o}={}){let s=fT(t.command);if(!s)return null;let a=`merge|${e.id}|${t.id??t.ts??t.command}`;if(Vr.has(a))return null;Vr.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=mT(e);if(w.length>1&&/^\d+$/.test(String(s.selector??"")))return null;for(let m of w){let g=await _e(m).catch(()=>null);g&&!d.includes(g)&&d.push(g)}}if(l||=(await Qs(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 at(c,w.number);return g&&g.trackId!==e.id?null:(g||await Ct({repo:c,number:w.number,trackId:e.id,url:w.url,headRef:w.headRefName,title:w.title,source:"merge-observed"}),await Ci(c,w.number),m&&((await K(e).catch(()=>[])).some(y=>y.type==="pr.state.changed"&&(y.payload?.change==="auto-armed"||y.payload?.change==="merged")&&y.payload?.number===w.number)||(await rh(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(M=>setTimeout(M,w));let m=[];for(let M of d)try{er("observer");let{stdout:H}=await aT("gh",["pr","view",String(l),"--repo",M,"--json",oL],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...await yn({slug:M})}}),P=JSON.parse(H||"null");P?.number&&m.push({slug:M,pr:P})}catch(H){qr(H)&&Kr(H)}let g=m.find(M=>M.pr.state==="MERGED")??(m.length===1?m[0]:null);if(!g)continue;c=g.slug;let b=g.pr;if(!b?.number)continue;if(b.state==="CLOSED")return null;if(b.state!=="MERGED"){if(f=b,s.auto)return p(b,!0);continue}let x=await at(c,b.number);if(x&&x.trackId!==e.id)return null;x||await Ct({repo:c,number:b.number,trackId:e.id,url:b.url,headRef:b.headRefName,title:b.title,source:"merge-observed"}),await rh(t.box,t.agent,r);let y=await K(e).catch(()=>[]);if(y.some(M=>M.type==="pr.state.changed"&&M.payload?.change==="merged"&&M.payload?.number===b.number))return null;let $=M=>M.some(H=>H.type==="pr.state.changed"&&H.payload?.change==="opened"&&H.payload?.number===b.number),O=0;if(!$(y)){if(pT(t.command)&&await Yn(c,b.number)){let M=Date.now();O=M+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:M,change:"opened",number:b.number,url:b.url,title:b.title,branch:b.headRefName,repo:c,selfMerge:!0}})}else if((await at(c,b.number))?.announced){let M=o?.capMs??Kj,H=o?.pollMs??Gj,P=Date.now()+M;for(;Date.now()<P&&(await new Promise(E=>setTimeout(E,H)),!$(await K(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(),O),change:"merged",number:b.number,url:b.url,title:b.title,branch:b.headRefName,repo:c}}),await Wu(e,{repo:c,number:b.number,title:b.title,branch:b.headRefName,url:b.url}).catch(()=>{}),await rr(c,b.number).catch(()=>{}),await nr(c,b.number).catch(()=>{}),await Hr(c,b.number,"merged"),b}return f?p(f,!1):null}finally{Vr.delete(a)}})();return i.catch(()=>Vr.delete(a)),i}var aT,iT,Hj,Wj,qj,Kj,Gj,cT,lT,zj,Vj,Jj,sT,Yj,dT,Xj,Zj,Qj,eL,Vr,sh,oL,ah=q(()=>{de();kr();pt();Ni();Zn();or();Fi();Fo();qu();aT=Uj(Fj),iT=[4e3,15e3,45e3],Hj=2500,Wj=5*6e4;qj=15e3,Kj=9e4,Gj=2e3,cT=/(?:^|[;&|\n({`]\s*|\)\s*)(?:(?:then|do|else|elif|if|while|until|time)\s+)?/.source,lT=/gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+/.source,zj=new RegExp(`${cT}${lT}create\\b`),Vj=new RegExp(`${cT}${lT}merge\\b`),Jj=/\s--web\b/,sT=/<<(-?)\s*(?:'([^'\n]+)'|"([^"\n]+)"|\\?([A-Za-z_][\w-]*))/g,Yj=e=>e.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");dT=/(?:--repo|-R)[\s=]+([\w.-]+\/[\w.-]+)/,Xj=/(?:--head|-H)[\s=]+([^\s"'`;&|]+)/,Zj=US;Qj=new Set(["--subject","-t","--body","-b","--body-file","-F","--match-head-commit","--author-email","-A","--repo","-R"]);eL="number,url,title,headRefName,createdAt";Vr=new Set,sh=new Set;oL="number,url,title,headRefName,state"});import sL from"node:fs/promises";import ch from"node:path";import aL from"node:os";function ih(e,t){let n=new RegExp(`\\b${t}="([^"]*)"`).exec(e);return n?n[1]:null}function Ku(e){let t=iL.exec(String(e||""));if(!t)return null;let[,n,r]=t,o=ih(n,"from"),s=o?o.replace(/^uds:/,""):null,a=yT(s);return{socket:s,pid:a,name:ih(n,"from-name"),mode:ih(n,"from-mode"),text:r.trim()}}function yT(e){let t=/(\d+)\.sock$/.exec(String(e||""));return t?Number(t[1]):null}function cL(){return process.env.CLAUDE_CONFIG_DIR?ch.join(process.env.CLAUDE_CONFIG_DIR,"sessions"):ch.join(aL.homedir(),".claude","sessions")}async function lL(e){let t=yT(e);if(!t)return null;try{let n=await sL.readFile(ch.join(cL(),`${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 bT(e,t){let n=await lL(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 iL,lh=q(()=>{iL=/<cross-session-message\b([^>]*)>([\s\S]*?)<\/cross-session-message>/});function uh(e=process.env){return!!($e(e)&&e.BOSTRAT_PLANE_TOKEN)}async function dh({loopId:e,outcome:t,note:n=null,env:r=process.env}={}){if(!uh(r))return{ok:!1,source:"unconfigured"};let o=new AbortController,s=setTimeout(()=>o.abort(),kT);try{let a=await xT(`${$e(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 vT(e,{provider:t=null,cls:n="other",status:r=null,text:o=""}={},{env:s=process.env,now:a=Date.now}={}){if(!e?.id||!String(e.name||"").startsWith("\u21BB"))return{ok:!1,source:"not-a-loop-track"};if(!uh(s))return{ok:!1,source:"unconfigured"};let i=Gu.get(e.id)||0;if(a()-i<uL)return{ok:!1,source:"debounced"};Gu.set(e.id,a());let c=await Wi({env:s}),l=c.loops.find(p=>p.trackId===e.id);if(!l)return Gu.delete(e.id),{ok:!1,source:c.source==="plane"?"no-loop":c.source};let u=`${t||"provider"} ${r?r+" ":""}${n}: ${String(o||"").replace(/\s+/g," ").trim()}`.slice(0,500),d=await dh({loopId:l.id,outcome:"errored",note:u,env:s});return d.ok||Gu.delete(e.id),{...d,loop:{id:l.id,name:l.name}}}async function Wi({env:e=process.env}={}){if(!uh(e))return{loops:[],source:"unconfigured"};let t=new AbortController,n=setTimeout(()=>t.abort(),kT);try{let r=await xT(`${$e(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 kT,xT,uL,Gu,ph=q(()=>{pt();kT=1e4,xT=(...e)=>fetch(...e);uL=10*6e4,Gu=new Map});function ST(e=process.env){return!!($e(e)&&e.BOSTRAT_PLANE_TOKEN)}async function TT(e,t,n=fh){let r=new AbortController,o=setTimeout(()=>r.abort(),n);try{return await pL(`${$e(t)}${e}`,{headers:fL(t),signal:r.signal})}finally{clearTimeout(o)}}async function qi({env:e=process.env,force:t=!1,timeoutMs:n=fh}={}){if(!ST(e))return{followups:[],source:"unconfigured"};if(!t&&Uo&&Date.now()-Uo.at<dL)return{followups:Uo.followups,source:"cache"};try{let r=await TT("/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 Uo={at:Date.now(),followups:s},{followups:s,source:"plane"}}catch(r){return Uo?{followups:Uo.followups,source:"stale",error:r?.message}:{followups:[],source:"unreachable",error:r?.message}}}async function AT(e,{env:t=process.env,timeoutMs:n=fh}={}){if(!e)return{followup:null,source:"unconfigured"};if(!ST(t))return{followup:null,source:"unconfigured"};try{let r=await TT(`/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=Uo?.followups.find(s=>s.id===e)??null;return o?{followup:o,source:"stale",error:r?.message}:{followup:null,source:"unreachable",error:r?.message}}}var dL,fh,Uo,pL,fL,ET=q(()=>{pt();dL=6e4,fh=5e3,Uo=null,pL=(...e)=>fetch(...e);fL=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});async function Jr(e,t){if(mh.has(e)){let n=new Error("offer already answered (answer in flight)");throw n.code="answer-in-flight",n}mh.add(e);try{return await t()}finally{mh.delete(e)}}var mh,Ki=q(()=>{mh=new Set});import{randomUUID as ra,createHash as mL}from"node:crypto";function RT(e){return String(e||"").toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}function bL(e){for(let[t,n]of yL)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 OT(e,{standing:t=!1}={}){let n=e&&typeof e=="object"?e:{},r=na(n.label).replace(/\s+/g," ");if(!r)throw new Error('label required (\u226460 chars, e.g. "Deploy to Pi")');if(r.length>_T)throw new Error(`label must be \u2264${_T} characters`);let o=na(n.trigger)||(n.ship?"now":""),s=t?wL:$T.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"?xL(n.ship):null,i=na(n.prompt);if(!a&&!i)throw new Error("prompt required \u2014 the full instruction a fresh session could execute");if(Buffer.byteLength(i,"utf8")>IT)throw new Error(`prompt must be \u2264${IT} bytes`);if(t){let u=bL(i);if(u)throw new Error(u)}let c=na(n.why).slice(0,hL)||null,l=t?kL(n.repo):null;return{label:r,prompt:i,trigger:o,why:c,...l?{repo:l}:{},...a?{ship:a}:{}}}function kL(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 xL(e){let t=e&&typeof e=="object"?e:{},n=Array.isArray(t.actions)?t.actions.map(i=>String(i).trim().toLowerCase()):hh.slice();for(let i of n)if(!hh.includes(i))throw new Error(`ship.actions may only contain ${hh.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=na(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=>na(i)).filter(Boolean),a.length||(a=null)}return{actions:[...new Set(n)],rebase:r,toPr:o,base:s,repos:a}}function zu(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 CT(e,t,{pull:n=qi,ship:r={}}={}){if(yh(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=OT(t);if(o.ship)return{kind:"ship",...await AL(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=ra(),b=ra();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:b,trigger:"now",repo:e.workspace?.repo||null,context:{},rows:[{armId:g,label:o.label,prompt:o.prompt,promptHash:wh(o.prompt),origin:"agent",why:o.why}]}}),{kind:"now",armId:g,offerId:b,...o}}let c=e.workspace?.repo||null,{followups:l}=await n().catch(()=>({followups:[]})),u=RT(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 K(s),f=zu(p,{trigger:o.trigger}),w=f.length?f[f.length-1].armId:null,m=ra();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 MT(e,t){if(!t)throw new Error("armId required");let n={id:e.id,cwd:e.cwd},r=await K(n);if(!zu(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 NT(e,t,{pull:n=qi}={}){if(yh(e))throw new Error("propose from a lead Track, not a loop's run Track");let r=OT(t,{standing:!0}),o=r.repo??e.workspace?.repo??null,s={id:e.id,cwd:e.cwd};if((await K(s)).reduce((g,b)=>b.type==="followup.create.offered"?b.payload?.proposalId??g:b.type==="followup.create.answered"&&b.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=RT(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}" (${gh[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=ra(),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 PT(e,t,n,{followupId:r=null}={}){if(!t)throw new Error("proposalId required");let o={id:e.id,cwd:e.cwd},s=await K(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 Gi(e,t,n={},{pull:r=qi}={}){if(!e||yh(e))return null;let o={id:e.id,cwd:e.cwd},s=await K(o).catch(()=>[]),a=n.repo??e.workspace?.repo??null;if(t==="pr.merged"){let p=m=>{let g=(m?.prs||[]).filter(b=>Number.isFinite(Number(b?.number))).map(b=>`${b?.repo??m?.repo??""}#${Number(b.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=zu(s,{trigger:t}).map(p=>({armId:p.armId,label:p.label,prompt:p.prompt,promptHash:wh(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:vL(f.prompt),promptHash:wh(f.prompt),origin:f.origin,repo:f.repo??null}))}let l=[...i,...c].slice(0,gL);if(!l.length)return null;let u=ra(),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 SL(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 DT(e,{offerId:t,followupId:n=null,armId:r=null,promoted:o=null}={},s={}){if(!t)throw new Error("offerId required");return Jr(`fu:${e.id}:${t}`,()=>TL(e,{offerId:t,followupId:n,armId:r,promoted:o},s))}async function TL(e,{offerId:t,followupId:n,armId:r,promoted:o},s){let{sayToLead:a,unarchiveTrack:i,getFollowup:c=AT}=s,l={id:e.id,cwd:e.cwd},u=await K(l),d=u.find(y=>y.type==="followup.offered"&&y.payload?.offerId===t);if(!d)throw new Error("unknown offer");if(u.some(y=>y.type==="followup.answered"&&y.payload?.offerId===t))throw new Error("offer already answered");let p=d.payload.rows||[],f=y=>C(l,{type:"followup.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,...y}});if(!n&&!r)return await f({action:"dismiss",followupIds:p.map(y=>y.followupId).filter(Boolean),armIds:p.map(y=>y.armId).filter(Boolean)}),{offerId:t,action:"dismiss"};let w=null,m=null;if(n){if(!p.some(O=>O.followupId===n))throw new Error("that follow-up is not on this card");let{followup:y,source:$}=await c(n);if($==="unreachable")throw new Error("plane unreachable \u2014 the follow-up's current prompt can't be read; try again shortly");if(!y||y.status!=="active"){await f({action:"removed",followupId:n});let O=new Error("removed in Settings since it was offered");throw O.code="removed",O}w=y.prompt,m=y.label}else{let y=p.find(O=>O.armId===r);if(!y)throw new Error("that arm is not on this card");if(w=u.find(O=>O.type==="followup.armed"&&O.payload?.armId===r)?.payload?.prompt??y.prompt,m=y.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 b=`${SL(d.payload)}
195
195
 
196
- ${w}`,x=await a(e.id,b,{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 TL(e,t,{changedRepos:n=null,probe:r=Mu,branchOf:o=Gr}={}){let s=t.ship;if(!e.workspace?.branch)throw new Error("this Track has no branch to ship \u2014 a ship offer needs a worktree Track");let a={id:e.id,cwd:e.cwd},i=(e.boxes||[]).find(g=>g.name===e.leadBox)||null,c=e.workspace?.kind==="multi",l;if(c&&n){let g=await n(e).catch(()=>[]),b=s.repos?g.filter(x=>s.repos.includes(x.name)):g;l=b.length?b.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=>Fr.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=ra(),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 DT(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 jT(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 BT(e,{pull:t=qi}={}){let{followups:n,source:r,error:o}=await t().catch(a=>({followups:[],source:"unreachable",error:a?.message})),s=e?await K({id:e.id,cwd:e.cwd}).catch(()=>[]):[];return{followups:n,source:r,error:o,arms:e?Gu(s):[]}}var ET,_T,mL,IT,hL,wh,wL,mh,hh,na,gL,gh,xL,zu=q(()=>{de();Mo();Gm();Fo();AT();Ki();ET=60,_T=8*1024,mL=200,IT=["now","pr.merged","ship.done","pr.opened","checks.green","track.opened"],hL=IT.filter(e=>e!=="now"&&e!=="track.opened"),wh={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"},wL=3,mh=["commit","push","pr"];hh=e=>fL("sha256").update(String(e)).digest("hex").slice(0,16),na=e=>typeof e=="string"?e.trim():"",gL=[[/(^|[^\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"]];gh=e=>String(e?.name||"").startsWith("\u21BB");xL=e=>String(e||"").split(`
196
+ ${w}`,x=await a(e.id,b,{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 AL(e,t,{changedRepos:n=null,probe:r=Mu,branchOf:o=Gr}={}){let s=t.ship;if(!e.workspace?.branch)throw new Error("this Track has no branch to ship \u2014 a ship offer needs a worktree Track");let a={id:e.id,cwd:e.cwd},i=(e.boxes||[]).find(g=>g.name===e.leadBox)||null,c=e.workspace?.kind==="multi",l;if(c&&n){let g=await n(e).catch(()=>[]),b=s.repos?g.filter(x=>s.repos.includes(x.name)):g;l=b.length?b.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=>Fr.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=ra(),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 BT(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 jT(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 LT(e,{pull:t=qi}={}){let{followups:n,source:r,error:o}=await t().catch(a=>({followups:[],source:"unreachable",error:a?.message})),s=e?await K({id:e.id,cwd:e.cwd}).catch(()=>[]):[];return{followups:n,source:r,error:o,arms:e?zu(s):[]}}var _T,IT,hL,$T,wL,gh,gL,hh,wh,na,yL,yh,vL,Vu=q(()=>{de();Mo();zm();Fo();ET();Ki();_T=60,IT=8*1024,hL=200,$T=["now","pr.merged","ship.done","pr.opened","checks.green","track.opened"],wL=$T.filter(e=>e!=="now"&&e!=="track.opened"),gh={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"},gL=3,hh=["commit","push","pr"];wh=e=>mL("sha256").update(String(e)).digest("hex").slice(0,16),na=e=>typeof e=="string"?e.trim():"",yL=[[/(^|[^\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"]];yh=e=>String(e?.name||"").startsWith("\u21BB");vL=e=>String(e||"").split(`
197
197
  `).slice(0,3).join(`
198
- `).slice(0,400)});import{randomUUID as AL}from"node:crypto";function zi(e){return e.sourceId?`${e.role}|id:${e.sourceId}`:`${e.role}|${e.ts??"?"}|${String(e.text||"").slice(0,40)}`}function LT(e){return e.id?`cmd|${e.box}|id:${e.id}`:`cmd|${e.box}|${e.ts??"?"}|${String(e.command||"").slice(0,40)}`}function FT(e){return`job|${e.box}|id:${e.id}`}async function bh(e){return yh.has(e.id)?yh.get(e.id):(Vu.has(e.id)||Vu.set(e.id,K(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(zi({role:o,sourceId:r.payload.sourceId})),n.keys.add(zi({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(zi({role:"user",sourceId:r.payload.sourceId})),n.keys.add(zi({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(LT({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(FT({id:r.payload.id,box:r.boxId}));return yh.set(e.id,n),n}).finally(()=>Vu.delete(e.id))),Vu.get(e.id))}async function UT(e,t){let n=new Set;try{let r=(await bh(e)).keys;for(let o of t||[]){if(!o||o.ts==null||!String(o.text||"").trim()&&!o.images?.length)continue;let s=zi(o);if(r.has(s))continue;r.add(s);let a=o.role==="user"?qu(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 yT(a,Vi),boxRole:o.boxRole,sourceId:o.sourceId||void 0}});continue}let i=Pk(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}}),xT(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=Wv(o.text);if(c&&DT(await K(e).catch(()=>[])))continue;if(c){let l=Gv(c),u;if(e.workspace?.kind==="multi"){let w=await Ho(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 Gr(e.cwd).catch(()=>null))||e.workspace.branch,p=await Mu(e,{branch:d,rebase:l}).catch(()=>null),f=p?null:Kv(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:AL(),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 HT(e,t){try{let n=await bh(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=LT(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}}),hT(e,o),wT(e,o)}}catch{}}async function WT(e,t){try{let n=await bh(e),r=[...t||[]].filter(o=>o&&o.id).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=FT(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 yh,Vu,qT=q(()=>{de();Mo();Gm();sh();Fo();ch();or();Bl();dh();zu();yh=new Map,Vu=new Map});function EL(e){let t=[],n=null;for(let r of String(e||"").split(`
199
- `)){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 _L(e,t){let n=`${e.id}:${t.name}`;if(!kh.has(n)){let r=await K(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);kh.set(n,o)}return kh.get(n)}async function KT(e,t){try{if(t?.agent!=="codex"||!t.cwd)return;let n=await ko(t.cwd,t.pinned?t.sessionId:null);if(!n)return;let r=await _L(e,t),o=EL(await _t(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:Tn(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 kh,GT=q(()=>{de();vo();nn();Vn();kh=new Map});import Ju from"node:fs";import vh from"node:path";import IL from"node:os";async function OL({sinceMs:e,cookie:t,fetchImpl:n=fetch}){let r=[];for(let o=1;o<=20;o++){let s=await n(RL,{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:zT})});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<zT)break}return r}function CL(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 JT(){try{return JSON.parse(Ju.readFileSync(Yu(),"utf8"))}catch{return{sinceMs:0,seen:[]}}}function NL(e){try{Ju.mkdirSync(vh.dirname(Yu()),{recursive:!0});let t=Yu()+".tmp";Ju.writeFileSync(t,JSON.stringify(e)),Ju.renameSync(t,Yu())}catch{}}async function DL({fetchImpl:e,now:t=Date.now()}={}){if(Yr.rows&&t-Yr.at<ML)return Yr.rows;let n=process.env.BOSTRAT_CURSOR_USAGE_COOKIE;if(!n)return null;let r=JT(),o=Math.max(r.sinceMs-6e4,t-24*36e5);try{let s=await OL({sinceMs:o,cookie:n,fetchImpl:e});Yr={at:t,rows:s.map(CL).filter(Boolean),error:null}}catch(s){Yr={at:t,rows:null,error:String(s?.message||s)}}return Yr.rows}async function jL(e,t){let n=`${e.id}:${t.name}`;if(!xh.has(n)){let r=await K(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);xh.set(n,o)}return xh.get(n)}async function YT(e,t,{fetchImpl:n}={}){try{if(t?.agent!=="cursor"||!t.cwd||!VT())return;let r=await DL({fetchImpl:n});if(!r||!r.length)return;let o=await Dx(t.cwd,t.pinned?t.sessionId:null);if(!o?.chatId)return;let s=await jL(e,t),a=JT(),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=Tn(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}})}NL({sinceMs:c,seen:[...i].slice(-PL)})}catch{}}var $L,VT,RL,zT,ML,Yr,Yu,PL,Sh,xh,Th=q(()=>{de();em();Vn();$L=process.env.BOSTRAT_STATE_DIR||vh.join(process.env.HOME||IL.tmpdir(),".bostrat"),VT=(e=process.env)=>!!e.BOSTRAT_CURSOR_USAGE_COOKIE,RL="https://cursor.com/api/dashboard/get-filtered-usage-events",zT=100;ML=5*6e4,Yr={at:0,rows:null,error:null},Yu=()=>vh.join($L,"cursor-usage.json");PL=5e3;Sh=()=>({enabled:VT(),lastPollAt:Yr.at||null,error:Yr.error}),xh=new Map});import{randomUUID as BL,createHmac as LL}from"node:crypto";function ZT(e){Eh=typeof e=="string"&&e?e:null}function FL(e){if(!Eh)return null;let t=He(e);return t?LL("sha256",Buffer.from(Eh,"base64url")).update(t,"utf8").digest("hex").slice(0,16):null}function tA(){let e={};for(let t of eA)e[String(t)]=0;return e.inf=0,{buckets:e,sumMs:0,count:0}}function XT(e,t){let n=Math.max(0,Number(t)||0);for(let r of eA)n<=r&&(e.buckets[String(r)]+=1);e.buckets.inf+=1,e.sumMs+=n,e.count+=1}function nA(){let e={};for(let t of QT)e[t]=0;return e}function HL(){In={total:new Map,holds:nA(),queueWaitMs:tA(),readyWaitMs:new Map,verify:new Map,retries:new Map}}function rA({queueDepth:e=0,queueOldestAgeMs:t=0}={}){let n=In;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]=r.split("|");return{provider:s,verdict:a,n:o}}),retries:[...n.retries].map(([r,o])=>({provider:r,n:o})),queueDepth:Number(e)||0,queueOldestAgeMs:Number(t)||0}}function Ji({kind:e=null,producer:t=null,orchestration:n=!1}={}){return n?`orchestration:${e||"orchestration"}`:e?`scripted:${e}`:UL.has(t)?t:"composer"}function Yi({text:e="",producer:t="composer",kind:n=null,provider:r=null,attachments:o=0,now:s=Date.now}={}){let a=s();return{id:BL(),producer:t,kind:n||null,provider:r||null,textBytes:Buffer.byteLength(String(e||""),"utf8"),textHmac16:FL(e),attachments:Number(o)||0,paste:null,t0:a,queuedAt:null,dequeuedAt:null,holds:nA(),requeued:0,readyWaitMs:null,readyOutcome:null,verify:null,settled:!1,outcome:null}}async function Xi(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 oA(e,t){QT.includes(t)&&(e?.holds&&(e.holds[t]+=1),In.holds[t]+=1)}function Zi(e,{ms:t,outcome:n}){e&&(e.readyWaitMs=Math.max(0,Number(t)||0),e.readyOutcome=n||null)}async function $n(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(Ah(In.total,`${s}|${t.producer}|${n}`),a&&XT(In.queueWaitMs,i),t.readyWaitMs!=null){let l=`${s}|${t.readyOutcome||"unknown"}`;In.readyWaitMs.has(l)||In.readyWaitMs.set(l,tA()),XT(In.readyWaitMs.get(l),t.readyWaitMs)}t.verify?.verdict&&(Ah(In.verify,`${s}|${t.verify.verdict}`),t.verify.retries&&Ah(In.retries,s,t.verify.retries));let c={ts:o,deliveryId:t.id,producer:t.producer,...t.kind?{kind:t.kind}:{},cliVersion:null,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:c}).catch(()=>{}),c}function oa(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 Eh,QT,eA,UL,In,Ah,_h=q(()=>{de();yi();Eh=null;QT=["busy","prompt","handoff","noSession","cap","grace"],eA=[500,2e3,1e4,6e4,6e5],UL=new Set(["composer","voice","loop"]);In=null;HL();Ah=(e,t,n=1)=>e.set(t,(e.get(t)||0)+n)});import tc from"node:fs/promises";import It from"node:path";import WL from"node:os";import qL from"node:net";import{randomUUID as KL}from"node:crypto";import{execFile as GL}from"node:child_process";import{promisify as zL}from"node:util";function eF(e){for(let t of Nh(e))if(!uA.test(t))return t;return null}function dA(e){let t=Nh(e),n=t.indexOf("--");return n===-1?t:t.slice(0,n)}function tF(e,t){let n=dA(t);for(let r=0;r<n.length;r++){let o=/^--prefix=(.+)$/.exec(n[r]);if(o)return It.resolve(e,o[1]);if(n[r]==="--prefix"&&n[r+1])return It.resolve(e,n[r+1])}return e}function rF(e){let t=!1,n=!1;for(let r of Nh(e)){if(!t){if(uA.test(r))continue;t=!0;continue}if(r.startsWith("-")){let o=r.indexOf("="),s=o===-1?null:r.slice(o+1);if(s&&Ih(s))return`serves the filesystem root ("${s}")`;n=o===-1;continue}if(n){if(n=!1,Ih(r))return`serves the filesystem root ("${r}")`;continue}if(Ih(r))return`serves the filesystem root ("${r}")`;if(nF(r))return`serves a path that escapes the workspace ("${r}")`}return null}async function sF(e,t){if(It.resolve(e)===It.resolve(t))return!0;let[n,r]=await Promise.all([Xu(e),Xu(t)]);return n===r}async function aF(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 pA(It.join(e,o.name,Oh))?`./${o.name}`:null))).filter(Boolean)}async function iF(e,t){let[n,r]=await Promise.all([Xu(e),Xu(t)]),o=It.relative(n,r);if(o&&(o.startsWith("..")||It.isAbsolute(o)))throw Qi(`serve directory escapes the Track workspace: ${t}`)}async function cF(e,t){let n=rF(t);if(n)throw Qi(`refusing this view: the command ${n} \u2014 serve a build dir, not the filesystem root`);if(!await oF(e))throw Qi(`serve directory does not exist: ${e}`);let r=eF(t);if(!r)return;if(!r.includes("/")&&!await ck(r,{loginShell:!0,failOpen:!0}))throw Qi(`\`${r}\` is not on the box's PATH \u2014 install it in the box first`);if(XL.test(t)||ZL.has(r)||!YL.has(r)||!dA(t).includes("run")||QL.test(t))return;let o=tF(e,t);if(await pA(It.join(o,Oh)))return;let s=await aF(o),a=s.length?` \u2014 found one in ${s.join(", ")}; run bostrat-view from there`:"";throw Qi(`no ${Oh} in ${o}${a}`)}async function ir(){return Rn||($h||=(async()=>{try{Rn=JSON.parse(await tc.readFile(lA,"utf8"))}catch{Rn={views:[],adoptWatermarks:{}}}finally{$h=null}return Rn.views||=[],Rn.adoptWatermarks||={},Rn})(),$h)}async function Cn(){await Et(lA,Rn)}function ar(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 Dh(e){return ec.get(e)||null}function mA(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 Ch(e,t){let n=ec.get(e);n&&!n.finishedAt&&!n.viewId&&(n.viewId=t,n.step="booting")}function Zu(e,{error:t=null}={}){let n=ec.get(e);return!n||n.finishedAt?null:(n.finishedAt=Date.now(),t&&(n.error=t),n)}function hA(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 Mh(e){return String(e||"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40).replace(/-+$/g,"")||"view"}function lF(e,t){let n=Mh(t),r=new Set(e.views.map(o=>o.slug));if(!r.has(n)&&!iA.has(n))return n;for(let o=2;;o++){let s=`${n}-${o}`;if(!r.has(s)&&!iA.has(s))return s}}function nc(e,{timeoutMs:t=1200}={}){return new Promise(n=>{let r=qL.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 jh(e){if(process.platform!=="darwin"){await On("fuser",["-k",`${e}/tcp`]).catch(()=>{});return}let t="";try{({stdout:t}=await On("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 wA(e=process.env){return new Set([Number(e.PORT)||3362,Number(e.BOSTRAT_TLS_PORT)||3443])}async function uF(e,t){let n=new Set(e.views.map(o=>o.port)),r=wA();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=sA;o<=aA;o++)if(!(n.has(o)||r.has(o))&&!await nc(o,{timeoutMs:250}))return o;throw new Error(`no free view port in ${sA}-${aA}`)}async function dF(e){try{let{stdout:t}=await On(X,Z("list-sessions","-F","#{session_name}"));return t.split(`
200
- `).some(n=>n.trim()===sa(e))}catch{return!1}}async function rc(e){try{await On(X,Z("kill-session","-t",sa(e)))}catch{}}async function Bh(e){if(!await si())throw new Error("host tmux server not running and auto-start failed \u2014 cannot spawn a view server");let t=sa(e.slug),n=e.serveCwd??e.cwd,r=It.dirname(process.execPath);await On(X,Z("new-session","-d","-s",t,"-c",n)),await On(X,Z("send-keys","-t",t,"-l",`export PORT=${e.port} PATH="${r}:$PATH"`)),await On(X,Z("send-keys","-t",t,"Enter")),await On(X,Z("send-keys","-t",t,"-l",e.cmd)),await On(X,Z("send-keys","-t",t,"Enter"))}async function cA(e,t=12){try{let{stdout:n}=await On(X,Z("capture-pane","-t",sa(e),"-p"));return String(n||"").trimEnd().split(`
198
+ `).slice(0,400)});import{randomUUID as EL}from"node:crypto";function zi(e){return e.sourceId?`${e.role}|id:${e.sourceId}`:`${e.role}|${e.ts??"?"}|${String(e.text||"").slice(0,40)}`}function FT(e){return e.id?`cmd|${e.box}|id:${e.id}`:`cmd|${e.box}|${e.ts??"?"}|${String(e.command||"").slice(0,40)}`}function UT(e){return`job|${e.box}|id:${e.id}`}async function kh(e){return bh.has(e.id)?bh.get(e.id):(Ju.has(e.id)||Ju.set(e.id,K(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(zi({role:o,sourceId:r.payload.sourceId})),n.keys.add(zi({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(zi({role:"user",sourceId:r.payload.sourceId})),n.keys.add(zi({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(FT({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(UT({id:r.payload.id,box:r.boxId}));return bh.set(e.id,n),n}).finally(()=>Ju.delete(e.id))),Ju.get(e.id))}async function HT(e,t){let n=new Set;try{let r=(await kh(e)).keys;for(let o of t||[]){if(!o||o.ts==null||!String(o.text||"").trim()&&!o.images?.length)continue;let s=zi(o);if(r.has(s))continue;r.add(s);let a=o.role==="user"?Ku(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 bT(a,Vi),boxRole:o.boxRole,sourceId:o.sourceId||void 0}});continue}let i=Pk(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}}),vT(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=Wv(o.text);if(c&&BT(await K(e).catch(()=>[])))continue;if(c){let l=Gv(c),u;if(e.workspace?.kind==="multi"){let w=await Ho(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 Gr(e.cwd).catch(()=>null))||e.workspace.branch,p=await Mu(e,{branch:d,rebase:l}).catch(()=>null),f=p?null:Kv(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:EL(),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 WT(e,t){try{let n=await kh(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=FT(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}}),wT(e,o),gT(e,o)}}catch{}}async function qT(e,t){try{let n=await kh(e),r=[...t||[]].filter(o=>o&&o.id).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=UT(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 bh,Ju,KT=q(()=>{de();Mo();zm();ah();Fo();lh();or();jl();ph();Vu();bh=new Map,Ju=new Map});function _L(e){let t=[],n=null;for(let r of String(e||"").split(`
199
+ `)){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 IL(e,t){let n=`${e.id}:${t.name}`;if(!xh.has(n)){let r=await K(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);xh.set(n,o)}return xh.get(n)}async function GT(e,t){try{if(t?.agent!=="codex"||!t.cwd)return;let n=await ko(t.cwd,t.pinned?t.sessionId:null);if(!n)return;let r=await IL(e,t),o=_L(await _t(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:Tn(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 xh,zT=q(()=>{de();vo();nn();Vn();xh=new Map});import Yu from"node:fs";import Sh from"node:path";import $L from"node:os";async function CL({sinceMs:e,cookie:t,fetchImpl:n=fetch}){let r=[];for(let o=1;o<=20;o++){let s=await n(OL,{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:VT})});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<VT)break}return r}function ML(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 YT(){try{return JSON.parse(Yu.readFileSync(Xu(),"utf8"))}catch{return{sinceMs:0,seen:[]}}}function PL(e){try{Yu.mkdirSync(Sh.dirname(Xu()),{recursive:!0});let t=Xu()+".tmp";Yu.writeFileSync(t,JSON.stringify(e)),Yu.renameSync(t,Xu())}catch{}}async function BL({fetchImpl:e,now:t=Date.now()}={}){if(Yr.rows&&t-Yr.at<NL)return Yr.rows;let n=process.env.BOSTRAT_CURSOR_USAGE_COOKIE;if(!n)return null;let r=YT(),o=Math.max(r.sinceMs-6e4,t-24*36e5);try{let s=await CL({sinceMs:o,cookie:n,fetchImpl:e});Yr={at:t,rows:s.map(ML).filter(Boolean),error:null}}catch(s){Yr={at:t,rows:null,error:String(s?.message||s)}}return Yr.rows}async function jL(e,t){let n=`${e.id}:${t.name}`;if(!vh.has(n)){let r=await K(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);vh.set(n,o)}return vh.get(n)}async function XT(e,t,{fetchImpl:n}={}){try{if(t?.agent!=="cursor"||!t.cwd||!JT())return;let r=await BL({fetchImpl:n});if(!r||!r.length)return;let o=await Dx(t.cwd,t.pinned?t.sessionId:null);if(!o?.chatId)return;let s=await jL(e,t),a=YT(),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=Tn(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}})}PL({sinceMs:c,seen:[...i].slice(-DL)})}catch{}}var RL,JT,OL,VT,NL,Yr,Xu,DL,Th,vh,Ah=q(()=>{de();tm();Vn();RL=process.env.BOSTRAT_STATE_DIR||Sh.join(process.env.HOME||$L.tmpdir(),".bostrat"),JT=(e=process.env)=>!!e.BOSTRAT_CURSOR_USAGE_COOKIE,OL="https://cursor.com/api/dashboard/get-filtered-usage-events",VT=100;NL=5*6e4,Yr={at:0,rows:null,error:null},Xu=()=>Sh.join(RL,"cursor-usage.json");DL=5e3;Th=()=>({enabled:JT(),lastPollAt:Yr.at||null,error:Yr.error}),vh=new Map});import{randomUUID as LL,createHmac as FL}from"node:crypto";function QT(e){_h=typeof e=="string"&&e?e:null}function UL(e){if(!_h)return null;let t=He(e);return t?FL("sha256",Buffer.from(_h,"base64url")).update(t,"utf8").digest("hex").slice(0,16):null}function nA(){let e={};for(let t of tA)e[String(t)]=0;return e.inf=0,{buckets:e,sumMs:0,count:0}}function ZT(e,t){let n=Math.max(0,Number(t)||0);for(let r of tA)n<=r&&(e.buckets[String(r)]+=1);e.buckets.inf+=1,e.sumMs+=n,e.count+=1}function rA(){let e={};for(let t of eA)e[t]=0;return e}function WL(){In={total:new Map,holds:rA(),queueWaitMs:nA(),readyWaitMs:new Map,verify:new Map,retries:new Map}}function oA({queueDepth:e=0,queueOldestAgeMs:t=0}={}){let n=In;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]=r.split("|");return{provider:s,verdict:a,n:o}}),retries:[...n.retries].map(([r,o])=>({provider:r,n:o})),queueDepth:Number(e)||0,queueOldestAgeMs:Number(t)||0}}function Ji({kind:e=null,producer:t=null,orchestration:n=!1}={}){return n?`orchestration:${e||"orchestration"}`:e?`scripted:${e}`:HL.has(t)?t:"composer"}function Yi({text:e="",producer:t="composer",kind:n=null,provider:r=null,attachments:o=0,now:s=Date.now}={}){let a=s();return{id:LL(),producer:t,kind:n||null,provider:r||null,textBytes:Buffer.byteLength(String(e||""),"utf8"),textHmac16:UL(e),attachments:Number(o)||0,paste:null,t0:a,queuedAt:null,dequeuedAt:null,holds:rA(),requeued:0,readyWaitMs:null,readyOutcome:null,verify:null,settled:!1,outcome:null}}async function Xi(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 sA(e,t){eA.includes(t)&&(e?.holds&&(e.holds[t]+=1),In.holds[t]+=1)}function Zi(e,{ms:t,outcome:n}){e&&(e.readyWaitMs=Math.max(0,Number(t)||0),e.readyOutcome=n||null)}async function $n(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(Eh(In.total,`${s}|${t.producer}|${n}`),a&&ZT(In.queueWaitMs,i),t.readyWaitMs!=null){let l=`${s}|${t.readyOutcome||"unknown"}`;In.readyWaitMs.has(l)||In.readyWaitMs.set(l,nA()),ZT(In.readyWaitMs.get(l),t.readyWaitMs)}t.verify?.verdict&&(Eh(In.verify,`${s}|${t.verify.verdict}`),t.verify.retries&&Eh(In.retries,s,t.verify.retries));let c={ts:o,deliveryId:t.id,producer:t.producer,...t.kind?{kind:t.kind}:{},cliVersion:null,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:c}).catch(()=>{}),c}function oa(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 _h,eA,tA,HL,In,Eh,Ih=q(()=>{de();yi();_h=null;eA=["busy","prompt","handoff","noSession","cap","grace"],tA=[500,2e3,1e4,6e4,6e5],HL=new Set(["composer","voice","loop"]);In=null;WL();Eh=(e,t,n=1)=>e.set(t,(e.get(t)||0)+n)});import tc from"node:fs/promises";import It from"node:path";import qL from"node:os";import KL from"node:net";import{randomUUID as GL}from"node:crypto";import{execFile as zL}from"node:child_process";import{promisify as VL}from"node:util";function tF(e){for(let t of Ph(e))if(!dA.test(t))return t;return null}function pA(e){let t=Ph(e),n=t.indexOf("--");return n===-1?t:t.slice(0,n)}function nF(e,t){let n=pA(t);for(let r=0;r<n.length;r++){let o=/^--prefix=(.+)$/.exec(n[r]);if(o)return It.resolve(e,o[1]);if(n[r]==="--prefix"&&n[r+1])return It.resolve(e,n[r+1])}return e}function oF(e){let t=!1,n=!1;for(let r of Ph(e)){if(!t){if(dA.test(r))continue;t=!0;continue}if(r.startsWith("-")){let o=r.indexOf("="),s=o===-1?null:r.slice(o+1);if(s&&$h(s))return`serves the filesystem root ("${s}")`;n=o===-1;continue}if(n){if(n=!1,$h(r))return`serves the filesystem root ("${r}")`;continue}if($h(r))return`serves the filesystem root ("${r}")`;if(rF(r))return`serves a path that escapes the workspace ("${r}")`}return null}async function aF(e,t){if(It.resolve(e)===It.resolve(t))return!0;let[n,r]=await Promise.all([Zu(e),Zu(t)]);return n===r}async function iF(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 fA(It.join(e,o.name,Ch))?`./${o.name}`:null))).filter(Boolean)}async function cF(e,t){let[n,r]=await Promise.all([Zu(e),Zu(t)]),o=It.relative(n,r);if(o&&(o.startsWith("..")||It.isAbsolute(o)))throw Qi(`serve directory escapes the Track workspace: ${t}`)}async function lF(e,t){let n=oF(t);if(n)throw Qi(`refusing this view: the command ${n} \u2014 serve a build dir, not the filesystem root`);if(!await sF(e))throw Qi(`serve directory does not exist: ${e}`);let r=tF(t);if(!r)return;if(!r.includes("/")&&!await ck(r,{loginShell:!0,failOpen:!0}))throw Qi(`\`${r}\` is not on the box's PATH \u2014 install it in the box first`);if(ZL.test(t)||QL.has(r)||!XL.has(r)||!pA(t).includes("run")||eF.test(t))return;let o=nF(e,t);if(await fA(It.join(o,Ch)))return;let s=await iF(o),a=s.length?` \u2014 found one in ${s.join(", ")}; run bostrat-view from there`:"";throw Qi(`no ${Ch} in ${o}${a}`)}async function ir(){return Rn||(Rh||=(async()=>{try{Rn=JSON.parse(await tc.readFile(uA,"utf8"))}catch{Rn={views:[],adoptWatermarks:{}}}finally{Rh=null}return Rn.views||=[],Rn.adoptWatermarks||={},Rn})(),Rh)}async function Cn(){await Et(uA,Rn)}function ar(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 Bh(e){return ec.get(e)||null}function hA(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 Mh(e,t){let n=ec.get(e);n&&!n.finishedAt&&!n.viewId&&(n.viewId=t,n.step="booting")}function Qu(e,{error:t=null}={}){let n=ec.get(e);return!n||n.finishedAt?null:(n.finishedAt=Date.now(),t&&(n.error=t),n)}function wA(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 Nh(e){return String(e||"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40).replace(/-+$/g,"")||"view"}function uF(e,t){let n=Nh(t),r=new Set(e.views.map(o=>o.slug));if(!r.has(n)&&!cA.has(n))return n;for(let o=2;;o++){let s=`${n}-${o}`;if(!r.has(s)&&!cA.has(s))return s}}function nc(e,{timeoutMs:t=1200}={}){return new Promise(n=>{let r=KL.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 jh(e){if(process.platform!=="darwin"){await On("fuser",["-k",`${e}/tcp`]).catch(()=>{});return}let t="";try{({stdout:t}=await On("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 gA(e=process.env){return new Set([Number(e.PORT)||3362,Number(e.BOSTRAT_TLS_PORT)||3443])}async function dF(e,t){let n=new Set(e.views.map(o=>o.port)),r=gA();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=aA;o<=iA;o++)if(!(n.has(o)||r.has(o))&&!await nc(o,{timeoutMs:250}))return o;throw new Error(`no free view port in ${aA}-${iA}`)}async function pF(e){try{let{stdout:t}=await On(X,Z("list-sessions","-F","#{session_name}"));return t.split(`
200
+ `).some(n=>n.trim()===sa(e))}catch{return!1}}async function rc(e){try{await On(X,Z("kill-session","-t",sa(e)))}catch{}}async function Lh(e){if(!await si())throw new Error("host tmux server not running and auto-start failed \u2014 cannot spawn a view server");let t=sa(e.slug),n=e.serveCwd??e.cwd,r=It.dirname(process.execPath);await On(X,Z("new-session","-d","-s",t,"-c",n)),await On(X,Z("send-keys","-t",t,"-l",`export PORT=${e.port} PATH="${r}:$PATH"`)),await On(X,Z("send-keys","-t",t,"Enter")),await On(X,Z("send-keys","-t",t,"-l",e.cmd)),await On(X,Z("send-keys","-t",t,"Enter"))}async function lA(e,t=12){try{let{stdout:n}=await On(X,Z("capture-pane","-t",sa(e),"-p"));return String(n||"").trimEnd().split(`
201
201
  `).filter(Boolean).slice(-t).join(`
202
- `)}catch{return""}}async function fF(e){if(e.state==="stopped"||e.state==="error")return!1;let t=e.origin!=="detected",n=t?await dF(e.slug):!0;if(t&&!n){let s=e.state==="starting";return e.state=s?"error":"stopped",s&&(e.error=await cA(e.slug)||"server exited before listening"),sr.delete(e.id),await ar(e,e.state,e.error?{error:e.error}:{}),!0}if(await nc(e.port))return sr.delete(e.id),e.lastHealthyAt=Date.now(),e.state!=="live"?(e.state="live",e.error=null,await ar(e,"live"),!0):!1;if(e.state==="starting")return Date.now()-e.createdAt>pF?(e.state="error",e.error=await cA(e.slug)||"never started listening",await ar(e,"error",{error:e.error}),!0):!1;let o=(sr.get(e.id)||0)+1;return sr.set(e.id,o),o>=3&&e.state==="live"?(e.state="unhealthy",!0):!1}async function Qu(){if(!Rh){Rh=!0;try{let e=await ir(),t=!1;for(let n of e.views)await fF(n)&&(t=!0);t&&await Cn()}finally{Rh=!1}}}async function Lh({trackId:e}={}){await Qu();let t=await ir();return(e?t.views.filter(r=>r.trackId===e):t.views).map(r=>({...r}))}async function gA(e){let n=(await ir()).views.find(r=>r.id===e);return n?{...n}:null}function Fh(e){return Rn&&Rn.views.find(t=>t.slug===e)||null}async function Uh({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=It.resolve(r,o??"."),d=i==="detected"?null:async()=>{await iF(r,u),await cF(u,n)},p=await ir();if(i!=="detected"){let m=Mh(t),g=String(n).trim(),b=p.views.find(x=>x.trackId===e&&(x.slug===m||Mh(x.name)===m||x.cmd===g&&It.resolve(x.serveCwd??x.cwd)===u));if(b)return mF(p,b,{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>=Xr)throw new Error(`view cap reached (${Xr} live) \u2014 stop one first`);let w={id:KL().slice(0,8),trackId:e,box:a||null,name:t.trim(),slug:lF(p,t),cmd:n?String(n).trim():null,cwd:r,serveCwd:u,branch:c,port:await uF(p,s),origin:i,state:"starting",error:null,createdAt:Date.now(),lastHealthyAt:null};return i!=="detected"&&await Bh(w),p.views.push(w),await Cn(),await ar(w,"created",{origin:i}),Ch(e,w.id),i==="detected"&&await nc(w.port)&&(w.state="live",w.lastHealthyAt=Date.now(),await Cn(),await ar(w,"live")),{...w}}async function mF(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 sF(t.serveCwd??t.cwd,s);if((t.state==="live"||t.state==="starting")&&!i&&!c&&await nc(t.port))return await Cn(),Ch(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>=Xr)throw new Error(`view cap reached (${Xr} live) \u2014 stop one first`);return t.origin==="detected"?(await jh(t.port),t.origin="agent"):await rc(t.slug),t.cmd=n,s!==void 0&&(t.serveCwd=s),t.state="starting",t.error=null,t.createdAt=Date.now(),sr.delete(t.id),await Bh(t),await Cn(),await ar(t,"created",{restarted:!0,reused:!0}),Ch(t.trackId,t.id),{...t,reused:!0}}async function yA(e){let n=(await ir()).views.find(r=>r.id===e);if(!n)throw new Error("view not found");return n.origin==="detected"?await jh(n.port):await rc(n.slug),n.state!=="stopped"&&(n.state="stopped",sr.delete(n.id),await Cn(),await ar(n,"stopped")),{...n}}async function bA(e){let t=await ir(),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>=Xr)throw new Error(`view cap reached (${Xr} live) \u2014 stop one first`);return await rc(n.slug),n.state="starting",n.error=null,n.createdAt=Date.now(),sr.delete(n.id),await Bh(n),await Cn(),await ar(n,"created",{restarted:!0}),{...n}}async function kA(e){let t=await ir(),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 jh(r.port):await rc(r.slug),t.views.splice(n,1),sr.delete(r.id),await Cn(),await ar(r,"deleted"),{ok:!0,id:e,slug:r.slug}}async function xA(e){let t=await ir(),n=t.views.filter(r=>r.trackId===e);for(let r of n)r.origin!=="detected"&&await rc(r.slug),sr.delete(r.id);return n.length&&(t.views=t.views.filter(r=>r.trackId!==e),await Cn()),n.length}async function vA(e,t){if(!e?.id||!Array.isArray(t)||!t.length)return[];let n=await ir(),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 Cn()),!o.length)return[];let a=new Set;for(let c of o)for(let l of String(c.text||"").matchAll(hF)){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(!wA().has(c)&&!n.views.some(l=>l.port===c)&&await nc(c))try{i.push(await Uh({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 On,VL,lA,sA,aA,Xr,JL,sa,iA,Qi,YL,Oh,XL,ZL,QL,Nh,uA,Ih,nF,oF,pA,Xu,Rn,$h,ec,Ph,fA,sr,pF,Rh,hF,ed=q(()=>{ct();de();vr();On=zL(GL),VL=process.env.BOSTRAT_STATE_DIR||It.join(process.env.HOME||WL.tmpdir(),".bostrat"),lA=It.join(VL,"views.json"),[sA,aA]=(process.env.BOSTRAT_VIEW_PORTS||"4300-4349").split("-").map(e=>Number(e)||0),Xr=Number(process.env.BOSTRAT_VIEW_MAX)||3,JL="bostrat-view-",sa=e=>`${JL}${e}`,iA=new Set(["bostrat","www","api","views","app"]),Qi=e=>Object.assign(new Error(e),{status:400}),YL=new Set(["npm","pnpm","yarn","bun"]),Oh="package.json",XL=/[|;&`]|\$\(/,ZL=new Set(["sh","bash","zsh","dash","env","exec","nohup","time"]),QL=/(^|\s)(-C|--cwd|--manifest-path|--dir)(=|\s)/,Nh=e=>String(e).trim().split(/\s+/).filter(Boolean),uA=/^[A-Za-z_][A-Za-z0-9_]*=/;Ih=e=>e==="/",nF=e=>e===".."||e.startsWith("../")||e.includes("/../")||e.endsWith("/..");oF=e=>tc.stat(e).then(t=>t.isDirectory(),()=>!1),pA=e=>tc.stat(e).then(t=>t.isFile(),()=>!1),Xu=e=>tc.realpath(e).catch(()=>It.resolve(e));Rn=null,$h=null;ec=new Map,Ph=Number(process.env.BOSTRAT_VIEW_JOB_TIMEOUT)||3e5,fA=12e3;sr=new Map,pF=12e4;Rh=!1;hF=/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::(\d{2,5}))?(?:\/|\b)/g});function td(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>gF?null:n}function yF(e,t){return e?.firstSeen==null||t?.ts==null||e.firstSeen<t.ts}async function nd(e,{bypassThrottle:t=!1}={}){let n=e?.workspace?.branch;if(!n)return;let r;try{r=await K(e)}catch{return}let o=td(r);if(o==null)return;let s=(e.boxes||[]).find(d=>d.name===e.leadBox);if(await Lo(e.leadBox,s?.agent).catch(()=>!1))return;let a=Date.now();if(!t&&a-(Hh.get(e.id)||0)<wF)return;Hh.set(e.id,a);let i;try{i=await En(e.cwd,{caller:"reconcile"})}catch{return}let c=await Qs(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 Ct({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 Yn(u,l.number))){if(!yF(d,o))return;let f=await K(e).catch(()=>null);if(f&&td(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(()=>{}),Hh.delete(e.id)}var wF,Hh,gF,rd=q(()=>{de();Bo();kr();Zn();Fi();Fo();wF=6e3,Hh=new Map,gF=30*6e4});import Wh from"node:os";import{execFile as bF}from"node:child_process";import{promisify as kF}from"node:util";async function od(){if(process.platform!=="darwin")return Wh.freemem();try{let{stdout:e}=await xF("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:Wh.freemem()}catch{return Wh.freemem()}}var xF,qh=q(()=>{xF=kF(bF)});import Ye from"node:fs/promises";import Ze from"node:path";import EA from"node:os";import{randomUUID as vF}from"node:crypto";import{execFile as SF}from"node:child_process";import{promisify as TF}from"node:util";import{chromium as AF}from"playwright-core";async function Pn(){return Wo||(Kh||=(async()=>{try{Wo=JSON.parse(await Ye.readFile(IA,"utf8"))}catch{Wo={mocks:[]}}finally{Kh=null}return Wo.mocks||=[],Wo})(),Kh)}async function Gt(){await Et(IA,Wo)}function CA(e,t){Nn(e,t.v,t.videoRel?.endsWith(".webm")?"webm":"mp4"),t.posterRel&&Nn(e,t.v,"png")}function kt(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 zt(e,t){let n=sc(e.cwd);return{html:Ze.join(n,`${e.id}.v${t}.html`),png:Ze.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?Ze.join(e.cwd,r):null}function an(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 Vh(e){return e.length<24||e.readUInt32BE(12)!==1229472850?null:{width:e.readUInt32BE(16),height:e.readUInt32BE(20)}}function sd(e){return Buffer.isBuffer(e)&&e.length>24&&e.subarray(0,8).equals(CF)}function MF(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 NF(e){let t=Buffer.alloc(24),n=await Ye.open(e,"r");try{await n.read(t,0,24,0)}finally{await n.close()}return t}function PF({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 DF(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 jF(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 BF({htmlPath:e,outPath:t,width:n}){let r=Date.now(),o;try{o=await AF.launch({executablePath:$A,args:["--disable-gpu"],timeout:3e4})}catch(s){throw new Mt("chromium failed to launch",s?.message||"")}try{let a=await(await o.newContext({viewport:{width:n,height:800},deviceScaleFactor:aa})).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 DF(a,i),u=l&&PF({...l,pad:IF*aa,align:aa});u&&(i=await jF(a,i,{bg:l.bg,crop:u}))}catch{}if(i.length<RA)throw new Mt(`capture produced a ${i.length}-byte image`);let c=Vh(i);if(!c)throw new Mt("output is not a PNG");return await Ye.writeFile(t,i),{width:Math.round(c.width/aa),height:Math.round(c.height/aa),dpr:aa,renderMs:Date.now()-r}}catch(s){throw s instanceof Mt?s:new Mt(/timeout/i.test(s?.message||"")?`render timed out after ${ia}ms`:"chromium render failed",s?.message||"")}finally{await o.close().catch(()=>{})}}async function AA({htmlPath:e,outPath:t,width:n}){let r=await Ye.mkdtemp(Ze.join(EA.tmpdir(),"bostrat-mock-profile-")),o=Date.now(),s="";try{try{s=(await zh(SA,["--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 Mt(`firefox not found (${SA})`,""):new Mt(c?.killed?`render timed out after ${ia}ms`:"firefox exited non-zero",s)}let a=await Ye.stat(t).catch(()=>null);if(!a||a.size<RA)throw new Mt(`render produced ${a?`a ${a.size}-byte file`:"no file"} (silent no-op \u2014 another firefox holding the profile?)`,s);let i=Vh(await NF(t));if(!i)throw new Mt("output is not a PNG",s);return{width:i.width,height:i.height,dpr:1,renderMs:Date.now()-o}}finally{await Ye.rm(r,{recursive:!0,force:!0}).catch(()=>{})}}async function LF(e){if(EF==="firefox")return AA(e);try{return await BF(e)}catch(t){if(!/failed to launch/i.test(t?.message||""))throw t;try{return await AA(e)}catch(n){throw/not found/.test(n?.message||"")?new Mt(`no browser installed \u2014 chromium missing at ${$A} 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 MA(e){return Gh=Gh.then(e,e),Gh}async function NA(e,t){let n=await Pn(),r=n.mocks.find(o=>o.id===e);if(r){r.state="rendering",await Gt(),await kt(r,"rendering",{version:t});try{let o=await od();if(o<$F)throw new Mt(`box is low on memory (${Math.round(o/1e6)} MB available) \u2014 not spawning a browser`);let s=zt(r,t),a=await FF({htmlPath:s.html,outPath:s.png,width:r.width});if(!n.mocks.some(i=>i.id===e)){await Ye.rm(s.png,{force:!0}).catch(()=>{});return}Jh(r,{v:t,source:"html",htmlRel:Ze.relative(r.cwd,s.html),pngRel:Ze.relative(r.cwd,s.png),width:a.width,height:a.height,dpr:a.dpr,renderMs:a.renderMs,createdAt:Date.now()}),await Gt(),await kt(r,"ready",{version:t,width:a.width,height:a.height,dpr:a.dpr}),Mn(r),Nn(r,t,"png")}catch(o){if(!n.mocks.some(s=>s.id===e))return;r.state="error",r.error=o?.message||String(o),await Gt(),await kt(r,"error",{version:t,error:r.error}),Mn(r)}}}function Jh(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 UF({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?_F:Number(r);if(!Number.isInteger(o)||o<320||o>4e3)throw new Error("invalid width (320-4000)");return o}async function ac({trackId:e,group:t}={}){let n=await Pn(),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 cr(e){let n=(await Pn()).mocks.find(r=>r.id===e);return n?{...n}:null}function PA({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&&!sd(t))throw new Error("image must be a PNG");if(n){let o=MF(n);if(!o)throw new Error("video must be an mp4 or webm (magic-byte check failed)");if(n.length>TA)throw new Error(`video must be ${TA/(1024*1024)} MB or smaller (got ${Math.round(n.length/(1024*1024))} MB)`);return o}return null}async function DA({trackId:e,name:t,html:n,image:r,video:o,cwd:s,width:a,group:i,box:c,agent:l,prompt:u}){let d=UF({trackId:e,name:t,cwd:s,width:a}),p=typeof n=="string"&&n.trim(),f=PA({html:n,image:r,video:o}),w=await Pn(),m={id:vF().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 Ye.mkdir(sc(s),{recursive:!0}),w.mocks.push(m),p?(await Ye.writeFile(zt(m,1).html,n),await Gt(),await kt(m,"created"),Mn(m),Nn(m,1,"html"),MA(()=>NA(m.id,1))):o?(await BA(m,1,o,f),await Gt(),await kt(m,"created"),await kt(m,"ready",{version:1,width:m.width,height:m.height,dpr:m.dpr,durationS:m.versions[0]?.durationS??null}),Mn(m),CA(m,m.versions[0])):(await LA(m,1,r),await Gt(),await kt(m,"created"),await kt(m,"ready",{version:1,width:m.width,height:m.height,dpr:m.dpr}),Mn(m),Nn(m,1,"png")),{...m}}async function jA(e,{html:t,image:n,video:r,width:o}={}){let a=(await Pn()).mocks.find(u=>u.id===e);if(!a)throw new Error("mock not found");let i=typeof t=="string"&&t.trim(),c=PA({html:t,image:n,video:r});if(o!=null){let u=Number(o);if(!Number.isInteger(u)||u<320||u>4e3)throw new Error("invalid width (320-4000)");a.width=u}let l=a.version+1;return a.version=l,a.updatedAt=Date.now(),a.source=i?"html":r?"video":"image",a.kind=r?"video":"image",await Ye.mkdir(sc(a.cwd),{recursive:!0}),i?(a.state="queued",await Ye.writeFile(zt(a,l).html,t),await Gt(),await kt(a,"updated",{version:l}),Mn(a),Nn(a,l,"html"),MA(()=>NA(a.id,l))):r?(await BA(a,l,r,c),await Gt(),await kt(a,"updated",{version:l}),await kt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr,durationS:an(a)?.durationS??null}),Mn(a),CA(a,a.versions.find(u=>u.v===l))):(await LA(a,l,n),await Gt(),await kt(a,"updated",{version:l}),await kt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr}),Mn(a),Nn(a,l,"png")),{...a}}async function HF(e){try{let{stdout:t}=await zh(RF,["-v","error","-print_format","json","-show_format","-show_streams",e],{timeout:OA,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 WF(e,t){try{await zh(OF,["-y","-v","error","-i",e,"-frames:v","1","-f","image2",t],{timeout:OA,killSignal:"SIGKILL",maxBuffer:4*1024*1024});let n=await Ye.stat(t).catch(()=>null);return!!n&&n.size>0}catch{return!1}}async function BA(e,t,n,r){let o=sc(e.cwd),s=Ze.join(o,`${e.id}.v${t}.${r.ext}`),a=Ze.join(o,`${e.id}.v${t}.poster.png`);await Ye.writeFile(s,n);let i=await HF(s),c=await WF(s,a);Jh(e,{v:t,source:"video",htmlRel:null,pngRel:null,videoRel:Ze.relative(e.cwd,s),posterRel:c?Ze.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 LA(e,t,n){let r=Vh(n);if(!r)throw new Error("image must be a PNG");let o=zt(e,t);await Ye.writeFile(o.png,n),Jh(e,{v:t,source:"image",htmlRel:null,pngRel:Ze.relative(e.cwd,o.png),width:r.width,height:r.height,dpr:1,renderMs:null,createdAt:Date.now()}),e.width=r.width}async function FA(e){let t=await Pn(),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 kt(n,"picked",{version:n.readyVersion,siblings:r}),{mock:{...n},siblings:r}}async function UA(e){let t=await Pn(),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=zt(r,o);await Ye.rm(s.html,{force:!0}).catch(()=>{}),await Ye.rm(s.png,{force:!0}).catch(()=>{})}for(let o of r.versions||[])for(let s of[o.videoRel,o.posterRel])s&&await Ye.rm(Ze.join(r.cwd,s),{force:!0}).catch(()=>{});return await Gt(),await kt(r,"deleted"),Zt("mocks",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function HA(e){let n=(await Pn()).mocks.filter(i=>i.trackId===e.id);if(!n.length)return 0;let r=Ze.join(_A,"mock-archive",e.id),o=sc(e.cwd),s=Ze.join(r,".bostrat","mocks");await Ye.mkdir(s,{recursive:!0});let a=await Ye.readdir(o).catch(()=>[]);for(let i of a)await Ye.copyFile(Ze.join(o,i),Ze.join(s,i));for(let i of n){for(let c of i.versions||[])for(let l of[c.htmlRel,c.pngRel,c.videoRel,c.posterRel]){if(!l)continue;if(!(await Ye.stat(Ze.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(),Mn(i)}return await Gt(),n.length}async function WA(e){let t=await Pn(),n=t.mocks.filter(r=>r.trackId===e);if(n.length){t.mocks=t.mocks.filter(r=>r.trackId!==e),await Gt();for(let r of n)Zt("mocks",r.id).catch(()=>{})}return n.length}async function qA(){if(!Fe())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("mocks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Pn();for(let r of n.mocks){await Mn(r);for(let o of r.versions||[])o.htmlRel&&await Nn(r,o.v,"html"),(o.pngRel||o.posterRel)&&await Nn(r,o.v,"png"),o.videoRel&&await Nn(r,o.v,o.videoRel.endsWith(".webm")?"webm":"mp4")}return{pushed:n.mocks.length,source:"plane"}}var zh,_A,IA,EF,$A,SA,_F,aa,IF,RA,ia,$F,TA,RF,OF,OA,Mt,Wo,Kh,Mn,Nn,sc,CF,FF,Gh,ca=q(()=>{de();vr();qh();Tr();zh=TF(SF),_A=process.env.BOSTRAT_STATE_DIR||Ze.join(process.env.HOME||EA.tmpdir(),".bostrat"),IA=Ze.join(_A,"mocks.json"),EF=process.env.BOSTRAT_MOCK_ENGINE||"chromium",$A=process.env.BOSTRAT_CHROMIUM_BIN||"/usr/bin/chromium",SA=process.env.BOSTRAT_FIREFOX_BIN||"firefox",_F=1300,aa=2,IF=32,RA=1500,ia=Number(process.env.BOSTRAT_MOCK_TIMEOUT_MS)||75e3,$F=700*1024*1024,TA=100*1024*1024,RF=process.env.BOSTRAT_FFPROBE_BIN||"ffprobe",OF=process.env.BOSTRAT_FFMPEG_BIN||"ffmpeg",OA=2e4,Mt=class extends Error{constructor(t,n=""){super(n?`${t}
202
+ `)}catch{return""}}async function mF(e){if(e.state==="stopped"||e.state==="error")return!1;let t=e.origin!=="detected",n=t?await pF(e.slug):!0;if(t&&!n){let s=e.state==="starting";return e.state=s?"error":"stopped",s&&(e.error=await lA(e.slug)||"server exited before listening"),sr.delete(e.id),await ar(e,e.state,e.error?{error:e.error}:{}),!0}if(await nc(e.port))return sr.delete(e.id),e.lastHealthyAt=Date.now(),e.state!=="live"?(e.state="live",e.error=null,await ar(e,"live"),!0):!1;if(e.state==="starting")return Date.now()-e.createdAt>fF?(e.state="error",e.error=await lA(e.slug)||"never started listening",await ar(e,"error",{error:e.error}),!0):!1;let o=(sr.get(e.id)||0)+1;return sr.set(e.id,o),o>=3&&e.state==="live"?(e.state="unhealthy",!0):!1}async function ed(){if(!Oh){Oh=!0;try{let e=await ir(),t=!1;for(let n of e.views)await mF(n)&&(t=!0);t&&await Cn()}finally{Oh=!1}}}async function Fh({trackId:e}={}){await ed();let t=await ir();return(e?t.views.filter(r=>r.trackId===e):t.views).map(r=>({...r}))}async function yA(e){let n=(await ir()).views.find(r=>r.id===e);return n?{...n}:null}function Uh(e){return Rn&&Rn.views.find(t=>t.slug===e)||null}async function Hh({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=It.resolve(r,o??"."),d=i==="detected"?null:async()=>{await cF(r,u),await lF(u,n)},p=await ir();if(i!=="detected"){let m=Nh(t),g=String(n).trim(),b=p.views.find(x=>x.trackId===e&&(x.slug===m||Nh(x.name)===m||x.cmd===g&&It.resolve(x.serveCwd??x.cwd)===u));if(b)return hF(p,b,{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>=Xr)throw new Error(`view cap reached (${Xr} live) \u2014 stop one first`);let w={id:GL().slice(0,8),trackId:e,box:a||null,name:t.trim(),slug:uF(p,t),cmd:n?String(n).trim():null,cwd:r,serveCwd:u,branch:c,port:await dF(p,s),origin:i,state:"starting",error:null,createdAt:Date.now(),lastHealthyAt:null};return i!=="detected"&&await Lh(w),p.views.push(w),await Cn(),await ar(w,"created",{origin:i}),Mh(e,w.id),i==="detected"&&await nc(w.port)&&(w.state="live",w.lastHealthyAt=Date.now(),await Cn(),await ar(w,"live")),{...w}}async function hF(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 aF(t.serveCwd??t.cwd,s);if((t.state==="live"||t.state==="starting")&&!i&&!c&&await nc(t.port))return await Cn(),Mh(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>=Xr)throw new Error(`view cap reached (${Xr} live) \u2014 stop one first`);return t.origin==="detected"?(await jh(t.port),t.origin="agent"):await rc(t.slug),t.cmd=n,s!==void 0&&(t.serveCwd=s),t.state="starting",t.error=null,t.createdAt=Date.now(),sr.delete(t.id),await Lh(t),await Cn(),await ar(t,"created",{restarted:!0,reused:!0}),Mh(t.trackId,t.id),{...t,reused:!0}}async function bA(e){let n=(await ir()).views.find(r=>r.id===e);if(!n)throw new Error("view not found");return n.origin==="detected"?await jh(n.port):await rc(n.slug),n.state!=="stopped"&&(n.state="stopped",sr.delete(n.id),await Cn(),await ar(n,"stopped")),{...n}}async function kA(e){let t=await ir(),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>=Xr)throw new Error(`view cap reached (${Xr} live) \u2014 stop one first`);return await rc(n.slug),n.state="starting",n.error=null,n.createdAt=Date.now(),sr.delete(n.id),await Lh(n),await Cn(),await ar(n,"created",{restarted:!0}),{...n}}async function xA(e){let t=await ir(),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 jh(r.port):await rc(r.slug),t.views.splice(n,1),sr.delete(r.id),await Cn(),await ar(r,"deleted"),{ok:!0,id:e,slug:r.slug}}async function vA(e){let t=await ir(),n=t.views.filter(r=>r.trackId===e);for(let r of n)r.origin!=="detected"&&await rc(r.slug),sr.delete(r.id);return n.length&&(t.views=t.views.filter(r=>r.trackId!==e),await Cn()),n.length}async function SA(e,t){if(!e?.id||!Array.isArray(t)||!t.length)return[];let n=await ir(),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 Cn()),!o.length)return[];let a=new Set;for(let c of o)for(let l of String(c.text||"").matchAll(wF)){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(!gA().has(c)&&!n.views.some(l=>l.port===c)&&await nc(c))try{i.push(await Hh({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 On,JL,uA,aA,iA,Xr,YL,sa,cA,Qi,XL,Ch,ZL,QL,eF,Ph,dA,$h,rF,sF,fA,Zu,Rn,Rh,ec,Dh,mA,sr,fF,Oh,wF,td=q(()=>{ct();de();vr();On=VL(zL),JL=process.env.BOSTRAT_STATE_DIR||It.join(process.env.HOME||qL.tmpdir(),".bostrat"),uA=It.join(JL,"views.json"),[aA,iA]=(process.env.BOSTRAT_VIEW_PORTS||"4300-4349").split("-").map(e=>Number(e)||0),Xr=Number(process.env.BOSTRAT_VIEW_MAX)||3,YL="bostrat-view-",sa=e=>`${YL}${e}`,cA=new Set(["bostrat","www","api","views","app"]),Qi=e=>Object.assign(new Error(e),{status:400}),XL=new Set(["npm","pnpm","yarn","bun"]),Ch="package.json",ZL=/[|;&`]|\$\(/,QL=new Set(["sh","bash","zsh","dash","env","exec","nohup","time"]),eF=/(^|\s)(-C|--cwd|--manifest-path|--dir)(=|\s)/,Ph=e=>String(e).trim().split(/\s+/).filter(Boolean),dA=/^[A-Za-z_][A-Za-z0-9_]*=/;$h=e=>e==="/",rF=e=>e===".."||e.startsWith("../")||e.includes("/../")||e.endsWith("/..");sF=e=>tc.stat(e).then(t=>t.isDirectory(),()=>!1),fA=e=>tc.stat(e).then(t=>t.isFile(),()=>!1),Zu=e=>tc.realpath(e).catch(()=>It.resolve(e));Rn=null,Rh=null;ec=new Map,Dh=Number(process.env.BOSTRAT_VIEW_JOB_TIMEOUT)||3e5,mA=12e3;sr=new Map,fF=12e4;Oh=!1;wF=/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::(\d{2,5}))?(?:\/|\b)/g});function nd(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>yF?null:n}function bF(e,t){return e?.firstSeen==null||t?.ts==null||e.firstSeen<t.ts}async function rd(e,{bypassThrottle:t=!1}={}){let n=e?.workspace?.branch;if(!n)return;let r;try{r=await K(e)}catch{return}let o=nd(r);if(o==null)return;let s=(e.boxes||[]).find(d=>d.name===e.leadBox);if(await Lo(e.leadBox,s?.agent).catch(()=>!1))return;let a=Date.now();if(!t&&a-(Wh.get(e.id)||0)<gF)return;Wh.set(e.id,a);let i;try{i=await En(e.cwd,{caller:"reconcile"})}catch{return}let c=await Qs(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 Ct({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 Yn(u,l.number))){if(!bF(d,o))return;let f=await K(e).catch(()=>null);if(f&&nd(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(()=>{}),Wh.delete(e.id)}var gF,Wh,yF,od=q(()=>{de();jo();kr();Zn();Fi();Fo();gF=6e3,Wh=new Map,yF=30*6e4});import qh from"node:os";import{execFile as kF}from"node:child_process";import{promisify as xF}from"node:util";async function sd(){if(process.platform!=="darwin")return qh.freemem();try{let{stdout:e}=await vF("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:qh.freemem()}catch{return qh.freemem()}}var vF,Kh=q(()=>{vF=xF(kF)});import Ye from"node:fs/promises";import Ze from"node:path";import _A from"node:os";import{randomUUID as SF}from"node:crypto";import{execFile as TF}from"node:child_process";import{promisify as AF}from"node:util";import{chromium as EF}from"playwright-core";async function Pn(){return Wo||(Gh||=(async()=>{try{Wo=JSON.parse(await Ye.readFile($A,"utf8"))}catch{Wo={mocks:[]}}finally{Gh=null}return Wo.mocks||=[],Wo})(),Gh)}async function Gt(){await Et($A,Wo)}function MA(e,t){Nn(e,t.v,t.videoRel?.endsWith(".webm")?"webm":"mp4"),t.posterRel&&Nn(e,t.v,"png")}function kt(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 zt(e,t){let n=sc(e.cwd);return{html:Ze.join(n,`${e.id}.v${t}.html`),png:Ze.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?Ze.join(e.cwd,r):null}function an(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 Jh(e){return e.length<24||e.readUInt32BE(12)!==1229472850?null:{width:e.readUInt32BE(16),height:e.readUInt32BE(20)}}function ad(e){return Buffer.isBuffer(e)&&e.length>24&&e.subarray(0,8).equals(MF)}function NF(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 PF(e){let t=Buffer.alloc(24),n=await Ye.open(e,"r");try{await n.read(t,0,24,0)}finally{await n.close()}return t}function DF({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 BF(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 jF(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 LF({htmlPath:e,outPath:t,width:n}){let r=Date.now(),o;try{o=await EF.launch({executablePath:RA,args:["--disable-gpu"],timeout:3e4})}catch(s){throw new Mt("chromium failed to launch",s?.message||"")}try{let a=await(await o.newContext({viewport:{width:n,height:800},deviceScaleFactor:aa})).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 BF(a,i),u=l&&DF({...l,pad:$F*aa,align:aa});u&&(i=await jF(a,i,{bg:l.bg,crop:u}))}catch{}if(i.length<OA)throw new Mt(`capture produced a ${i.length}-byte image`);let c=Jh(i);if(!c)throw new Mt("output is not a PNG");return await Ye.writeFile(t,i),{width:Math.round(c.width/aa),height:Math.round(c.height/aa),dpr:aa,renderMs:Date.now()-r}}catch(s){throw s instanceof Mt?s:new Mt(/timeout/i.test(s?.message||"")?`render timed out after ${ia}ms`:"chromium render failed",s?.message||"")}finally{await o.close().catch(()=>{})}}async function EA({htmlPath:e,outPath:t,width:n}){let r=await Ye.mkdtemp(Ze.join(_A.tmpdir(),"bostrat-mock-profile-")),o=Date.now(),s="";try{try{s=(await Vh(TA,["--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 Mt(`firefox not found (${TA})`,""):new Mt(c?.killed?`render timed out after ${ia}ms`:"firefox exited non-zero",s)}let a=await Ye.stat(t).catch(()=>null);if(!a||a.size<OA)throw new Mt(`render produced ${a?`a ${a.size}-byte file`:"no file"} (silent no-op \u2014 another firefox holding the profile?)`,s);let i=Jh(await PF(t));if(!i)throw new Mt("output is not a PNG",s);return{width:i.width,height:i.height,dpr:1,renderMs:Date.now()-o}}finally{await Ye.rm(r,{recursive:!0,force:!0}).catch(()=>{})}}async function FF(e){if(_F==="firefox")return EA(e);try{return await LF(e)}catch(t){if(!/failed to launch/i.test(t?.message||""))throw t;try{return await EA(e)}catch(n){throw/not found/.test(n?.message||"")?new Mt(`no browser installed \u2014 chromium missing at ${RA} 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 NA(e){return zh=zh.then(e,e),zh}async function PA(e,t){let n=await Pn(),r=n.mocks.find(o=>o.id===e);if(r){r.state="rendering",await Gt(),await kt(r,"rendering",{version:t});try{let o=await sd();if(o<RF)throw new Mt(`box is low on memory (${Math.round(o/1e6)} MB available) \u2014 not spawning a browser`);let s=zt(r,t),a=await UF({htmlPath:s.html,outPath:s.png,width:r.width});if(!n.mocks.some(i=>i.id===e)){await Ye.rm(s.png,{force:!0}).catch(()=>{});return}Yh(r,{v:t,source:"html",htmlRel:Ze.relative(r.cwd,s.html),pngRel:Ze.relative(r.cwd,s.png),width:a.width,height:a.height,dpr:a.dpr,renderMs:a.renderMs,createdAt:Date.now()}),await Gt(),await kt(r,"ready",{version:t,width:a.width,height:a.height,dpr:a.dpr}),Mn(r),Nn(r,t,"png")}catch(o){if(!n.mocks.some(s=>s.id===e))return;r.state="error",r.error=o?.message||String(o),await Gt(),await kt(r,"error",{version:t,error:r.error}),Mn(r)}}}function Yh(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 HF({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?IF:Number(r);if(!Number.isInteger(o)||o<320||o>4e3)throw new Error("invalid width (320-4000)");return o}async function ac({trackId:e,group:t}={}){let n=await Pn(),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 cr(e){let n=(await Pn()).mocks.find(r=>r.id===e);return n?{...n}:null}function DA({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&&!ad(t))throw new Error("image must be a PNG");if(n){let o=NF(n);if(!o)throw new Error("video must be an mp4 or webm (magic-byte check failed)");if(n.length>AA)throw new Error(`video must be ${AA/(1024*1024)} MB or smaller (got ${Math.round(n.length/(1024*1024))} MB)`);return o}return null}async function BA({trackId:e,name:t,html:n,image:r,video:o,cwd:s,width:a,group:i,box:c,agent:l,prompt:u}){let d=HF({trackId:e,name:t,cwd:s,width:a}),p=typeof n=="string"&&n.trim(),f=DA({html:n,image:r,video:o}),w=await Pn(),m={id:SF().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 Ye.mkdir(sc(s),{recursive:!0}),w.mocks.push(m),p?(await Ye.writeFile(zt(m,1).html,n),await Gt(),await kt(m,"created"),Mn(m),Nn(m,1,"html"),NA(()=>PA(m.id,1))):o?(await LA(m,1,o,f),await Gt(),await kt(m,"created"),await kt(m,"ready",{version:1,width:m.width,height:m.height,dpr:m.dpr,durationS:m.versions[0]?.durationS??null}),Mn(m),MA(m,m.versions[0])):(await FA(m,1,r),await Gt(),await kt(m,"created"),await kt(m,"ready",{version:1,width:m.width,height:m.height,dpr:m.dpr}),Mn(m),Nn(m,1,"png")),{...m}}async function jA(e,{html:t,image:n,video:r,width:o}={}){let a=(await Pn()).mocks.find(u=>u.id===e);if(!a)throw new Error("mock not found");let i=typeof t=="string"&&t.trim(),c=DA({html:t,image:n,video:r});if(o!=null){let u=Number(o);if(!Number.isInteger(u)||u<320||u>4e3)throw new Error("invalid width (320-4000)");a.width=u}let l=a.version+1;return a.version=l,a.updatedAt=Date.now(),a.source=i?"html":r?"video":"image",a.kind=r?"video":"image",await Ye.mkdir(sc(a.cwd),{recursive:!0}),i?(a.state="queued",await Ye.writeFile(zt(a,l).html,t),await Gt(),await kt(a,"updated",{version:l}),Mn(a),Nn(a,l,"html"),NA(()=>PA(a.id,l))):r?(await LA(a,l,r,c),await Gt(),await kt(a,"updated",{version:l}),await kt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr,durationS:an(a)?.durationS??null}),Mn(a),MA(a,a.versions.find(u=>u.v===l))):(await FA(a,l,n),await Gt(),await kt(a,"updated",{version:l}),await kt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr}),Mn(a),Nn(a,l,"png")),{...a}}async function WF(e){try{let{stdout:t}=await Vh(OF,["-v","error","-print_format","json","-show_format","-show_streams",e],{timeout:CA,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 qF(e,t){try{await Vh(CF,["-y","-v","error","-i",e,"-frames:v","1","-f","image2",t],{timeout:CA,killSignal:"SIGKILL",maxBuffer:4*1024*1024});let n=await Ye.stat(t).catch(()=>null);return!!n&&n.size>0}catch{return!1}}async function LA(e,t,n,r){let o=sc(e.cwd),s=Ze.join(o,`${e.id}.v${t}.${r.ext}`),a=Ze.join(o,`${e.id}.v${t}.poster.png`);await Ye.writeFile(s,n);let i=await WF(s),c=await qF(s,a);Yh(e,{v:t,source:"video",htmlRel:null,pngRel:null,videoRel:Ze.relative(e.cwd,s),posterRel:c?Ze.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 FA(e,t,n){let r=Jh(n);if(!r)throw new Error("image must be a PNG");let o=zt(e,t);await Ye.writeFile(o.png,n),Yh(e,{v:t,source:"image",htmlRel:null,pngRel:Ze.relative(e.cwd,o.png),width:r.width,height:r.height,dpr:1,renderMs:null,createdAt:Date.now()}),e.width=r.width}async function UA(e){let t=await Pn(),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 kt(n,"picked",{version:n.readyVersion,siblings:r}),{mock:{...n},siblings:r}}async function HA(e){let t=await Pn(),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=zt(r,o);await Ye.rm(s.html,{force:!0}).catch(()=>{}),await Ye.rm(s.png,{force:!0}).catch(()=>{})}for(let o of r.versions||[])for(let s of[o.videoRel,o.posterRel])s&&await Ye.rm(Ze.join(r.cwd,s),{force:!0}).catch(()=>{});return await Gt(),await kt(r,"deleted"),Zt("mocks",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function WA(e){let n=(await Pn()).mocks.filter(i=>i.trackId===e.id);if(!n.length)return 0;let r=Ze.join(IA,"mock-archive",e.id),o=sc(e.cwd),s=Ze.join(r,".bostrat","mocks");await Ye.mkdir(s,{recursive:!0});let a=await Ye.readdir(o).catch(()=>[]);for(let i of a)await Ye.copyFile(Ze.join(o,i),Ze.join(s,i));for(let i of n){for(let c of i.versions||[])for(let l of[c.htmlRel,c.pngRel,c.videoRel,c.posterRel]){if(!l)continue;if(!(await Ye.stat(Ze.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(),Mn(i)}return await Gt(),n.length}async function qA(e){let t=await Pn(),n=t.mocks.filter(r=>r.trackId===e);if(n.length){t.mocks=t.mocks.filter(r=>r.trackId!==e),await Gt();for(let r of n)Zt("mocks",r.id).catch(()=>{})}return n.length}async function KA(){if(!Fe())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("mocks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Pn();for(let r of n.mocks){await Mn(r);for(let o of r.versions||[])o.htmlRel&&await Nn(r,o.v,"html"),(o.pngRel||o.posterRel)&&await Nn(r,o.v,"png"),o.videoRel&&await Nn(r,o.v,o.videoRel.endsWith(".webm")?"webm":"mp4")}return{pushed:n.mocks.length,source:"plane"}}var Vh,IA,$A,_F,RA,TA,IF,aa,$F,OA,ia,RF,AA,OF,CF,CA,Mt,Wo,Gh,Mn,Nn,sc,MF,UF,zh,ca=q(()=>{de();vr();Kh();Tr();Vh=AF(TF),IA=process.env.BOSTRAT_STATE_DIR||Ze.join(process.env.HOME||_A.tmpdir(),".bostrat"),$A=Ze.join(IA,"mocks.json"),_F=process.env.BOSTRAT_MOCK_ENGINE||"chromium",RA=process.env.BOSTRAT_CHROMIUM_BIN||"/usr/bin/chromium",TA=process.env.BOSTRAT_FIREFOX_BIN||"firefox",IF=1300,aa=2,$F=32,OA=1500,ia=Number(process.env.BOSTRAT_MOCK_TIMEOUT_MS)||75e3,RF=700*1024*1024,AA=100*1024*1024,OF=process.env.BOSTRAT_FFPROBE_BIN||"ffprobe",CF=process.env.BOSTRAT_FFMPEG_BIN||"ffmpeg",CA=2e4,Mt=class extends Error{constructor(t,n=""){super(n?`${t}
203
203
  ${n.trim().split(`
204
204
  `).slice(-6).join(`
205
- `)}`:t),this.name="MockRenderError"}},Wo=null,Kh=null;Mn=e=>yt("mocks",{...e},{trackId:e.trackId}).catch(()=>{}),Nn=(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"?zt(e,t).html:null);return o?Sr("mocks",e.id,t,n,o).catch(()=>{}):Promise.resolve()};sc=e=>Ze.join(e,".bostrat","mocks");CF=Buffer.from([137,80,78,71,13,10,26,10]);FF=LF,Gh=Promise.resolve()});import qF from"node:fs/promises";import JA from"node:path";import KF from"node:os";import{randomUUID as YA}from"node:crypto";async function ur(){return lr||(Yh||=(async()=>{let e=!0;try{lr=JSON.parse(await qF.readFile(XA,"utf8"))}catch{lr={flows:[]},e=!1}finally{Yh=null}if(lr.flows||=[],!e&&Fe()){let{records:t,source:n}=await st("flows").catch(()=>({records:[],source:"error"}));if(n==="plane"){for(let r of t)!r.deletedAt&&r.data?.id&&lr.flows.push(r.data);lr.flows.length&&await la().catch(()=>{})}}return lr})(),Yh)}async function la(){await Et(XA,lr)}function Xh(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 ZA({trackId:e,steps:t,prevSteps:n=[]}){if(!Array.isArray(t)||t.length<1||t.length>KA)throw new Error(`steps must be an array of 1-${KA}`);let r=await ac({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>zA)throw new Error(`${l}: caption over ${zA} chars`);let d=c.title==null?null:String(c.title).trim()||null;if(d&&d.length>VA)throw new Error(`${l}: title over ${VA} 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),b=g>=0?o.splice(g,1)[0].id:YA().slice(0,8);s.push({id:b,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 zF(e){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");if(e.trim().length>GA)throw new Error(`name over ${GA} chars`);return e.trim()}async function QA({trackId:e}={}){let t=await ur();return(e?t.flows.filter(r=>r.trackId===e):t.flows).map(r=>({...r}))}async function VF(e){let n=(await ur()).flows.find(r=>r.id===e);return n?{...n}:null}async function eE(e){let t=await VF(e);if(!t)return null;let n=new Map((await ac({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=an(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 tE({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=zF(t),i=await ur(),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 ZA({trackId:e,steps:n}),d=Date.now(),p={id:YA().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 la(),await Xh(p,"created"),ad(p),{...p}}async function nE(e,{steps:t,note:n}={}){let o=(await ur()).flows.find(i=>i.id===e);if(!o)throw new Error("flow not found");let{steps:s,resolved:a}=await ZA({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 la(),await Xh(o,"updated",{version:o.version,...n?{note:String(n).slice(0,200)}:{}}),ad(o),{...o}}async function rE(e){let t=await ur(),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 la(),await Xh(r,"deleted"),Zt("flows",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function oE(e){return(await ur()).flows.filter(n=>n.steps.some(r=>r.mockId===e)).map(n=>({...n}))}async function sE(e){let n=(await ur()).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(),ad(r);return n.length&&await la(),n.length}async function aE(e){let t=await ur(),n=t.flows.filter(r=>r.trackId===e);if(n.length){t.flows=t.flows.filter(r=>r.trackId!==e),await la();for(let r of n)Zt("flows",r.id).catch(()=>{})}return n.length}async function iE(){if(!Fe())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("flows");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await ur();for(let r of n.flows)await ad(r);return{pushed:n.flows.length,source:"plane"}}var GF,XA,KA,GA,zA,VA,lr,Yh,ad,Zh=q(()=>{de();vr();ca();Tr();GF=process.env.BOSTRAT_STATE_DIR||JA.join(process.env.HOME||KF.tmpdir(),".bostrat"),XA=JA.join(GF,"flows.json"),KA=20,GA=80,zA=500,VA=80,lr=null,Yh=null;ad=e=>yt("flows",{...e},{trackId:e.trackId}).catch(()=>{})});import fr from"node:fs/promises";import mr from"node:path";import JF from"node:os";import{randomUUID as YF}from"node:crypto";function ic(e){return XF.filter(({re:t})=>t.test(e)).map(({label:t})=>t)}async function Dn(){return dr||(Qh||=(async()=>{let e=!0;try{dr=JSON.parse(await fr.readFile(lE,"utf8"))}catch{dr={runbooks:[]},e=!1}finally{Qh=null}return dr.runbooks||=[],!e&&Fe()&&await ZF().catch(()=>{}),dr})(),Qh)}async function Ko(){await Et(lE,dr)}function cd(e){return cc(yt("runbooks",{...e},{trackId:e.trackId}))}async function ZF(){let{records:e,source:t}=await st("runbooks");if(!(t!=="plane"||!e.length)){await fr.mkdir(id,{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 Za("runbooks",r.id,o.v,"md");typeof s=="string"&&await fr.writeFile(pr(r,o.v),s).catch(()=>{})}dr.runbooks.push(r)}dr.runbooks.length&&await Ko()}}function ua(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 pr(e,t){return mr.join(id,`${e.id}.v${t}.md`)}function uE(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 dE(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Buffer.byteLength(e,"utf8");if(t>cE)throw new Error(`runbook is ${Math.round(t/1024)} KB \u2014 over the ${cE/1024} KB cap; a doc that size belongs in the repo, not a runbook`);let n=ic(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 QF(e,t){if(e.trackDeletedAt)throw new Error(`runbook is orphaned (its Track was deleted) \u2014 cannot ${t} it`)}async function eU({trackId:e,status:t}={}){let n=await Dn(),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 pE({trackId:e,status:t}={}){let n=await Dn(),r=await eU({trackId:e,status:t});if(!Fe())return{runbooks:r,fleetDegraded:!1};let{records:o,source:s}=await st("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 ew(e){let t=await tU(e);if(t)return t;if(!Fe())return null;let{records:n,source:r}=await st("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 fE(e,t){let n=await Za("runbooks",e.id,t,"md");return typeof n=="string"?n:null}async function tU(e){let n=(await Dn()).runbooks.find(r=>r.id===e);return n?{...n}:null}async function mE({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=dE(r),c=await Dn(),l={id:YF().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 fr.mkdir(id,{recursive:!0}),await fr.writeFile(pr(l,1),r),l.versions.push({v:1,mdRel:mr.relative(qo,pr(l,1)),bytes:i,note:null,createdAt:Date.now()}),c.runbooks.push(l),await Ko(),await ua(l,"created",{version:1}),cd(l),cc(Sr("runbooks",l.id,1,"md",pr(l,1))),{...l}}async function hE(e,{md:t,note:n}={}){let o=(await Dn()).runbooks.find(i=>i.id===e);if(!o)throw new Error("runbook not found");QF(o,"update");let s=dE(t),a=o.version+1;return o.version=a,o.updatedAt=Date.now(),await fr.mkdir(id,{recursive:!0}),await fr.writeFile(pr(o,a),t),o.versions.push({v:a,mdRel:mr.relative(qo,pr(o,a)),bytes:s,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),await Ko(),await ua(o,"updated",{version:a,...n?{note:String(n).slice(0,200)}:{}}),cd(o),cc(Sr("runbooks",o.id,a,"md",pr(o,a))),{...o}}async function wE(e,t){if(t!=="open"&&t!=="done")throw new Error('status must be "open" or "done"');let r=(await Dn()).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 Ko(),await ua(r,t==="done"?"done":"reopened"),cd(r),{...r})}async function gE(e){let t=await Dn(),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 fr.rm(mr.join(qo,o.mdRel),{force:!0}).catch(()=>{});return await Ko(),r.trackDeletedAt||await ua(r,"deleted"),cc(Zt("runbooks",r.id)),{ok:!0,id:e,name:r.name}}async function yE(e){let n=(await Dn()).runbooks.filter(r=>r.trackId===e&&!r.trackDeletedAt);for(let r of n)r.trackDeletedAt=Date.now(),r.updatedAt=Date.now(),await ua(r,"orphaned"),r.cwd=null,cd(r);return n.length&&await Ko(),n.length}async function bE(e){let t=await Dn(),n=t.runbooks.filter(r=>r.trackId===e);for(let r of n){await ua(r,"deleted");for(let o of r.versions||[])await fr.rm(mr.join(qo,o.mdRel),{force:!0}).catch(()=>{});cc(Zt("runbooks",r.id))}return n.length&&(t.runbooks=t.runbooks.filter(r=>r.trackId!==e),await Ko()),n.length}async function kE(){if(!Fe())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("runbooks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Dn();for(let r of n.runbooks){await yt("runbooks",{...r},{trackId:r.trackId}).catch(()=>{});for(let o of r.versions||[])await Sr("runbooks",r.id,o.v,"md",mr.join(qo,o.mdRel)).catch(()=>{})}return{pushed:n.runbooks.length,source:"plane"}}var qo,lE,id,cE,XF,dr,Qh,cc,ld=q(()=>{vr();de();Tr();qo=process.env.BOSTRAT_STATE_DIR||mr.join(process.env.HOME||JF.tmpdir(),".bostrat"),lE=mr.join(qo,"runbooks.json"),id=mr.join(qo,"runbooks"),cE=256*1024,XF=[{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/}];dr=null,Qh=null;cc=e=>Promise.resolve(e).catch(()=>{})});import tw from"node:fs/promises";import lc from"node:path";import{randomUUID as nU}from"node:crypto";function rw(e){let t=String(e||"").toLowerCase().replace(/^\./,"");return rU.has(t)?"image":oU.has(t)?"doc":null}function sU(e){let r=lc.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 SE(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>xE)throw new Error(`file too large \u2014 max ${Math.floor(xE/(1024*1024))} MB`);let r=sU(t),o=lc.extname(r).slice(1),s=rw(o);if(!s)throw new Error(`unsupported file type "${o||"unknown"}" \u2014 attach an image or a document`);let a=nU().slice(0,8),i=nw(e);await tw.mkdir(i,{recursive:!0});let c=`${a}-${r}`;return await tw.writeFile(lc.join(i,c),n,{mode:384}),await tw.chmod(lc.join(i,c),384).catch(()=>{}),{id:a,name:r,rel:`${vE}/${c}`,kind:s,size:n.length}}function TE(e){let t=e.map(r=>`\`${r}\``).join(", ");return`[Attached \u2014 please read ${e.length===1?"this file":`these ${e.length} files`}: ${t}]`}function ow(e){return e.role==="user"&&aU.test((e.text||"").trim())}var vE,nw,xE,rU,oU,aU,sw=q(()=>{vE=".bostrat/uploads",nw=e=>lc.join(e,vE),xE=Number(process.env.BOSTRAT_MAX_UPLOAD_BYTES)||24*1024*1024,rU=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","tif","tiff","heic","heif","avif","ico"]),oU=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"]);aU=/\[Attached — please read (?:this file|these \d+ files): [^\]]*\]$/});function Go(e,t,n=Date.now()){return t?e.idleSince==null?(e.idleSince=n,!1):n-e.idleSince>=6500:(e.idleSince=null,!1)}var AE=q(()=>{});import{execFile as iU}from"node:child_process";import{promisify as cU}from"node:util";function aw(e){return`refs/bostrat/wip/${e}`}function dU(e,t=Date.now()){return`refs/bostrat/rescue/${e}-${t}`}function IE(e=process.env){let t=String(e.BOSTRAT_WIP_SYNC_MS??"").trim().toLowerCase();return t!=="0"&&t!=="off"&&t!=="false"}function pU(e=process.env){let t=Number(e.BOSTRAT_WIP_SYNC_MS);return Number.isFinite(t)&&t>0?t:uU}async function iw(e,{log:t=console,force:n=!1}={}){let{id:r,cwd:o}=e??{};if(!r||!o)return{pushed:!1,reason:"no-workspace"};try{await Zr(o,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await Zr(o,["remote","get-url","origin"])}catch{return EE.has(o)||(EE.add(o),t.log?.(`[wip-sync] ${r}: no origin remote \u2014 durable code fidelity is chat/memory-only for this Track`)),{pushed:!1,reason:"no-origin"}}try{let s=await Hs(o,"bostrat: wip snapshot"),{stdout:a}=await Zr(o,["rev-parse",`${s}^{tree}`]),i=a.trim();if(!n&&ud.get(o)===i)return{pushed:!1,reason:"unchanged"};let c=aw(r);return await Zr(o,["push","--force","origin",`${s}:${c}`],_E),ud.set(o,i),await C(e,{type:"code.pushed",actor:"orchestrator",boxId:e.leadBox??null,payload:{ref:c,sha:s,wip:!0,ts:Date.now()}}).catch(()=>{}),t.log?.(`[wip-sync] ${r}: pushed ${s.slice(0,7)} \u2192 ${c}`),{pushed:!0,sha:s,ref:c}}catch(s){return t.log?.(`[wip-sync] ${r}: push failed (will retry): ${String(s?.message||s).split(`
206
- `)[0]}`),{pushed:!1,reason:"push-failed"}}}async function cw(e,{log:t=console}={}){let{id:n,cwd:r}=e??{};if(!n||!r)return{pushed:!1,reason:"no-workspace"};try{await Zr(r,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await Zr(r,["remote","get-url","origin"])}catch{return{pushed:!1,reason:"no-origin"}}try{let o=await Hs(r,"bostrat: transfer rescue snapshot"),{stdout:s}=await Zr(r,["rev-parse",`${o}^{tree}`]),a=s.trim();if(ud.get(r)===a)return{pushed:!1,reason:"unchanged"};let i=dU(n);return await Zr(r,["push","origin",`${o}:${i}`],_E),ud.set(r,a),await C(e,{type:"code.pushed",actor:"orchestrator",boxId:e.leadBox??null,payload:{ref:i,sha:o,rescue:!0,ts:Date.now()}}).catch(()=>{}),t.log?.(`[wip-sync] ${n}: rescued stranded work ${o.slice(0,7)} \u2192 ${i}`),{pushed:!0,sha:o,ref:i}}catch(o){return t.log?.(`[wip-sync] ${n}: rescue push failed: ${String(o?.message||o).split(`
207
- `)[0]}`),{pushed:!1,reason:"push-failed"}}}function $E({listTracks:e,sweepMs:t=pU(),log:n=console}){let r=!1,o=async()=>{if(!r){r=!0;try{let a=await e()??[];for(let i of a)Ve(i)||i?.kind==="setup"||await iw(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 lU,uU,_E,Zr,ud,EE,lw=q(()=>{uu();de();An();lU=cU(iU),uU=12e4,_E=6e4;Zr=(e,t,n=15e3)=>lU("git",["-C",e,...t],{timeout:n,maxBuffer:4*1024*1024}),ud=new Map,EE=new Set});import fU from"node:fs";import uw from"node:fs/promises";import mU from"node:path";function yU(e=process.env){return!!($e(e)&&e.BOSTRAT_PLANE_TOKEN)}async function RE(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(!yU(t))return{restored:!1,reason:"plane not configured"};let s=gs(e),a=mU.join(s,`${o}.ndjson`);try{if(fU.statSync(a).size>0)return{restored:!1,reason:"log not empty"}}catch{}let i=$e(t),c={authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`},l=[],u=0;for(;;){let p=new AbortController,f=setTimeout(()=>p.abort(),gU),w;try{w=await n(`${i}/v1/spine/${encodeURIComponent(o)}?after=${u}&limit=${hU}`,{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>wU)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 uw.mkdir(s,{recursive:!0});let d=`${a}.pull-${process.pid}-${Date.now()}`;return await uw.writeFile(d,l.join(`
205
+ `)}`:t),this.name="MockRenderError"}},Wo=null,Gh=null;Mn=e=>yt("mocks",{...e},{trackId:e.trackId}).catch(()=>{}),Nn=(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"?zt(e,t).html:null);return o?Sr("mocks",e.id,t,n,o).catch(()=>{}):Promise.resolve()};sc=e=>Ze.join(e,".bostrat","mocks");MF=Buffer.from([137,80,78,71,13,10,26,10]);UF=FF,zh=Promise.resolve()});import KF from"node:fs/promises";import YA from"node:path";import GF from"node:os";import{randomUUID as XA}from"node:crypto";async function ur(){return lr||(Xh||=(async()=>{let e=!0;try{lr=JSON.parse(await KF.readFile(ZA,"utf8"))}catch{lr={flows:[]},e=!1}finally{Xh=null}if(lr.flows||=[],!e&&Fe()){let{records:t,source:n}=await st("flows").catch(()=>({records:[],source:"error"}));if(n==="plane"){for(let r of t)!r.deletedAt&&r.data?.id&&lr.flows.push(r.data);lr.flows.length&&await la().catch(()=>{})}}return lr})(),Xh)}async function la(){await Et(ZA,lr)}function Zh(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 QA({trackId:e,steps:t,prevSteps:n=[]}){if(!Array.isArray(t)||t.length<1||t.length>GA)throw new Error(`steps must be an array of 1-${GA}`);let r=await ac({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>VA)throw new Error(`${l}: caption over ${VA} chars`);let d=c.title==null?null:String(c.title).trim()||null;if(d&&d.length>JA)throw new Error(`${l}: title over ${JA} 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),b=g>=0?o.splice(g,1)[0].id:XA().slice(0,8);s.push({id:b,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 VF(e){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");if(e.trim().length>zA)throw new Error(`name over ${zA} chars`);return e.trim()}async function eE({trackId:e}={}){let t=await ur();return(e?t.flows.filter(r=>r.trackId===e):t.flows).map(r=>({...r}))}async function JF(e){let n=(await ur()).flows.find(r=>r.id===e);return n?{...n}:null}async function tE(e){let t=await JF(e);if(!t)return null;let n=new Map((await ac({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=an(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 nE({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=VF(t),i=await ur(),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 QA({trackId:e,steps:n}),d=Date.now(),p={id:XA().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 la(),await Zh(p,"created"),id(p),{...p}}async function rE(e,{steps:t,note:n}={}){let o=(await ur()).flows.find(i=>i.id===e);if(!o)throw new Error("flow not found");let{steps:s,resolved:a}=await QA({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 la(),await Zh(o,"updated",{version:o.version,...n?{note:String(n).slice(0,200)}:{}}),id(o),{...o}}async function oE(e){let t=await ur(),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 la(),await Zh(r,"deleted"),Zt("flows",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function sE(e){return(await ur()).flows.filter(n=>n.steps.some(r=>r.mockId===e)).map(n=>({...n}))}async function aE(e){let n=(await ur()).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(),id(r);return n.length&&await la(),n.length}async function iE(e){let t=await ur(),n=t.flows.filter(r=>r.trackId===e);if(n.length){t.flows=t.flows.filter(r=>r.trackId!==e),await la();for(let r of n)Zt("flows",r.id).catch(()=>{})}return n.length}async function cE(){if(!Fe())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("flows");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await ur();for(let r of n.flows)await id(r);return{pushed:n.flows.length,source:"plane"}}var zF,ZA,GA,zA,VA,JA,lr,Xh,id,Qh=q(()=>{de();vr();ca();Tr();zF=process.env.BOSTRAT_STATE_DIR||YA.join(process.env.HOME||GF.tmpdir(),".bostrat"),ZA=YA.join(zF,"flows.json"),GA=20,zA=80,VA=500,JA=80,lr=null,Xh=null;id=e=>yt("flows",{...e},{trackId:e.trackId}).catch(()=>{})});import fr from"node:fs/promises";import mr from"node:path";import YF from"node:os";import{randomUUID as XF}from"node:crypto";function ic(e){return ZF.filter(({re:t})=>t.test(e)).map(({label:t})=>t)}async function Dn(){return dr||(ew||=(async()=>{let e=!0;try{dr=JSON.parse(await fr.readFile(uE,"utf8"))}catch{dr={runbooks:[]},e=!1}finally{ew=null}return dr.runbooks||=[],!e&&Fe()&&await QF().catch(()=>{}),dr})(),ew)}async function Ko(){await Et(uE,dr)}function ld(e){return cc(yt("runbooks",{...e},{trackId:e.trackId}))}async function QF(){let{records:e,source:t}=await st("runbooks");if(!(t!=="plane"||!e.length)){await fr.mkdir(cd,{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 Za("runbooks",r.id,o.v,"md");typeof s=="string"&&await fr.writeFile(pr(r,o.v),s).catch(()=>{})}dr.runbooks.push(r)}dr.runbooks.length&&await Ko()}}function ua(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 pr(e,t){return mr.join(cd,`${e.id}.v${t}.md`)}function dE(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 pE(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Buffer.byteLength(e,"utf8");if(t>lE)throw new Error(`runbook is ${Math.round(t/1024)} KB \u2014 over the ${lE/1024} KB cap; a doc that size belongs in the repo, not a runbook`);let n=ic(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 eU(e,t){if(e.trackDeletedAt)throw new Error(`runbook is orphaned (its Track was deleted) \u2014 cannot ${t} it`)}async function tU({trackId:e,status:t}={}){let n=await Dn(),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 fE({trackId:e,status:t}={}){let n=await Dn(),r=await tU({trackId:e,status:t});if(!Fe())return{runbooks:r,fleetDegraded:!1};let{records:o,source:s}=await st("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 tw(e){let t=await nU(e);if(t)return t;if(!Fe())return null;let{records:n,source:r}=await st("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 mE(e,t){let n=await Za("runbooks",e.id,t,"md");return typeof n=="string"?n:null}async function nU(e){let n=(await Dn()).runbooks.find(r=>r.id===e);return n?{...n}:null}async function hE({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=pE(r),c=await Dn(),l={id:XF().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 fr.mkdir(cd,{recursive:!0}),await fr.writeFile(pr(l,1),r),l.versions.push({v:1,mdRel:mr.relative(qo,pr(l,1)),bytes:i,note:null,createdAt:Date.now()}),c.runbooks.push(l),await Ko(),await ua(l,"created",{version:1}),ld(l),cc(Sr("runbooks",l.id,1,"md",pr(l,1))),{...l}}async function wE(e,{md:t,note:n}={}){let o=(await Dn()).runbooks.find(i=>i.id===e);if(!o)throw new Error("runbook not found");eU(o,"update");let s=pE(t),a=o.version+1;return o.version=a,o.updatedAt=Date.now(),await fr.mkdir(cd,{recursive:!0}),await fr.writeFile(pr(o,a),t),o.versions.push({v:a,mdRel:mr.relative(qo,pr(o,a)),bytes:s,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),await Ko(),await ua(o,"updated",{version:a,...n?{note:String(n).slice(0,200)}:{}}),ld(o),cc(Sr("runbooks",o.id,a,"md",pr(o,a))),{...o}}async function gE(e,t){if(t!=="open"&&t!=="done")throw new Error('status must be "open" or "done"');let r=(await Dn()).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 Ko(),await ua(r,t==="done"?"done":"reopened"),ld(r),{...r})}async function yE(e){let t=await Dn(),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 fr.rm(mr.join(qo,o.mdRel),{force:!0}).catch(()=>{});return await Ko(),r.trackDeletedAt||await ua(r,"deleted"),cc(Zt("runbooks",r.id)),{ok:!0,id:e,name:r.name}}async function bE(e){let n=(await Dn()).runbooks.filter(r=>r.trackId===e&&!r.trackDeletedAt);for(let r of n)r.trackDeletedAt=Date.now(),r.updatedAt=Date.now(),await ua(r,"orphaned"),r.cwd=null,ld(r);return n.length&&await Ko(),n.length}async function kE(e){let t=await Dn(),n=t.runbooks.filter(r=>r.trackId===e);for(let r of n){await ua(r,"deleted");for(let o of r.versions||[])await fr.rm(mr.join(qo,o.mdRel),{force:!0}).catch(()=>{});cc(Zt("runbooks",r.id))}return n.length&&(t.runbooks=t.runbooks.filter(r=>r.trackId!==e),await Ko()),n.length}async function xE(){if(!Fe())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("runbooks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Dn();for(let r of n.runbooks){await yt("runbooks",{...r},{trackId:r.trackId}).catch(()=>{});for(let o of r.versions||[])await Sr("runbooks",r.id,o.v,"md",mr.join(qo,o.mdRel)).catch(()=>{})}return{pushed:n.runbooks.length,source:"plane"}}var qo,uE,cd,lE,ZF,dr,ew,cc,ud=q(()=>{vr();de();Tr();qo=process.env.BOSTRAT_STATE_DIR||mr.join(process.env.HOME||YF.tmpdir(),".bostrat"),uE=mr.join(qo,"runbooks.json"),cd=mr.join(qo,"runbooks"),lE=256*1024,ZF=[{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/}];dr=null,ew=null;cc=e=>Promise.resolve(e).catch(()=>{})});import nw from"node:fs/promises";import lc from"node:path";import{randomUUID as rU}from"node:crypto";function ow(e){let t=String(e||"").toLowerCase().replace(/^\./,"");return oU.has(t)?"image":sU.has(t)?"doc":null}function aU(e){let r=lc.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 TE(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>vE)throw new Error(`file too large \u2014 max ${Math.floor(vE/(1024*1024))} MB`);let r=aU(t),o=lc.extname(r).slice(1),s=ow(o);if(!s)throw new Error(`unsupported file type "${o||"unknown"}" \u2014 attach an image or a document`);let a=rU().slice(0,8),i=rw(e);await nw.mkdir(i,{recursive:!0});let c=`${a}-${r}`;return await nw.writeFile(lc.join(i,c),n,{mode:384}),await nw.chmod(lc.join(i,c),384).catch(()=>{}),{id:a,name:r,rel:`${SE}/${c}`,kind:s,size:n.length}}function AE(e){let t=e.map(r=>`\`${r}\``).join(", ");return`[Attached \u2014 please read ${e.length===1?"this file":`these ${e.length} files`}: ${t}]`}function sw(e){return e.role==="user"&&iU.test((e.text||"").trim())}var SE,rw,vE,oU,sU,iU,aw=q(()=>{SE=".bostrat/uploads",rw=e=>lc.join(e,SE),vE=Number(process.env.BOSTRAT_MAX_UPLOAD_BYTES)||24*1024*1024,oU=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","tif","tiff","heic","heif","avif","ico"]),sU=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"]);iU=/\[Attached — please read (?:this file|these \d+ files): [^\]]*\]$/});function Go(e,t,n=Date.now()){return t?e.idleSince==null?(e.idleSince=n,!1):n-e.idleSince>=6500:(e.idleSince=null,!1)}var EE=q(()=>{});import{execFile as cU}from"node:child_process";import{promisify as lU}from"node:util";function iw(e){return`refs/bostrat/wip/${e}`}function pU(e,t=Date.now()){return`refs/bostrat/rescue/${e}-${t}`}function $E(e=process.env){let t=String(e.BOSTRAT_WIP_SYNC_MS??"").trim().toLowerCase();return t!=="0"&&t!=="off"&&t!=="false"}function fU(e=process.env){let t=Number(e.BOSTRAT_WIP_SYNC_MS);return Number.isFinite(t)&&t>0?t:dU}async function cw(e,{log:t=console,force:n=!1}={}){let{id:r,cwd:o}=e??{};if(!r||!o)return{pushed:!1,reason:"no-workspace"};try{await Zr(o,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await Zr(o,["remote","get-url","origin"])}catch{return _E.has(o)||(_E.add(o),t.log?.(`[wip-sync] ${r}: no origin remote \u2014 durable code fidelity is chat/memory-only for this Track`)),{pushed:!1,reason:"no-origin"}}try{let s=await Hs(o,"bostrat: wip snapshot"),{stdout:a}=await Zr(o,["rev-parse",`${s}^{tree}`]),i=a.trim();if(!n&&dd.get(o)===i)return{pushed:!1,reason:"unchanged"};let c=iw(r);return await Zr(o,["push","--force","origin",`${s}:${c}`],IE),dd.set(o,i),await C(e,{type:"code.pushed",actor:"orchestrator",boxId:e.leadBox??null,payload:{ref:c,sha:s,wip:!0,ts:Date.now()}}).catch(()=>{}),t.log?.(`[wip-sync] ${r}: pushed ${s.slice(0,7)} \u2192 ${c}`),{pushed:!0,sha:s,ref:c}}catch(s){return t.log?.(`[wip-sync] ${r}: push failed (will retry): ${String(s?.message||s).split(`
206
+ `)[0]}`),{pushed:!1,reason:"push-failed"}}}async function lw(e,{log:t=console}={}){let{id:n,cwd:r}=e??{};if(!n||!r)return{pushed:!1,reason:"no-workspace"};try{await Zr(r,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await Zr(r,["remote","get-url","origin"])}catch{return{pushed:!1,reason:"no-origin"}}try{let o=await Hs(r,"bostrat: transfer rescue snapshot"),{stdout:s}=await Zr(r,["rev-parse",`${o}^{tree}`]),a=s.trim();if(dd.get(r)===a)return{pushed:!1,reason:"unchanged"};let i=pU(n);return await Zr(r,["push","origin",`${o}:${i}`],IE),dd.set(r,a),await C(e,{type:"code.pushed",actor:"orchestrator",boxId:e.leadBox??null,payload:{ref:i,sha:o,rescue:!0,ts:Date.now()}}).catch(()=>{}),t.log?.(`[wip-sync] ${n}: rescued stranded work ${o.slice(0,7)} \u2192 ${i}`),{pushed:!0,sha:o,ref:i}}catch(o){return t.log?.(`[wip-sync] ${n}: rescue push failed: ${String(o?.message||o).split(`
207
+ `)[0]}`),{pushed:!1,reason:"push-failed"}}}function RE({listTracks:e,sweepMs:t=fU(),log:n=console}){let r=!1,o=async()=>{if(!r){r=!0;try{let a=await e()??[];for(let i of a)Ve(i)||i?.kind==="setup"||await cw(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 uU,dU,IE,Zr,dd,_E,uw=q(()=>{uu();de();An();uU=lU(cU),dU=12e4,IE=6e4;Zr=(e,t,n=15e3)=>uU("git",["-C",e,...t],{timeout:n,maxBuffer:4*1024*1024}),dd=new Map,_E=new Set});import mU from"node:fs";import dw from"node:fs/promises";import hU from"node:path";function bU(e=process.env){return!!($e(e)&&e.BOSTRAT_PLANE_TOKEN)}async function OE(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(!bU(t))return{restored:!1,reason:"plane not configured"};let s=gs(e),a=hU.join(s,`${o}.ndjson`);try{if(mU.statSync(a).size>0)return{restored:!1,reason:"log not empty"}}catch{}let i=$e(t),c={authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`},l=[],u=0;for(;;){let p=new AbortController,f=setTimeout(()=>p.abort(),yU),w;try{w=await n(`${i}/v1/spine/${encodeURIComponent(o)}?after=${u}&limit=${wU}`,{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>gU)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 dw.mkdir(s,{recursive:!0});let d=`${a}.pull-${process.pid}-${Date.now()}`;return await dw.writeFile(d,l.join(`
208
208
  `)+`
209
- `),await uw.rename(d,a),r.log?.(`[spine-pull] rehydrated ${o}: ${l.length} event(s) \u2192 ${a}`),{restored:!0,rows:l.length}}var hU,wU,gU,OE=q(()=>{pt();de();hU=1e3,wU=5e5,gU=3e4});function CE(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 ME(e){let t=(e||[]).filter(n=>!bU.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 NE({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?cn("archived","lifecycle",e):n||r>0||s?cn("needs-you",n?"pane":s?"loop":"obligations",o||w,{count:r||(n||s?1:null)}):t?cn("archiving","lifecycle",e||w):a?.count?cn("needs-you","pr",a.since,{count:a.count,summary:a.summary??null}):i?.status==="working"?cn("working","operation",i.since,{summary:i.summary??null,count:i.count??null}):(l||n)&&c?.phase?cn("working","agent-phase",c.at,{summary:c.summary??null}):l?cn("working","pane",u||w):i?.status==="waiting"?cn("waiting","operation",i.since,{summary:i.summary??null,count:i.count??null}):d?.count?cn("waiting",d.source||"pending",d.since,{summary:d.summary??null,count:d.count}):p&&f?cn("settled","obligations",p,{summary:"no open actions"}):cn("idle","fallback",p||w)}var cn,bU,PE=q(()=>{cn=(e,t,n,r={})=>({kind:e,source:t,since:n||0,...r});bU=new Set(["merged","closed","lost"])});async function DE(e){if(dd.has(e.id))return dd.get(e.id);let t=await K(e).catch(()=>[]),n=[];try{n=Sn(t)}catch{}let r=Zl(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 dd.set(e.id,p),p}var dd,jE=q(()=>{de();Ql();dd=new Map;ot.on("event",e=>{e?.trackId&&dd.delete(e.trackId)})});import{randomUUID as kU}from"node:crypto";async function dw(e,t,n={}){let r={operationId:kU(),kind:t,startedAt:Date.now(),...n};return pd.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 pw(e,t,n="completed",r=null){pd.get(e.id)?.operationId===t?.operationId&&pd.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 pd,BE,fw=q(()=>{de();pd=new Map;BE=e=>pd.get(e)||null});var w_={};Ap(w_,{HANDOFF_LATEST_REL:()=>zo,KNOWN_AGENTS:()=>bc,TRACK_NAME_MAX:()=>Ew,addTrackRepo:()=>Ww,adoptTrack:()=>ig,agentAvailability:()=>gd,announceNodeUpdate:()=>Bn,answerFullscreenOffer:()=>eg,answerPrompt:()=>bd,archiveTrack:()=>Yo,archiveTrackForMergedPr:()=>nr,augmentFirstPromptAfterHandoff:()=>VE,buildAgentCmd:()=>$w,canResumeSubtask:()=>f_,cancelQueued:()=>vc,cancelQueuedToDraft:()=>Dw,cancelStopJob:()=>Sc,cancelSubtask:()=>$d,changedRepos:()=>Ho,commitTransferOut:()=>_d,createSetupTrack:()=>Gw,createTrack:()=>vd,deleteTrack:()=>Vw,demoteTransferredTracks:()=>ag,ensureLeadEpochs:()=>ga,forceMergeSubtask:()=>dg,getHandoffJob:()=>xa,getSubtaskJob:()=>E4,getTrack:()=>oe,getTransferOutJob:()=>rg,healDeadLead:()=>gc,interruptLead:()=>xd,isArchiving:()=>m4,isHandoffNoteEcho:()=>vw,isInterruptEcho:()=>Sw,isModelSwitchEcho:()=>Tw,leadCliDead:()=>Yw,listSubtaskJobs:()=>Zo,listTracks:()=>me,matchTranscriptsToBoxes:()=>XE,mergeNotifyMessage:()=>l_,navigatePrompt:()=>Nw,notifyTrackForMergedPr:()=>rr,notifyTrackForResolvedPr:()=>Sd,offerFollowupsForMergedPr:()=>Xo,pendingOffers:()=>Cw,queueGauges:()=>Pw,queueShipCompleteNotify:()=>Bw,queuedMessages:()=>Vo,reapArchivedOrphans:()=>Qw,reconcileDemotedTracks:()=>Zw,reconcileHandoffOutcome:()=>u_,reconcileInterruptedHandoffs:()=>ng,reconcileInterruptedSubtasks:()=>cg,reconcileNodeUpdateNotices:()=>Ow,reconcileSubtaskOutcome:()=>p_,refreshStandingInstructions:()=>Kw,refuseIfTransferred:()=>sg,rehydrateLead:()=>Ac,removeTrackRepo:()=>qw,renameTrack:()=>Xw,reposOf:()=>jt,resolveTrackBox:()=>Vi,resolveTrackBoxByHookToken:()=>xc,restartLead:()=>Ad,resumeAgentCmd:()=>Rw,sayToLead:()=>Dt,sendOptionsForAgent:()=>vn,setTrackDraft:()=>Uw,setTrackModel:()=>Hw,startLeadHandoff:()=>Ed,startSpinUpView:()=>Lw,startSubtask:()=>ug,startTransferOut:()=>og,stopJobActive:()=>e_,subtaskMessages:()=>Mw,trackMessages:()=>yd,unarchiveTrack:()=>Td});import Q from"node:fs/promises";import re from"node:path";import{randomUUID as hd}from"node:crypto";import{execFile as xU}from"node:child_process";import{promisify as vU}from"node:util";function $w(e,{skipPermissions:t=!0}={}){let n=wd[e];if(!n)throw new Error(`unknown agent "${e}"`);let r=process.env[n.envVar];return r||(t&&n.skipFlag?`${n.base} ${n.skipFlag}`:n.base)}function Rw(e,t,{skipPermissions:n=!0,cwd:r=null,peerName:o=null}={}){let s=wd[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&&!tn(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 ka(e){let t=wd[e];if(t)return process.env[t.envVar]||t.base}async function gd({maxAgeMs:e=6e4}={}){if(Qr.value&&Date.now()-Qr.at<e)return Qr.value;let t=Qr.value,n=await Promise.all(bc.map(async r=>{let o=await Cl(ka(r),{retries:[]});return o===Ss?[r,t?.[r]??!0]:[r,o===Ol]}));return Qr.value=Object.fromEntries(n),Qr.at=Date.now(),Qr.value}async function kc(e,t=!0){let n=$w(e,{skipPermissions:t});if(await Cl(n)===vs){Qr.at=0;let r=n.split(/\s+/)[0],o=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.":tf[r]?`Install it on this node: ${tf[r]}`:"Its CLI must be installed and on PATH first.";throw new Error(`agent "${e}" isn't available on this box (command not found: ${r}). ${o}`)}return n}function VE(e,t=zo){return`${e.trim()}
209
+ `),await dw.rename(d,a),r.log?.(`[spine-pull] rehydrated ${o}: ${l.length} event(s) \u2192 ${a}`),{restored:!0,rows:l.length}}var wU,gU,yU,CE=q(()=>{pt();de();wU=1e3,gU=5e5,yU=3e4});function ME(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 NE(e){let t=(e||[]).filter(n=>!kU.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 PE({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?cn("archived","lifecycle",e):n||r>0||s?cn("needs-you",n?"pane":s?"loop":"obligations",o||w,{count:r||(n||s?1:null)}):t?cn("archiving","lifecycle",e||w):a?.count?cn("needs-you","pr",a.since,{count:a.count,summary:a.summary??null}):i?.status==="working"?cn("working","operation",i.since,{summary:i.summary??null,count:i.count??null}):(l||n)&&c?.phase?cn("working","agent-phase",c.at,{summary:c.summary??null}):l?cn("working","pane",u||w):i?.status==="waiting"?cn("waiting","operation",i.since,{summary:i.summary??null,count:i.count??null}):d?.count?cn("waiting",d.source||"pending",d.since,{summary:d.summary??null,count:d.count}):p&&f?cn("settled","obligations",p,{summary:"no open actions"}):cn("idle","fallback",p||w)}var cn,kU,DE=q(()=>{cn=(e,t,n,r={})=>({kind:e,source:t,since:n||0,...r});kU=new Set(["merged","closed","lost"])});async function BE(e){if(pd.has(e.id))return pd.get(e.id);let t=await K(e).catch(()=>[]),n=[];try{n=Sn(t)}catch{}let r=Zl(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 pd.set(e.id,p),p}var pd,jE=q(()=>{de();Ql();pd=new Map;ot.on("event",e=>{e?.trackId&&pd.delete(e.trackId)})});import{randomUUID as xU}from"node:crypto";async function pw(e,t,n={}){let r={operationId:xU(),kind:t,startedAt:Date.now(),...n};return fd.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 fw(e,t,n="completed",r=null){fd.get(e.id)?.operationId===t?.operationId&&fd.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 fd,LE,mw=q(()=>{de();fd=new Map;LE=e=>fd.get(e)||null});var g_={};Ep(g_,{HANDOFF_LATEST_REL:()=>zo,KNOWN_AGENTS:()=>bc,TRACK_NAME_MAX:()=>_w,addTrackRepo:()=>qw,adoptTrack:()=>cg,agentAvailability:()=>yd,announceNodeUpdate:()=>jn,answerFullscreenOffer:()=>tg,answerPrompt:()=>kd,archiveTrack:()=>Yo,archiveTrackForMergedPr:()=>nr,augmentFirstPromptAfterHandoff:()=>JE,buildAgentCmd:()=>Rw,canResumeSubtask:()=>m_,cancelQueued:()=>vc,cancelQueuedToDraft:()=>Bw,cancelStopJob:()=>Sc,cancelSubtask:()=>Rd,changedRepos:()=>Ho,commitTransferOut:()=>Id,createSetupTrack:()=>zw,createTrack:()=>Sd,deleteTrack:()=>Jw,demoteTransferredTracks:()=>ig,ensureLeadEpochs:()=>ga,forceMergeSubtask:()=>pg,getHandoffJob:()=>xa,getSubtaskJob:()=>_4,getTrack:()=>oe,getTransferOutJob:()=>og,healDeadLead:()=>gc,interruptLead:()=>vd,isArchiving:()=>h4,isHandoffNoteEcho:()=>Sw,isInterruptEcho:()=>Tw,isModelSwitchEcho:()=>Aw,leadCliDead:()=>Xw,listSubtaskJobs:()=>Zo,listTracks:()=>me,matchTranscriptsToBoxes:()=>ZE,mergeNotifyMessage:()=>u_,navigatePrompt:()=>Pw,notifyTrackForMergedPr:()=>rr,notifyTrackForResolvedPr:()=>Td,offerFollowupsForMergedPr:()=>Xo,pendingOffers:()=>Mw,queueGauges:()=>Dw,queueShipCompleteNotify:()=>Lw,queuedMessages:()=>Vo,reapArchivedOrphans:()=>eg,reconcileDemotedTracks:()=>Qw,reconcileHandoffOutcome:()=>d_,reconcileInterruptedHandoffs:()=>rg,reconcileInterruptedSubtasks:()=>lg,reconcileNodeUpdateNotices:()=>Cw,reconcileSubtaskOutcome:()=>f_,refreshStandingInstructions:()=>Gw,refuseIfTransferred:()=>ag,rehydrateLead:()=>Ac,removeTrackRepo:()=>Kw,renameTrack:()=>Zw,reposOf:()=>Bt,resolveTrackBox:()=>Vi,resolveTrackBoxByHookToken:()=>xc,restartLead:()=>Ed,resumeAgentCmd:()=>Ow,sayToLead:()=>Dt,sendOptionsForAgent:()=>vn,setTrackDraft:()=>Hw,setTrackModel:()=>Ww,startLeadHandoff:()=>_d,startSpinUpView:()=>Fw,startSubtask:()=>dg,startTransferOut:()=>sg,stopJobActive:()=>t_,subtaskMessages:()=>Nw,trackMessages:()=>bd,unarchiveTrack:()=>Ad});import Q from"node:fs/promises";import re from"node:path";import{randomUUID as wd}from"node:crypto";import{execFile as vU}from"node:child_process";import{promisify as SU}from"node:util";function Rw(e,{skipPermissions:t=!0}={}){let n=gd[e];if(!n)throw new Error(`unknown agent "${e}"`);let r=process.env[n.envVar];return r||(t&&n.skipFlag?`${n.base} ${n.skipFlag}`:n.base)}function Ow(e,t,{skipPermissions:n=!0,cwd:r=null,peerName:o=null}={}){let s=gd[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&&!tn(r,t)){let c=o&&je(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 ka(e){let t=gd[e];if(t)return process.env[t.envVar]||t.base}async function yd({maxAgeMs:e=6e4}={}){if(Qr.value&&Date.now()-Qr.at<e)return Qr.value;let t=Qr.value,n=await Promise.all(bc.map(async r=>{let o=await Cl(ka(r),{retries:[]});return o===Ss?[r,t?.[r]??!0]:[r,o===Ol]}));return Qr.value=Object.fromEntries(n),Qr.at=Date.now(),Qr.value}async function kc(e,t=!0){let n=Rw(e,{skipPermissions:t});if(await Cl(n)===vs){Qr.at=0;let r=n.split(/\s+/)[0],o=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.":nf[r]?`Install it on this node: ${nf[r]}`:"Its CLI must be installed and on PATH first.";throw new Error(`agent "${e}" isn't available on this box (command not found: ${r}). ${o}`)}return n}function JE(e,t=zo){return`${e.trim()}
210
210
 
211
- (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 vw(e){return e.role==="user"&&AU.test((e.text||"").trim())}async function ee(){return Vt||(mw||=(async()=>{try{Vt=JSON.parse(await Q.readFile(GE,"utf8"))}catch{Vt={tracks:[]}}finally{mw=null}return Vt})(),mw)}async function ae(){await Et(GE,Vt)}function IU(e,t){let n=JSON.stringify({trackId:e,...t})+`
212
- `;return hw=hw.then(()=>Q.mkdir(jn,{recursive:!0})).then(()=>Q.appendFile(SU,n)).catch(()=>{}),hw}async function Bn({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 Q.readFile(ww,"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)Ve(d)||!d.leadBox||(Ie(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 Q.mkdir(re.dirname(ww),{recursive:!0}),await Q.writeFile(ww,JSON.stringify({current:e,latest:t,at:Date.now()}))}catch{}return{announced:u}}async function Ow({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)||$U(e,c)||(Ie(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 $U(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 JE(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=>RU.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 YE(e,t,n,{kind:r}={}){let o=await ke(t);if(!o)throw new Error(`box "${t}" is not running`);let s=ka(o.agent),a=Yi({text:n,producer:Ji({kind:r,orchestration:!0}),kind:r||"orchestration",provider:o.agent}),i=we(await ee(),e)||null,c=Date.now(),l=null;try{l=await $r({cwd:o.cwd,sessionId:o.sessionId,sessionName:t,agent:o.agent,agentCmd:s})}catch(g){throw Zi(a,{ms:Date.now()-c,outcome:g?.code==="cli-not-running"?"cli-not-running":"blocked"}),await $n(i,a,oa(g)),g}Zi(a,{ms:Date.now()-c,outcome:l||"up"});let u=vn(o.agent,n);a.paste=!!u.paste;try{await nt(t,n,{...u,kind:r||"orchestration"})}catch(g){throw await $n(i,a,oa(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 $n(i,a,p?d.verdict==="unverified"?"unverified":"delivered":"unsubmitted"),await le({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=we(f,e);if(!w)return;let m=w.boxes.find(g=>g.name===t);Ie(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 OU(e){let t=re.join(gs(e),`${e.id}.ndjson`),n;try{n=await Q.stat(t)}catch{return null}let r=LE.get(e.id);if(r&&r.mtimeMs===n.mtimeMs)return r.at;let o=null;for(let s of await K(e)){if(s.type!=="turn.agent")continue;let a=s.payload?.ts??s.ts;a&&(!o||a>o)&&(o=a)}return LE.set(e.id,{mtimeMs:n.mtimeMs,at:o}),o}async function CU(e,t){let n=t.find(r=>r.name===e.leadBox);return n?.state!=="live"?{working:!1,prompted:!1}:zm(n.name,n.agent)}async function Nt(e,t=null,n=null){let r=t??new Map((await Qt()).map(y=>[y.name,y])),o=!!e.transferredTo,s=e.boxes.map(y=>{let $=o?null:r.get(y.name),O=eo.has(y.state)?y.state:$?y.role==="lead"?"live":y.state:"stopped";return{...y,state:O,cwd:$?.cwd||y.cwd,agent:$?.agent||y.agent,sessionId:$?.sessionId||y.sessionId}}),[a,{working:i,prompted:c},l,u]=await Promise.all([OU(e),CU(e,s),DE(e),n??Xn().catch(()=>[])]),d=wc.has(e.id),p=(u||[]).filter(y=>y.trackId===e.id&&!["merged","closed","lost"].includes(y.state)),f=BE(e.id),w=f&&{status:"waiting",since:f.startedAt,summary:f.summary??null,count:f.count??null}||CE(p),m=s.find(y=>y.name===e.leadBox)?.state==="live",g=m?Vo(e.id).filter(y=>y.kind!=="ship-notify"&&y.kind!=="prompt-answer"):[],b=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(y=>y.ts||Date.now())),summary:"a queued message is about to send"}:null,x=NE({archivedAt:e.archivedAt,archiving:d,prompted:c,openActions:l.openActions,openActionSince:l.openActionSince,prDecisions:ME(p),operation:w,phase:l.phase,working:i,workingSince:l.currentTurnAt,pending:b,completedTurnAt:l.completedTurnAt||a,live:m});return{...e,boxes:s,lastResponseAt:a,working:i,prompted:c,archiving:d,status:x}}function XE(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-MU,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 ZE(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=xk(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=XE(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 dk(p.box,p.sessionId),n=!0}}return n}async function me(){let e=await ee();await ZE(e)&&await ae();let t=new Map((await Qt()).map(r=>[r.name,r])),n=await Xn().catch(()=>[]);return Promise.all(e.tracks.map(r=>Nt(r,t,n)))}async function Vi(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 xc(e){let t=La(e);if(!t)return null;let n=await ee();for(let r of n.tracks||[])for(let o of r.boxes||[])if(o.hookTokenHash&&Qy(o.hookTokenHash,t))return{track:r,box:o};return null}async function oe(e){let t=await ee(),n=we(t,e);return n?(await ZE(t)&&await ae(),Nt(n)):null}async function Cw(e){let t=await K(e).catch(()=>[]),n;try{n=Sn(t)}catch{return[]}let r=Zl(n).map(s=>({kind:s.kind,id:s.offerId??s.proposalId??s.id,ts:s.ts??null})),o=[];try{o=N0(t)}catch{o=[]}return r.concat(o.map(s=>({kind:"pr-open",id:`${s.repo??""}#${s.number}`,ts:null})))}function Sw(e){if(e.role!=="user")return!1;let t=(e.text||"").trim();return(NU[e.agent]||[]).some(n=>n.test(t))}function Tw(e){let t=(e.text||"").trim();return t?PU.some(n=>n.test(t)):!1}async function yd(e,t={}){let n=await oe(e);if(!n)return null;let r=new Set([...n.events.filter(I=>I.type==="orchestration-prompt"&&I.prompt).map(I=>String(I.prompt).trim()),...n.events.filter(I=>I.type==="said"&&I.text).map(I=>String(I.text).trim())]),o=xa(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=Dh(n.id),c=!!(i&&!i.finishedAt),l=c&&i.startedAt&&i.box?[{box:i.box,from:i.startedAt,to:Date.now()+1e12}]:[],u=[...hA(n),...l],p={windows:[...rx(n),...ox(n,nu),...a,...u]},w=(await Promise.all(n.boxes.map(I=>sm(I,t)))).flat(),m=w.map(I=>{let j={kind:"message",...I};if(j.role==="assistant"&&(j.text||"").trim()&&j.tools?.length){let fe=jr(j.agent).cliTools,Pe=j.tools.filter(Ce=>!fe.has(Ce));return{...j,tools:Pe.length?Pe:void 0}}return j}).map(I=>{if(I.role!=="user")return I;let j=S0(I);return j?j.kind==="suppress"?null:{...I,note:j,text:T0(j)}:I}).filter(Boolean).filter(I=>!(I.role==="user"&&r.has((I.text||"").trim()))).filter(I=>!Sw(I)).filter(I=>!Tw(I)).filter(I=>!vw(I)).filter(I=>!ow(I)).filter(I=>I.role!=="assistant"||!!(I.text||"").trim()||!!I.images?.length).filter(I=>!sx(I,p)),g=m.filter(I=>I.failed&&I.text===xo);if(g.length){let I=new Map;for(let j of g){if(!I.has(j.box)){let Ce=[...(await je(j.box,{lines:tt}).catch(()=>"")).matchAll(/^\s*■\s+(.+?)\s*$/gm)].map(wn=>wn[1]);I.set(j.box,Ce.length?Ce[Ce.length-1]:null)}let fe=I.get(j.box);fe&&(j.text=`\u25A0 ${fe}`)}}let b=await Promise.all(n.boxes.map(I=>Ux(I,t)));await WT(n,b.flat());let{agentTurnBoxes:x}=await UT(n,m);for(let I of n.boxes)x.has(I.name)&&I.cwd&&kl(I.cwd);await Dv(n),await vA(n,m).catch(()=>{});for(let I of n.boxes)I.agent==="codex"&&I.state==="live"&&await KT(n,I),I.agent==="cursor"&&I.state==="live"&&await YT(n,I);let y=await Promise.all(n.boxes.map(I=>Fx(I,t)));await HT(n,y.flat().filter(I=>!gw(I.box,I.ts,u)));let $=await K(n),O=c&&i.viewId?i.viewId:null,M=Vv($),H=Sn($).filter(I=>!(I.kind==="message"&&(Sw(I)||Tw(I)||vw(I)||ow(I)))&&!(I.kind==="view-card"&&O&&I.viewId===O)),P=Jv(H,M),E=H.filter(I=>!(I.kind==="message"&&I.role==="assistant"&&!P.has(I)&&gw(I.box,I.ts,M))),R=Uf($,E).map(I=>({kind:"command-batch",id:I.id,ts:I.pending?I.ts:(I.anchorTs??I.ts)-1,anchorTs:I.anchorTs,anchorBox:I.anchorBox,agent:I.agent,boxRole:I.boxRole,commands:I.commands,pending:I.pending})).filter(I=>!gw(I.anchorBox,I.anchorTs??I.ts,u)),G=C0(M0([...E,...R].filter(I=>I.ts!=null).sort((I,j)=>I.ts-j.ts))),V=jU(n),A=V.size?G.filter(I=>I.kind==="event"||!V.has(I.box??I.anchorBox)):G,_=n.boxes.find(I=>I.name===n.leadBox)||null,N=_?await ci(_.cwd,_.sessionId,{fallbackNewest:!1}):null;if(!N&&_){let I=[...$].reverse().find(j=>j.type==="context.usage"&&j.boxId===_.name);I?.payload?.window&&(N={pct:I.payload.pct??(I.payload.occupancy!=null?I.payload.occupancy/I.payload.window:null),occupancy:I.payload.occupancy??null,window:I.payload.window,windowKnown:!0,model:I.payload.model||null})}let U=[...w].reverse().find(I=>I.role==="assistant"&&I.model),z=U?.model||null,ue=[...n.events||[]].reverse().find(I=>I.type==="model-change"),pe=N?.model||z;ue&&(!U?.ts||ue.at>=U.ts)&&(pe=ue.to);let Se=_?await je(_.name,{lines:tt}).catch(()=>""):"",Ae=_&&Ro(_.agent,Se)?await Gn(_.name).catch(()=>Se):Se,W=_?Br(_,Ae):null;if(W&&_){let I=cu(_,W,Ae);if(I){let j=rv(_.name,W.promptId);j.action!=="give-up"&&(j.action==="send"&&(Ke(_.name,I.keys,{kind:"auto-reject"}).catch(()=>{}),j.first&&C(n,{type:"prompt.autoRejected",actor:"system",source:"pane",boxId:_.name,provider:_.agent,payload:{ts:Date.now(),promptId:W.promptId,rule:I.id}}).catch(()=>{})),W=null)}}!W&&_&&!Cs(_.agent,Se)&&!Vo(n.id).length&&(W=Bf(A,{leadBoxId:_.name,provider:_.agent,isAnswered:I=>$.some(j=>j.type==="prompt.answered"&&j.payload?.promptId===I)})),W&&jv(n,_,W);let te=A.filter(I=>!(I.kind==="message"&&I.role==="assistant"&&I.ask&&!String(I.text||"").trim()&&!I.images?.length)),J=!!_&&Nu(_.name,_.agent,Se)&&!W;_&&!_.readyAt&&(J||W||Se&&Ms(_.agent,Se))&&(_.readyAt=Date.now(),await ae());let ge=!!_&&!_.readyAt&&Date.now()-(n.createdAt||0)<DU;if(n.kind==="setup"&&n.setup?.provider&&!n.setup.connectedAt&&_&&Ms(_.agent,Se)&&!W){let I=await ee(),j=we(I,n.id);j?.setup&&!j.setup.connectedAt&&(j.setup.connectedAt=Date.now(),n.setup.connectedAt=j.setup.connectedAt,await C(j,{type:"provider.connected",actor:"system",source:"pane",boxId:_.name,provider:_.agent,payload:{provider:_.agent,ts:j.setup.connectedAt}}).catch(()=>{}),await ae())}let Oe=s?{running:!0,step:o.step,toAgent:o.toAgent||null}:null,Me=null;if(c){let I=Date.now()-i.startedAt;if(i.viewId&&!J){let j=Zu(n.id);j&&(Ie(n,"view-spinup",{box:i.box,startedAt:i.startedAt,endedAt:j.finishedAt}),await ae())}else if(W||I>fA&&!J&&!i.viewId||I>Ph){let j=W?"needs-input":I>Ph?"timeout":"no-view";Zu(n.id,{error:j})&&await C(n,{type:"view.spinup.failed",actor:"orchestrator",source:"orchestrator",boxId:i.box,provider:_?.agent||null,payload:{ts:i.startedAt,name:i.name,reason:j}}).catch(()=>{})}else Me={running:!0,step:i.step,name:i.name}}return{trackId:n.id,leadBox:n.leadBox,items:te,context:N?{pct:N.pct,occupancy:N.occupancy,window:N.window,windowKnown:N.windowKnown,model:N.model}:null,models:{current:pe,options:$v(_?.agent)},pendingPrompt:W,working:J,stopping:e_(n.id),leadStarting:ge,handoff:Oe,view:Me,queued:Vo(n.id).filter(I=>I.kind!=="ship-notify"&&I.kind!=="prompt-answer"),draft:n.draft||null,draftRev:n.draftRev||0}}function jU(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 Mw(e,t){let n=await oe(e);if(!n)return null;let r=Zo(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 K(n),a=Sn(s).filter(d=>d.box===o&&!(d.kind==="message"&&d.role==="assistant"&&d.ask&&!String(d.text||"").trim()&&!d.images?.length)),i=Uf(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 je(o,{lines:tt}).catch(()=>"");u=Nu(o,l.agent||r.agent,d)}return{items:c,working:u,box:o,agent:r.agent,task:r.task}}async function bd(e,{promptId:t,answers:n,text:r}={}){let o=we(await ee(),e);if(!o)throw new Error(`track "${e}" not found`);Sc(e,"prompt-answer");let s=o.boxes.find(w=>w.name===o.leadBox);if(!s)throw new Error(`track "${e}" has no lead box`);if(!await ke(o.leadBox))throw new Error(`lead box "${o.leadBox}" is not running`);let i=await fm(s);if(i||(i=await BU(o,s)),!i)throw new Error("no pending prompt to answer");if(t&&t!==i.promptId)throw new Error("prompt changed since it was shown \u2014 reload and answer the current prompt");let c;if(i.answerMode==="text"){let w=typeof r=="string"?r.trim():"";if(!w)throw new Error("this prompt needs a code \u2014 paste it into the card");if(/\s/.test(w)||w.length>2048)throw new Error("that doesn't look like a sign-in code \u2014 paste the code exactly as shown");await nt(o.leadBox,w,{enter:!0,kind:"answer-prompt"}),c={mode:"text-input",value:"\u2039code\u203A",count:1,redacted:!0}}else if(i.answerMode==="esc")await Ke(o.leadBox,["Escape"],{kind:"answer-prompt"}),c={mode:"keys",value:"Escape",count:1};else if(i.answerMode==="say"){let w=I0(i,n||[],typeof r=="string"?r:"");if(!w)throw new Error("no answer selected \u2014 pick an option or reply in chat");await Dt(o.id,w,{kind:"prompt-answer"}),c={mode:"say",value:w,count:1}}else if(i.provider==="claude"||i.answerMode==="keys"){let w=Qx(i,n||[]);await Ke(o.leadBox,w,{kind:"answer-prompt"}),c={mode:"keys",value:w.join(" "),count:w.length}}else{let w=Jk(i,n||[]);await nt(o.leadBox,w,{enter:!0,kind:"answer-prompt"}),c={mode:"text",value:w,count:1}}if(i.answerMode==="say"){let w=i.questions||[];for(let m=0;m<w.length;m++){let g=w[m],b=new Set(Array.isArray(n?.[m])?n[m]:[]),x=[...b].map($=>g.options?.[$]).filter(Boolean).map($=>({label:$.label,description:$.description||""})),y=(g.options||[]).map(($,O)=>b.has(O)?null:$?.label).filter(Boolean);Rm(o,s,i,{...c,groupId:i.groupId||i.promptId,questionIndex:m,questionTotal:i.questionTotal??w.length,header:g.header||"",question:g.question||"",multiSelect:!!g.multiSelect,chosen:x,rejected:y})}return await le({flow:"prompt",phase:"answered",sessionName:o.leadBox,agent:s.agent,provider:i.provider,promptId:i.promptId,...c}).catch(()=>{}),{ok:!0,promptId:i.promptId,sent:c.count}}let l=i.questions?.[0]||{},u=new Set(Array.isArray(n?.[0])?n[0]:[]),d=[...u].map(w=>l.options?.[w]).filter(Boolean).map(w=>({label:w.label,description:w.description||""})),p=(l.options||[]).map((w,m)=>u.has(m)?null:w?.label).filter(Boolean),f=i.review?"review":/^claude:model-confirm:/.test(i.promptId||"")?"model-confirm":/^claude:resume-confirm:/.test(i.promptId||"")?"resume-confirm":void 0;return c={...c,groupId:i.groupId||i.promptId,questionIndex:i.questionIndex??0,questionTotal:i.questionTotal??1,header:l.header||"",question:l.question||"",multiSelect:!!l.multiSelect,chosen:d,rejected:p,...f?{control:f}:{}},await le({flow:"prompt",phase:"answered",sessionName:o.leadBox,agent:s.agent,provider:i.provider,promptId:i.promptId,...c}).catch(()=>{}),Rm(o,s,i,c),{ok:!0,promptId:i.promptId,sent:c.count}}async function BU(e,t){if(!t)return null;let n=await K(e).catch(()=>[]);return Bf(Sn(n),{leadBoxId:t.name,provider:t.agent,isAnswered:r=>n.some(o=>o.type==="prompt.answered"&&o.payload?.promptId===r)})}async function Nw(e,{promptId:t,questionIndex:n}={}){let r=we(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 fm(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=ev(a,n);return c.length?(await Ke(r.leadBox,c,{kind:"navigate-prompt"}),await le({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 kd(e){let t=ha.get(e);return t||(t={items:[],timer:null,flushing:!1,idleSince:null},ha.set(e,t)),t}function Vo(e){return(ha.get(e)?.items??[]).map(({delivery:t,...n})=>({...n}))}function Pw(e=Date.now()){let t=0,n=0;for(let r of ha.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 FU(e,t,n){let r=t.filter(o=>o.delivery&&!o.delivery.settled);r.length&&(async()=>{let o=we(await ee(),e)||null;for(let s of r)await $n(o,s.delivery,`dropped:${n}`)})().catch(()=>{})}function vc(e,t="cancel"){let n=ha.get(e);if(!n)return[];let r=n.items.splice(0);return n.idleSince=null,n.timer&&(clearInterval(n.timer),n.timer=null),FU(e,r,t),r}async function Dw(e){let t=vc(e),n=t.filter(o=>o.text&&!o.kind).map(o=>o.text),r=null;if(n.length){let o=we(await ee(),e);if(o)return r=wa(o,n),await ae(),{removed:t,restored:r,draftRev:o.draftRev||0}}return{removed:t,restored:r,draftRev:null}}function jw(e){let t=kd(e);t.timer||(t.timer=setInterval(()=>UU(e).catch(()=>{}),LU))}async function UU(e){let t=ha.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=we(await ee(),e);if(!n||n.archivedAt){vc(e,"archived");return}let r=l=>{for(let u of t.items)oA(u.delivery,l)},o=xa(e);if(o&&!o.finishedAt&&o.step!=="done"&&!o.error){Go(t,!1),r("handoff");return}let s=await ke(n.leadBox),a=n.boxes.find(l=>l.name===n.leadBox);if(s&&await Yw(s)&&(s=await gc(n,a,"queue")?await ke(n.leadBox):null,await ae()),!s){Go(t,!1),r("noSession");return}if(Co(a?.agent)){Go(t,!1),r("cap");return}let i=await je(n.leadBox,{lines:tt}).catch(()=>"");if(ql(a?.agent,i)){Go(t,!1),r("busy");return}if(Ro(a?.agent,i)){let l=await Gn(n.leadBox).catch(()=>i);if(Br(a,l)){Go(t,!1),r("prompt");return}}if(!Go(t,!0)){r("grace");return}let c=t.items.shift();t.idleSince=null,c.delivery&&(c.delivery.dequeuedAt=Date.now());try{await Aw(n,a,s,c.text,c.kind??null,c.attachments??null,c.delivery??null)}catch(l){if(l?.code!=="cli-not-running")throw c.delivery&&await $n(n,c.delivery,oa(l)),l;t.items.unshift(c),c.delivery&&(c.delivery.requeued+=1,c.delivery.dequeuedAt=null,await Xi(n,c.delivery,{position:1,reason:"requeue"})),await gc(n,a,"queue-gate")}await ae()}finally{t.flushing=!1}}}async function QE(e,t,n,r){let o=Co(t?.agent);if(!o)return;if(!r&&typeof n=="string"&&n.trim()&&(wa(e,[n]),await ae()),bv(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 HU(e,t){let n=await je(e.leadBox,{lines:tt}).catch(()=>"");if(!Ro(t?.agent,n))return!1;let r=await Gn(e.leadBox).catch(()=>n);return!!Br(t,r)}async function Aw(e,t,n,r,o=null,s=null,a=null){a||(a=Yi({text:r,producer:Ji({kind:o}),kind:o,provider:t?.agent??null,attachments:Array.isArray(s)?s.length:0})),a.provider??=t?.agent??null,await QE(e,t,r,o);let i=fc.get(e.id)||0,c=r,l=!1,u=e.pendingHandoffHydrate||null;e.pendingHandoffHydrate&&(c=VE(r,e.pendingHandoffHydrate.artifact||zo),delete e.pendingHandoffHydrate,l=!0);let d=Array.isArray(s)?s.filter(m=>m&&m.rel):[];if(d.length){let m=TE(d.map(g=>g.rel));c=c.trim()?`${c.trim()}
211
+ (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 Sw(e){return e.role==="user"&&EU.test((e.text||"").trim())}async function ee(){return Vt||(hw||=(async()=>{try{Vt=JSON.parse(await Q.readFile(zE,"utf8"))}catch{Vt={tracks:[]}}finally{hw=null}return Vt})(),hw)}async function ae(){await Et(zE,Vt)}function $U(e,t){let n=JSON.stringify({trackId:e,...t})+`
212
+ `;return ww=ww.then(()=>Q.mkdir(Bn,{recursive:!0})).then(()=>Q.appendFile(TU,n)).catch(()=>{}),ww}async function jn({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 Q.readFile(gw,"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)Ve(d)||!d.leadBox||(Ie(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 Q.mkdir(re.dirname(gw),{recursive:!0}),await Q.writeFile(gw,JSON.stringify({current:e,latest:t,at:Date.now()}))}catch{}return{announced:u}}async function Cw({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)||RU(e,c)||(Ie(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 RU(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 YE(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=>OU.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 XE(e,t,n,{kind:r}={}){let o=await ke(t);if(!o)throw new Error(`box "${t}" is not running`);let s=ka(o.agent),a=Yi({text:n,producer:Ji({kind:r,orchestration:!0}),kind:r||"orchestration",provider:o.agent}),i=we(await ee(),e)||null,c=Date.now(),l=null;try{l=await $r({cwd:o.cwd,sessionId:o.sessionId,sessionName:t,agent:o.agent,agentCmd:s})}catch(g){throw Zi(a,{ms:Date.now()-c,outcome:g?.code==="cli-not-running"?"cli-not-running":"blocked"}),await $n(i,a,oa(g)),g}Zi(a,{ms:Date.now()-c,outcome:l||"up"});let u=vn(o.agent,n);a.paste=!!u.paste;try{await nt(t,n,{...u,kind:r||"orchestration"})}catch(g){throw await $n(i,a,oa(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 $n(i,a,p?d.verdict==="unverified"?"unverified":"delivered":"unsubmitted"),await le({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=we(f,e);if(!w)return;let m=w.boxes.find(g=>g.name===t);Ie(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 CU(e){let t=re.join(gs(e),`${e.id}.ndjson`),n;try{n=await Q.stat(t)}catch{return null}let r=FE.get(e.id);if(r&&r.mtimeMs===n.mtimeMs)return r.at;let o=null;for(let s of await K(e)){if(s.type!=="turn.agent")continue;let a=s.payload?.ts??s.ts;a&&(!o||a>o)&&(o=a)}return FE.set(e.id,{mtimeMs:n.mtimeMs,at:o}),o}async function MU(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 Nt(e,t=null,n=null){let r=t??new Map((await Qt()).map(y=>[y.name,y])),o=!!e.transferredTo,s=e.boxes.map(y=>{let $=o?null:r.get(y.name),O=eo.has(y.state)?y.state:$?y.role==="lead"?"live":y.state:"stopped";return{...y,state:O,cwd:$?.cwd||y.cwd,agent:$?.agent||y.agent,sessionId:$?.sessionId||y.sessionId}}),[a,{working:i,prompted:c},l,u]=await Promise.all([CU(e),MU(e,s),BE(e),n??Xn().catch(()=>[])]),d=wc.has(e.id),p=(u||[]).filter(y=>y.trackId===e.id&&!["merged","closed","lost"].includes(y.state)),f=LE(e.id),w=f&&{status:"waiting",since:f.startedAt,summary:f.summary??null,count:f.count??null}||ME(p),m=s.find(y=>y.name===e.leadBox)?.state==="live",g=m?Vo(e.id).filter(y=>y.kind!=="ship-notify"&&y.kind!=="prompt-answer"):[],b=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(y=>y.ts||Date.now())),summary:"a queued message is about to send"}:null,x=PE({archivedAt:e.archivedAt,archiving:d,prompted:c,openActions:l.openActions,openActionSince:l.openActionSince,prDecisions:NE(p),operation:w,phase:l.phase,working:i,workingSince:l.currentTurnAt,pending:b,completedTurnAt:l.completedTurnAt||a,live:m});return{...e,boxes:s,lastResponseAt:a,working:i,prompted:c,archiving:d,status:x}}function ZE(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-NU,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 QE(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=xk(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=ZE(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 dk(p.box,p.sessionId),n=!0}}return n}async function me(){let e=await ee();await QE(e)&&await ae();let t=new Map((await Qt()).map(r=>[r.name,r])),n=await Xn().catch(()=>[]);return Promise.all(e.tracks.map(r=>Nt(r,t,n)))}async function Vi(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 xc(e){let t=La(e);if(!t)return null;let n=await ee();for(let r of n.tracks||[])for(let o of r.boxes||[])if(o.hookTokenHash&&Qy(o.hookTokenHash,t))return{track:r,box:o};return null}async function oe(e){let t=await ee(),n=we(t,e);return n?(await QE(t)&&await ae(),Nt(n)):null}async function Mw(e){let t=await K(e).catch(()=>[]),n;try{n=Sn(t)}catch{return[]}let r=Zl(n).map(s=>({kind:s.kind,id:s.offerId??s.proposalId??s.id,ts:s.ts??null})),o=[];try{o=N0(t)}catch{o=[]}return r.concat(o.map(s=>({kind:"pr-open",id:`${s.repo??""}#${s.number}`,ts:null})))}function Tw(e){if(e.role!=="user")return!1;let t=(e.text||"").trim();return(PU[e.agent]||[]).some(n=>n.test(t))}function Aw(e){let t=(e.text||"").trim();return t?DU.some(n=>n.test(t)):!1}async function bd(e,t={}){let n=await oe(e);if(!n)return null;let r=new Set([...n.events.filter(I=>I.type==="orchestration-prompt"&&I.prompt).map(I=>String(I.prompt).trim()),...n.events.filter(I=>I.type==="said"&&I.text).map(I=>String(I.text).trim())]),o=xa(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=Bh(n.id),c=!!(i&&!i.finishedAt),l=c&&i.startedAt&&i.box?[{box:i.box,from:i.startedAt,to:Date.now()+1e12}]:[],u=[...wA(n),...l],p={windows:[...rx(n),...ox(n,nu),...a,...u]},w=(await Promise.all(n.boxes.map(I=>am(I,t)))).flat(),m=w.map(I=>{let B={kind:"message",...I};if(B.role==="assistant"&&(B.text||"").trim()&&B.tools?.length){let fe=Br(B.agent).cliTools,Pe=B.tools.filter(Ce=>!fe.has(Ce));return{...B,tools:Pe.length?Pe:void 0}}return B}).map(I=>{if(I.role!=="user")return I;let B=S0(I);return B?B.kind==="suppress"?null:{...I,note:B,text:T0(B)}:I}).filter(Boolean).filter(I=>!(I.role==="user"&&r.has((I.text||"").trim()))).filter(I=>!Tw(I)).filter(I=>!Aw(I)).filter(I=>!Sw(I)).filter(I=>!sw(I)).filter(I=>I.role!=="assistant"||!!(I.text||"").trim()||!!I.images?.length).filter(I=>!sx(I,p)),g=m.filter(I=>I.failed&&I.text===xo);if(g.length){let I=new Map;for(let B of g){if(!I.has(B.box)){let Ce=[...(await Be(B.box,{lines:tt}).catch(()=>"")).matchAll(/^\s*■\s+(.+?)\s*$/gm)].map(wn=>wn[1]);I.set(B.box,Ce.length?Ce[Ce.length-1]:null)}let fe=I.get(B.box);fe&&(B.text=`\u25A0 ${fe}`)}}let b=await Promise.all(n.boxes.map(I=>Ux(I,t)));await qT(n,b.flat());let{agentTurnBoxes:x}=await HT(n,m);for(let I of n.boxes)x.has(I.name)&&I.cwd&&kl(I.cwd);await Dv(n),await SA(n,m).catch(()=>{});for(let I of n.boxes)I.agent==="codex"&&I.state==="live"&&await GT(n,I),I.agent==="cursor"&&I.state==="live"&&await XT(n,I);let y=await Promise.all(n.boxes.map(I=>Fx(I,t)));await WT(n,y.flat().filter(I=>!yw(I.box,I.ts,u)));let $=await K(n),O=c&&i.viewId?i.viewId:null,M=Vv($),H=Sn($).filter(I=>!(I.kind==="message"&&(Tw(I)||Aw(I)||Sw(I)||sw(I)))&&!(I.kind==="view-card"&&O&&I.viewId===O)),P=Jv(H,M),E=H.filter(I=>!(I.kind==="message"&&I.role==="assistant"&&!P.has(I)&&yw(I.box,I.ts,M))),R=Hf($,E).map(I=>({kind:"command-batch",id:I.id,ts:I.pending?I.ts:(I.anchorTs??I.ts)-1,anchorTs:I.anchorTs,anchorBox:I.anchorBox,agent:I.agent,boxRole:I.boxRole,commands:I.commands,pending:I.pending})).filter(I=>!yw(I.anchorBox,I.anchorTs??I.ts,u)),G=C0(M0([...E,...R].filter(I=>I.ts!=null).sort((I,B)=>I.ts-B.ts))),V=jU(n),A=V.size?G.filter(I=>I.kind==="event"||!V.has(I.box??I.anchorBox)):G,_=n.boxes.find(I=>I.name===n.leadBox)||null,N=_?await ci(_.cwd,_.sessionId,{fallbackNewest:!1}):null;if(!N&&_){let I=[...$].reverse().find(B=>B.type==="context.usage"&&B.boxId===_.name);I?.payload?.window&&(N={pct:I.payload.pct??(I.payload.occupancy!=null?I.payload.occupancy/I.payload.window:null),occupancy:I.payload.occupancy??null,window:I.payload.window,windowKnown:!0,model:I.payload.model||null})}let U=[...w].reverse().find(I=>I.role==="assistant"&&I.model),z=U?.model||null,ue=[...n.events||[]].reverse().find(I=>I.type==="model-change"),pe=N?.model||z;ue&&(!U?.ts||ue.at>=U.ts)&&(pe=ue.to);let Se=_?await Be(_.name,{lines:tt}).catch(()=>""):"",Ae=_&&Ro(_.agent,Se)?await Gn(_.name).catch(()=>Se):Se,W=_?jr(_,Ae):null;if(W&&_){let I=cu(_,W,Ae);if(I){let B=rv(_.name,W.promptId);B.action!=="give-up"&&(B.action==="send"&&(Ke(_.name,I.keys,{kind:"auto-reject"}).catch(()=>{}),B.first&&C(n,{type:"prompt.autoRejected",actor:"system",source:"pane",boxId:_.name,provider:_.agent,payload:{ts:Date.now(),promptId:W.promptId,rule:I.id}}).catch(()=>{})),W=null)}}!W&&_&&!Cs(_.agent,Se)&&!Vo(n.id).length&&(W=Lf(A,{leadBoxId:_.name,provider:_.agent,isAnswered:I=>$.some(B=>B.type==="prompt.answered"&&B.payload?.promptId===I)})),W&&Bv(n,_,W);let te=A.filter(I=>!(I.kind==="message"&&I.role==="assistant"&&I.ask&&!String(I.text||"").trim()&&!I.images?.length)),J=!!_&&Nu(_.name,_.agent,Se)&&!W;_&&!_.readyAt&&(J||W||Se&&Ms(_.agent,Se))&&(_.readyAt=Date.now(),await ae());let ge=!!_&&!_.readyAt&&Date.now()-(n.createdAt||0)<BU;if(n.kind==="setup"&&n.setup?.provider&&!n.setup.connectedAt&&_&&Ms(_.agent,Se)&&!W){let I=await ee(),B=we(I,n.id);B?.setup&&!B.setup.connectedAt&&(B.setup.connectedAt=Date.now(),n.setup.connectedAt=B.setup.connectedAt,await C(B,{type:"provider.connected",actor:"system",source:"pane",boxId:_.name,provider:_.agent,payload:{provider:_.agent,ts:B.setup.connectedAt}}).catch(()=>{}),await ae())}let Oe=s?{running:!0,step:o.step,toAgent:o.toAgent||null}:null,Me=null;if(c){let I=Date.now()-i.startedAt;if(i.viewId&&!J){let B=Qu(n.id);B&&(Ie(n,"view-spinup",{box:i.box,startedAt:i.startedAt,endedAt:B.finishedAt}),await ae())}else if(W||I>mA&&!J&&!i.viewId||I>Dh){let B=W?"needs-input":I>Dh?"timeout":"no-view";Qu(n.id,{error:B})&&await C(n,{type:"view.spinup.failed",actor:"orchestrator",source:"orchestrator",boxId:i.box,provider:_?.agent||null,payload:{ts:i.startedAt,name:i.name,reason:B}}).catch(()=>{})}else Me={running:!0,step:i.step,name:i.name}}return{trackId:n.id,leadBox:n.leadBox,items:te,context:N?{pct:N.pct,occupancy:N.occupancy,window:N.window,windowKnown:N.windowKnown,model:N.model}:null,models:{current:pe,options:$v(_?.agent)},pendingPrompt:W,working:J,stopping:t_(n.id),leadStarting:ge,handoff:Oe,view:Me,queued:Vo(n.id).filter(I=>I.kind!=="ship-notify"&&I.kind!=="prompt-answer"),draft:n.draft||null,draftRev:n.draftRev||0}}function jU(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 Nw(e,t){let n=await oe(e);if(!n)return null;let r=Zo(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 K(n),a=Sn(s).filter(d=>d.box===o&&!(d.kind==="message"&&d.role==="assistant"&&d.ask&&!String(d.text||"").trim()&&!d.images?.length)),i=Hf(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 Be(o,{lines:tt}).catch(()=>"");u=Nu(o,l.agent||r.agent,d)}return{items:c,working:u,box:o,agent:r.agent,task:r.task}}async function kd(e,{promptId:t,answers:n,text:r}={}){let o=we(await ee(),e);if(!o)throw new Error(`track "${e}" not found`);Sc(e,"prompt-answer");let s=o.boxes.find(w=>w.name===o.leadBox);if(!s)throw new Error(`track "${e}" has no lead box`);if(!await ke(o.leadBox))throw new Error(`lead box "${o.leadBox}" is not running`);let i=await mm(s);if(i||(i=await LU(o,s)),!i)throw new Error("no pending prompt to answer");if(t&&t!==i.promptId)throw new Error("prompt changed since it was shown \u2014 reload and answer the current prompt");let c;if(i.answerMode==="text"){let w=typeof r=="string"?r.trim():"";if(!w)throw new Error("this prompt needs a code \u2014 paste it into the card");if(/\s/.test(w)||w.length>2048)throw new Error("that doesn't look like a sign-in code \u2014 paste the code exactly as shown");await nt(o.leadBox,w,{enter:!0,kind:"answer-prompt"}),c={mode:"text-input",value:"\u2039code\u203A",count:1,redacted:!0}}else if(i.answerMode==="esc")await Ke(o.leadBox,["Escape"],{kind:"answer-prompt"}),c={mode:"keys",value:"Escape",count:1};else if(i.answerMode==="say"){let w=I0(i,n||[],typeof r=="string"?r:"");if(!w)throw new Error("no answer selected \u2014 pick an option or reply in chat");await Dt(o.id,w,{kind:"prompt-answer"}),c={mode:"say",value:w,count:1}}else if(i.provider==="claude"||i.answerMode==="keys"){let w=Qx(i,n||[]);await Ke(o.leadBox,w,{kind:"answer-prompt"}),c={mode:"keys",value:w.join(" "),count:w.length}}else{let w=Jk(i,n||[]);await nt(o.leadBox,w,{enter:!0,kind:"answer-prompt"}),c={mode:"text",value:w,count:1}}if(i.answerMode==="say"){let w=i.questions||[];for(let m=0;m<w.length;m++){let g=w[m],b=new Set(Array.isArray(n?.[m])?n[m]:[]),x=[...b].map($=>g.options?.[$]).filter(Boolean).map($=>({label:$.label,description:$.description||""})),y=(g.options||[]).map(($,O)=>b.has(O)?null:$?.label).filter(Boolean);Om(o,s,i,{...c,groupId:i.groupId||i.promptId,questionIndex:m,questionTotal:i.questionTotal??w.length,header:g.header||"",question:g.question||"",multiSelect:!!g.multiSelect,chosen:x,rejected:y})}return await le({flow:"prompt",phase:"answered",sessionName:o.leadBox,agent:s.agent,provider:i.provider,promptId:i.promptId,...c}).catch(()=>{}),{ok:!0,promptId:i.promptId,sent:c.count}}let l=i.questions?.[0]||{},u=new Set(Array.isArray(n?.[0])?n[0]:[]),d=[...u].map(w=>l.options?.[w]).filter(Boolean).map(w=>({label:w.label,description:w.description||""})),p=(l.options||[]).map((w,m)=>u.has(m)?null:w?.label).filter(Boolean),f=i.review?"review":/^claude:model-confirm:/.test(i.promptId||"")?"model-confirm":/^claude:resume-confirm:/.test(i.promptId||"")?"resume-confirm":void 0;return c={...c,groupId:i.groupId||i.promptId,questionIndex:i.questionIndex??0,questionTotal:i.questionTotal??1,header:l.header||"",question:l.question||"",multiSelect:!!l.multiSelect,chosen:d,rejected:p,...f?{control:f}:{}},await le({flow:"prompt",phase:"answered",sessionName:o.leadBox,agent:s.agent,provider:i.provider,promptId:i.promptId,...c}).catch(()=>{}),Om(o,s,i,c),{ok:!0,promptId:i.promptId,sent:c.count}}async function LU(e,t){if(!t)return null;let n=await K(e).catch(()=>[]);return Lf(Sn(n),{leadBoxId:t.name,provider:t.agent,isAnswered:r=>n.some(o=>o.type==="prompt.answered"&&o.payload?.promptId===r)})}async function Pw(e,{promptId:t,questionIndex:n}={}){let r=we(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 mm(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=ev(a,n);return c.length?(await Ke(r.leadBox,c,{kind:"navigate-prompt"}),await le({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 xd(e){let t=ha.get(e);return t||(t={items:[],timer:null,flushing:!1,idleSince:null},ha.set(e,t)),t}function Vo(e){return(ha.get(e)?.items??[]).map(({delivery:t,...n})=>({...n}))}function Dw(e=Date.now()){let t=0,n=0;for(let r of ha.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 UU(e,t,n){let r=t.filter(o=>o.delivery&&!o.delivery.settled);r.length&&(async()=>{let o=we(await ee(),e)||null;for(let s of r)await $n(o,s.delivery,`dropped:${n}`)})().catch(()=>{})}function vc(e,t="cancel"){let n=ha.get(e);if(!n)return[];let r=n.items.splice(0);return n.idleSince=null,n.timer&&(clearInterval(n.timer),n.timer=null),UU(e,r,t),r}async function Bw(e){let t=vc(e),n=t.filter(o=>o.text&&!o.kind).map(o=>o.text),r=null;if(n.length){let o=we(await ee(),e);if(o)return r=wa(o,n),await ae(),{removed:t,restored:r,draftRev:o.draftRev||0}}return{removed:t,restored:r,draftRev:null}}function jw(e){let t=xd(e);t.timer||(t.timer=setInterval(()=>HU(e).catch(()=>{}),FU))}async function HU(e){let t=ha.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=we(await ee(),e);if(!n||n.archivedAt){vc(e,"archived");return}let r=l=>{for(let u of t.items)sA(u.delivery,l)},o=xa(e);if(o&&!o.finishedAt&&o.step!=="done"&&!o.error){Go(t,!1),r("handoff");return}let s=await ke(n.leadBox),a=n.boxes.find(l=>l.name===n.leadBox);if(s&&await Xw(s)&&(s=await gc(n,a,"queue")?await ke(n.leadBox):null,await ae()),!s){Go(t,!1),r("noSession");return}if(Co(a?.agent)){Go(t,!1),r("cap");return}let i=await Be(n.leadBox,{lines:tt}).catch(()=>"");if(ql(a?.agent,i)){Go(t,!1),r("busy");return}if(Ro(a?.agent,i)){let l=await Gn(n.leadBox).catch(()=>i);if(jr(a,l)){Go(t,!1),r("prompt");return}}if(!Go(t,!0)){r("grace");return}let c=t.items.shift();t.idleSince=null,c.delivery&&(c.delivery.dequeuedAt=Date.now());try{await Ew(n,a,s,c.text,c.kind??null,c.attachments??null,c.delivery??null)}catch(l){if(l?.code!=="cli-not-running")throw c.delivery&&await $n(n,c.delivery,oa(l)),l;t.items.unshift(c),c.delivery&&(c.delivery.requeued+=1,c.delivery.dequeuedAt=null,await Xi(n,c.delivery,{position:1,reason:"requeue"})),await gc(n,a,"queue-gate")}await ae()}finally{t.flushing=!1}}}async function e_(e,t,n,r){let o=Co(t?.agent);if(!o)return;if(!r&&typeof n=="string"&&n.trim()&&(wa(e,[n]),await ae()),bv(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 WU(e,t){let n=await Be(e.leadBox,{lines:tt}).catch(()=>"");if(!Ro(t?.agent,n))return!1;let r=await Gn(e.leadBox).catch(()=>n);return!!jr(t,r)}async function Ew(e,t,n,r,o=null,s=null,a=null){a||(a=Yi({text:r,producer:Ji({kind:o}),kind:o,provider:t?.agent??null,attachments:Array.isArray(s)?s.length:0})),a.provider??=t?.agent??null,await e_(e,t,r,o);let i=fc.get(e.id)||0,c=r,l=!1,u=e.pendingHandoffHydrate||null;e.pendingHandoffHydrate&&(c=JE(r,e.pendingHandoffHydrate.artifact||zo),delete e.pendingHandoffHydrate,l=!0);let d=Array.isArray(s)?s.filter(m=>m&&m.rel):[];if(d.length){let m=AE(d.map(g=>g.rel));c=c.trim()?`${c.trim()}
213
213
 
214
- ${m}`:m}let p=Ie(e,"said",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,text:r,deliveryId:a.id,...o?{kind:o}:{},...d.length?{attachments:d}:{}});o||ma(e,null);try{let m=Date.now(),g=null;try{g=await $r({cwd:n.cwd,sessionId:n.sessionId,sessionName:e.leadBox,agent:n.agent,agentCmd:ka(n.agent),bailOnDialog:!0})}catch(x){throw Zi(a,{ms:Date.now()-m,outcome:x?.code==="cli-not-running"?"cli-not-running":"blocked"}),x}if(Zi(a,{ms:Date.now()-m,outcome:g||"up"}),(fc.get(e.id)||0)!==i){!o&&r.trim()&&(wa(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 HU(e,t)){let x=kd(e.id);a.requeued+=1,a.dequeuedAt=null;let y={id:a.id,text:r,ts:Date.now(),...o?{kind:o}:{},...d.length?{attachments:d}:{},delivery:a};x.items.unshift(y),jw(e.id),await Xi(e,a,{position:1,reason:"prompt"});let $=new Error("lead is blocked on a prompt \u2014 message queued");throw $.requeued={id:y.id,position:x.items.length},$}let b=vn(t?.agent,c);a.paste=!!b.paste,await nt(e.leadBox,c,{...b,kind:l?"lead-handoff-first-prompt":"say"})}catch(m){if(u&&!e.pendingHandoffHydrate&&(e.pendingHandoffHydrate=u),Ie(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 $n(e,a,oa(m)),m}let f={},w=await r4(e,t,c,f);a.verify=f,w?await $n(e,a,f.verdict==="unverified"?"unverified":"delivered"):(await t_(e.leadBox,t?.agent,c.length+8,c).catch(()=>{}),Ie(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:p.at,text:r,reason:"unsubmitted"}),o||wa(e,[r]),await $n(e,a,"unsubmitted")),l&&await le({flow:"lead-handoff",phase:"first-prompt",trackId:e.id,sessionName:e.leadBox,agent:t?.agent,userTextLen:r.length})}function Bw(e,{actions:t}={}){let n=kd(e),r=Yv(t),o=Yi({text:r,producer:Ji({kind:"ship-notify"}),kind:"ship-notify"});n.items.push({id:o.id,text:r,ts:Date.now(),kind:"ship-notify",delivery:o}),jw(e),(async()=>{let s=we(await ee(),e);s&&(o.provider=s.boxes.find(a=>a.name===s.leadBox)?.agent??null,await Xi(s,o,{position:n.items.length,reason:"queue"}))})().catch(()=>{})}async function Dt(e,t,{kind:n=null,attachments:r=null,producer:o=null}={}){let s=Array.isArray(r)?r.filter(u=>u&&typeof u.rel=="string"):[];if((typeof t!="string"||!Fs(t))&&!s.length)throw new Error("text (string) or an attachment required");let a=we(await ee(),e);if(!a)throw new Error(`track "${e}" not found`);if(a.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it before driving it`);sg(a);let i=a.boxes.find(u=>u.name===a.leadBox),c=Fs(t),l=Yi({text:c,producer:Ji({kind:n,producer:o}),kind:n,provider:i?.agent??null,attachments:s.length});try{return await WU(e,a,i,c,{kind:n,atts:s,d:l})}catch(u){throw await $n(a,l,oa(u)),u}}async function WU(e,t,n,r,{kind:o,atts:s,d:a}){await QE(t,n,r,o),Sc(e,"say");let i=await ke(t.leadBox);if(i&&await Yw(i)?await gc(t,n,"say")?(await ae(),i=await ke(t.leadBox)):i=null:!i&&await Ac(t)&&(await ae(),i=await ke(t.leadBox)),!i)throw new Error(`lead box "${t.leadBox}" is not running`);let c=kd(e),l=await je(t.leadBox,{lines:tt}).catch(()=>""),u=c.items.length>0?"queue":ql(n?.agent,l)?"busy":null,d=u!=null;if(!d&&Ro(n?.agent,l)){let f=await Gn(t.leadBox).catch(()=>l);d=!!Br(n,f),d&&(u="prompt")}if(d){let f={id:a.id,text:r,ts:Date.now(),...o?{kind:o}:{},...s.length?{attachments:s}:{},delivery:a};return c.items.push(f),jw(e),o||ma(t,null),await ae(),await Xi(t,a,{position:c.items.length,reason:u}),{ok:!0,leadBox:t.leadBox,queued:!0,id:f.id,position:c.items.length,deliveryId:a.id}}let p;try{p=await Aw(t,n,i,r,o,s,a)}catch(f){if(f?.code!=="cli-not-running"||!await gc(t,n,"say-gate")||(await ae(),i=await ke(t.leadBox),!i))throw f;p=await Aw(t,n,i,r,o,s,a)}return await ae(),p?.queued?{ok:!0,leadBox:t.leadBox,queued:!0,id:p.id,position:p.position,deliveryId:a.id}:{ok:!0,leadBox:t.leadBox,deliveryId:a.id}}async function Lw(e,{hint:t}={}){let n=we(await ee(),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=Dh(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";mA(n.id,{name:s,box:n.leadBox});let a=String(t||"").trim()?`${FE}
214
+ ${m}`:m}let p=Ie(e,"said",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,text:r,deliveryId:a.id,...o?{kind:o}:{},...d.length?{attachments:d}:{}});o||ma(e,null);try{let m=Date.now(),g=null;try{g=await $r({cwd:n.cwd,sessionId:n.sessionId,sessionName:e.leadBox,agent:n.agent,agentCmd:ka(n.agent),bailOnDialog:!0})}catch(x){throw Zi(a,{ms:Date.now()-m,outcome:x?.code==="cli-not-running"?"cli-not-running":"blocked"}),x}if(Zi(a,{ms:Date.now()-m,outcome:g||"up"}),(fc.get(e.id)||0)!==i){!o&&r.trim()&&(wa(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 WU(e,t)){let x=xd(e.id);a.requeued+=1,a.dequeuedAt=null;let y={id:a.id,text:r,ts:Date.now(),...o?{kind:o}:{},...d.length?{attachments:d}:{},delivery:a};x.items.unshift(y),jw(e.id),await Xi(e,a,{position:1,reason:"prompt"});let $=new Error("lead is blocked on a prompt \u2014 message queued");throw $.requeued={id:y.id,position:x.items.length},$}let b=vn(t?.agent,c);a.paste=!!b.paste,await nt(e.leadBox,c,{...b,kind:l?"lead-handoff-first-prompt":"say"})}catch(m){if(u&&!e.pendingHandoffHydrate&&(e.pendingHandoffHydrate=u),Ie(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 $n(e,a,oa(m)),m}let f={},w=await o4(e,t,c,f);a.verify=f,w?await $n(e,a,f.verdict==="unverified"?"unverified":"delivered"):(await n_(e.leadBox,t?.agent,c.length+8,c).catch(()=>{}),Ie(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:p.at,text:r,reason:"unsubmitted"}),o||wa(e,[r]),await $n(e,a,"unsubmitted")),l&&await le({flow:"lead-handoff",phase:"first-prompt",trackId:e.id,sessionName:e.leadBox,agent:t?.agent,userTextLen:r.length})}function Lw(e,{actions:t}={}){let n=xd(e),r=Yv(t),o=Yi({text:r,producer:Ji({kind:"ship-notify"}),kind:"ship-notify"});n.items.push({id:o.id,text:r,ts:Date.now(),kind:"ship-notify",delivery:o}),jw(e),(async()=>{let s=we(await ee(),e);s&&(o.provider=s.boxes.find(a=>a.name===s.leadBox)?.agent??null,await Xi(s,o,{position:n.items.length,reason:"queue"}))})().catch(()=>{})}async function Dt(e,t,{kind:n=null,attachments:r=null,producer:o=null}={}){let s=Array.isArray(r)?r.filter(u=>u&&typeof u.rel=="string"):[];if((typeof t!="string"||!Fs(t))&&!s.length)throw new Error("text (string) or an attachment required");let a=we(await ee(),e);if(!a)throw new Error(`track "${e}" not found`);if(a.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it before driving it`);ag(a);let i=a.boxes.find(u=>u.name===a.leadBox),c=Fs(t),l=Yi({text:c,producer:Ji({kind:n,producer:o}),kind:n,provider:i?.agent??null,attachments:s.length});try{return await qU(e,a,i,c,{kind:n,atts:s,d:l})}catch(u){throw await $n(a,l,oa(u)),u}}async function qU(e,t,n,r,{kind:o,atts:s,d:a}){await e_(t,n,r,o),Sc(e,"say");let i=await ke(t.leadBox);if(i&&await Xw(i)?await gc(t,n,"say")?(await ae(),i=await ke(t.leadBox)):i=null:!i&&await Ac(t)&&(await ae(),i=await ke(t.leadBox)),!i)throw new Error(`lead box "${t.leadBox}" is not running`);let c=xd(e),l=await Be(t.leadBox,{lines:tt}).catch(()=>""),u=c.items.length>0?"queue":ql(n?.agent,l)?"busy":null,d=u!=null;if(!d&&Ro(n?.agent,l)){let f=await Gn(t.leadBox).catch(()=>l);d=!!jr(n,f),d&&(u="prompt")}if(d){let f={id:a.id,text:r,ts:Date.now(),...o?{kind:o}:{},...s.length?{attachments:s}:{},delivery:a};return c.items.push(f),jw(e),o||ma(t,null),await ae(),await Xi(t,a,{position:c.items.length,reason:u}),{ok:!0,leadBox:t.leadBox,queued:!0,id:f.id,position:c.items.length,deliveryId:a.id}}let p;try{p=await Ew(t,n,i,r,o,s,a)}catch(f){if(f?.code!=="cli-not-running"||!await gc(t,n,"say-gate")||(await ae(),i=await ke(t.leadBox),!i))throw f;p=await Ew(t,n,i,r,o,s,a)}return await ae(),p?.queued?{ok:!0,leadBox:t.leadBox,queued:!0,id:p.id,position:p.position,deliveryId:a.id}:{ok:!0,leadBox:t.leadBox,deliveryId:a.id}}async function Fw(e,{hint:t}={}){let n=we(await ee(),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=Bh(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";hA(n.id,{name:s,box:n.leadBox});let a=String(t||"").trim()?`${UE}
215
215
 
216
- What to preview: ${String(t).trim()}`:FE;try{await Dt(e,a,{kind:"spin-up-view"})}catch(i){throw Zu(n.id,{error:"drive-failed"}),i}return{ok:!0,running:!0}}async function xd(e){let t=we(await ee(),e);if(!t)throw new Error(`track "${e}" not found`);if(t.archivedAt)throw new Error(`track "${e}" is archived`);fc.set(e,(fc.get(e)||0)+1);let n=vc(e,"interrupt"),r=n.filter(i=>i.text&&!i.kind).map(i=>i.text),o=fa.get(e);if(o&&!o.canceled){o.clicks++;let i=null;return r.length&&(i=wa(t,r),await ae()),{ok:!0,interrupted:!0,stopped:!1,stopping:!0,dropped:n.length,restored:i,draftRev:t.draftRev||0}}let s=JU(e,{droppedCount:n.length,droppedTexts:r});await Promise.race([s.settled,Jo(qU)]);let a=we(await ee(),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 e_(e){let t=fa.get(e);return!!t&&!t.canceled}function Sc(e,t){let n=fa.get(e);n&&!n.canceled&&(n.canceled=!0,n.cancelReason=t||null)}function Fw(e){Sc(e,"track-ended"),fc.delete(e),vc(e,"track-ended")}function JU(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}),fa.set(e,r),(async()=>{let s=we(await ee(),e),a=s?.boxes.find(g=>g.name===s.leadBox),i=s?await ke(s.leadBox):null,c=!1,l=!1;if(i){e:for(let g=0;g<KU&&!r.canceled;g++){await Ke(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.escSends++;for(let b of GU){await Jo(b);let x=await je(s.leadBox,{lines:tt}).catch(()=>"");if(!Cs(a?.agent,x)){c=!0;break e}}}if(!c){l=!0;for(let g=0;g<VU&&!r.canceled&&(await Jo(zU),!r.canceled);g++){let b=await je(s.leadBox,{lines:tt}).catch(()=>"");if(!Cs(a?.agent,b)){c=!0;break}await Ke(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.bgSends++}}}let u=we(await ee(),e)||s,d=u?.boxes.find(g=>g.name===u.leadBox)||a,p=null,f=null;u&&d&&i&&c&&!r.canceled&&(p=await QU(u,d).catch(()=>null),p||(f=await n4(u,d).catch(()=>null)));let w=u&&i&&!r.canceled?await XU(u).catch(()=>null):null,m=[p||f,...r.queuedTexts].filter(Boolean);u&&m.length&&(r.restored=wa(u,m),await ae()),r.result=i?r.canceled?"canceled":c?l?"stopped-late":"stopped":"gave-up":"no-session",await YU(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 le({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"),fa.get(e)===r&&fa.delete(e),o()}),r}async function YU(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 XU(e){let t=td(await K(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 QU(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 ZU){await Jo(r);let o=await je(e.leadBox,{lines:tt}).catch(()=>""),s=gi(t.agent,o);if(s&&Kl(n.text,s))return await t_(e.leadBox,t.agent,n.text.length+8),Ie(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:n.at,text:n.text}),n.text}return null}async function n4(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>e4||n.some(s=>s.type==="unsaid"&&s.saidTs===r.at)||!He(r.text))return null;for(let s of t4){await Jo(s);let a;try{a=await sm(t,{})}catch{return null}if(o0(a,r))return null;let i=await je(e.leadBox,{lines:tt}).catch(()=>"");if(gi(t.agent,i))return null}return Ie(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:r.at,text:r.text,reason:"lost"}),r.text}async function r4(e,t,n,r=null){return ki({sessionName:e.leadBox,agent:t?.agent,agentCmd:ka(t?.agent),text:n,trackId:e.id,flow:"say",stats:r})}async function t_(e,t,n,r=null){for(let o=0;o<3;o++){await As(e,n,{kind:"unsend-wipe"}).catch(()=>{}),await Jo(200);let s=await je(e,{lines:tt}).catch(()=>""),a=gi(t,s);if(!a||r&&!Kl(r,a)&&!(t==="codex"&&$f(r,a)))return!0;n=a.length+8}return!1}function ma(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 wa(e,t){let n=[],r=o=>n.some(s=>He(s).includes(He(o)));for(let o of[e.draft?.text,...t])o&&o.trim()&&!r(o)&&n.push(o);return n.length?ma(e,n.join(`
216
+ What to preview: ${String(t).trim()}`:UE;try{await Dt(e,a,{kind:"spin-up-view"})}catch(i){throw Qu(n.id,{error:"drive-failed"}),i}return{ok:!0,running:!0}}async function vd(e){let t=we(await ee(),e);if(!t)throw new Error(`track "${e}" not found`);if(t.archivedAt)throw new Error(`track "${e}" is archived`);fc.set(e,(fc.get(e)||0)+1);let n=vc(e,"interrupt"),r=n.filter(i=>i.text&&!i.kind).map(i=>i.text),o=fa.get(e);if(o&&!o.canceled){o.clicks++;let i=null;return r.length&&(i=wa(t,r),await ae()),{ok:!0,interrupted:!0,stopped:!1,stopping:!0,dropped:n.length,restored:i,draftRev:t.draftRev||0}}let s=YU(e,{droppedCount:n.length,droppedTexts:r});await Promise.race([s.settled,Jo(KU)]);let a=we(await ee(),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 t_(e){let t=fa.get(e);return!!t&&!t.canceled}function Sc(e,t){let n=fa.get(e);n&&!n.canceled&&(n.canceled=!0,n.cancelReason=t||null)}function Uw(e){Sc(e,"track-ended"),fc.delete(e),vc(e,"track-ended")}function YU(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}),fa.set(e,r),(async()=>{let s=we(await ee(),e),a=s?.boxes.find(g=>g.name===s.leadBox),i=s?await ke(s.leadBox):null,c=!1,l=!1;if(i){e:for(let g=0;g<GU&&!r.canceled;g++){await Ke(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.escSends++;for(let b of zU){await Jo(b);let x=await Be(s.leadBox,{lines:tt}).catch(()=>"");if(!Cs(a?.agent,x)){c=!0;break e}}}if(!c){l=!0;for(let g=0;g<JU&&!r.canceled&&(await Jo(VU),!r.canceled);g++){let b=await Be(s.leadBox,{lines:tt}).catch(()=>"");if(!Cs(a?.agent,b)){c=!0;break}await Ke(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.bgSends++}}}let u=we(await ee(),e)||s,d=u?.boxes.find(g=>g.name===u.leadBox)||a,p=null,f=null;u&&d&&i&&c&&!r.canceled&&(p=await e4(u,d).catch(()=>null),p||(f=await r4(u,d).catch(()=>null)));let w=u&&i&&!r.canceled?await ZU(u).catch(()=>null):null,m=[p||f,...r.queuedTexts].filter(Boolean);u&&m.length&&(r.restored=wa(u,m),await ae()),r.result=i?r.canceled?"canceled":c?l?"stopped-late":"stopped":"gave-up":"no-session",await XU(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 le({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"),fa.get(e)===r&&fa.delete(e),o()}),r}async function XU(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 ZU(e){let t=nd(await K(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 e4(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 QU){await Jo(r);let o=await Be(e.leadBox,{lines:tt}).catch(()=>""),s=gi(t.agent,o);if(s&&Kl(n.text,s))return await n_(e.leadBox,t.agent,n.text.length+8),Ie(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:n.at,text:n.text}),n.text}return null}async function r4(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>t4||n.some(s=>s.type==="unsaid"&&s.saidTs===r.at)||!He(r.text))return null;for(let s of n4){await Jo(s);let a;try{a=await am(t,{})}catch{return null}if(o0(a,r))return null;let i=await Be(e.leadBox,{lines:tt}).catch(()=>"");if(gi(t.agent,i))return null}return Ie(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:r.at,text:r.text,reason:"lost"}),r.text}async function o4(e,t,n,r=null){return ki({sessionName:e.leadBox,agent:t?.agent,agentCmd:ka(t?.agent),text:n,trackId:e.id,flow:"say",stats:r})}async function n_(e,t,n,r=null){for(let o=0;o<3;o++){await As(e,n,{kind:"unsend-wipe"}).catch(()=>{}),await Jo(200);let s=await Be(e,{lines:tt}).catch(()=>""),a=gi(t,s);if(!a||r&&!Kl(r,a)&&!(t==="codex"&&Rf(r,a)))return!0;n=a.length+8}return!1}function ma(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 wa(e,t){let n=[],r=o=>n.some(s=>He(s).includes(He(o)));for(let o of[e.draft?.text,...t])o&&o.trim()&&!r(o)&&n.push(o);return n.length?ma(e,n.join(`
217
217
 
218
- `),{source:"restore"})?.text??null:null}function s4(e,t){let n=He(t);if(!n)return!1;if(Vo(e.id).some(o=>He(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>o4)break;if(!(s.type!=="said"||!s.text||He(s.text)!==n))return!r.some(a=>a.type==="unsaid"&&a.saidTs===s.at)}return!1}async function Uw(e,t,{rev:n=null}={}){if(typeof t!="string")throw new Error("text (string) required");let r=we(await ee(),e);if(!r)throw new Error(`track "${e}" not found`);let o=t,s=Fs(t);if(typeof n=="number"&&n<(r.draftRev||0)&&s&&s4(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;He(o).includes(He(i))?ma(r,o):ma(r,`${i}
218
+ `),{source:"restore"})?.text??null:null}function a4(e,t){let n=He(t);if(!n)return!1;if(Vo(e.id).some(o=>He(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>s4)break;if(!(s.type!=="said"||!s.text||He(s.text)!==n))return!r.some(a=>a.type==="unsaid"&&a.saidTs===s.at)}return!1}async function Hw(e,t,{rev:n=null}={}){if(typeof t!="string")throw new Error("text (string) required");let r=we(await ee(),e);if(!r)throw new Error(`track "${e}" not found`);let o=t,s=Fs(t);if(typeof n=="number"&&n<(r.draftRev||0)&&s&&a4(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;He(o).includes(He(i))?ma(r,o):ma(r,`${i}
219
219
 
220
- ${o}`,{source:"restore"})}else ma(r,o);return await ae(),{ok:!0,draft:r.draft||null,rev:r.draftRev||0}}async function Hw(e,t){if(typeof t!="string"||!t.trim())throw new Error("model (string) required");let n=t.trim(),r=we(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=Rv(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 $r({cwd:o.cwd,sessionId:o.sessionId,sessionName:r.leadBox,agent:o.agent,agentCmd:ka(o.agent)});let u=await Ov(a,r.leadBox,i);return Ie(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 n_(e){for(let t of e){if(!t||!await Us(t))continue;let n=await iv(t).catch(()=>null);if(!n)continue;if((await Q.stat(re.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:re.basename(t.base),dir:t.dir??null,base:t.base,baseRef:t.baseRef??null,repo:t.repo??null}]:[]:[]}async function Ho(e){let t=[];for(let n of jt(e?.workspace)){if(!n?.dir)continue;let r=await Ii(n.dir,{ignorePlumbing:!0}).catch(()=>!1),o=await $i(n.dir,n.baseRef).catch(()=>0);(r||o>0)&&t.push({...n,dirty:r,ahead:o})}return t}async function r_(e){let t=e;typeof t=="string"&&!re.isAbsolute(t)&&/^[^/\s]+\/[^/\s]+$/.test(t)&&(t=await ms(t)??await pl(t));let n=await n_([t]);if(!n)throw new Error(`tagged repo "${e}" is not a usable base (need a primary checkout or a synced owner/name)`);return n}async function a4(e,t,n,r){let o=`track/${lg(t)}-${e}`,s=[];try{await Q.mkdir(n,{recursive:!0});let a=new Set([".bostrat"]);for(let i of r){let c=await r_(i);if(s.some(f=>f.base===c))throw new Error(`repo tagged twice: ${i}`);let l=await _e(c).catch(()=>null),u=re.basename(c);a.has(u)&&l&&(u=l.replace("/","-"));for(let f=2;a.has(u);f++)u=`${re.basename(c)}-${f}`;a.add(u);let d=re.join(n,u),p=await qs(c);await Ws(c,d,o,p),s.push({name:u,dir:d,base:c,baseRef:p,repo:l})}return await Tc(n,s,o),{dir:n,kind:"multi",branch:o,repos:s}}catch(a){for(let i of s)await Ot(i.base,i.dir).catch(()=>{});throw await Q.rm(n,{recursive:!0,force:!0}).catch(()=>{}),a}}async function Ww(e,t){let n=await ee(),r=we(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 r_(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=re.basename(s);i.has(c)&&a&&(c=a.replace("/","-"));for(let p=2;i.has(c);p++)c=`${re.basename(s)}-${p}`;let l=re.join(o.dir,c),u=await qs(s);await cv(s,o.branch)?await lu(s,l,o.branch):await Ws(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 Tc(o.dir,o.repos,o.branch),Ie(r,"retagged",{action:"add",repo:a??s,name:c,workspace:o_(o)}),await ae(),d}async function qw(e,t){let n=await ee(),r=we(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 Pt.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 Ii(s.dir,{ignorePlumbing:!0}).catch(()=>!1),i=await $i(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 Ot(s.base,s.dir).catch(()=>{}),await Q.rm(s.dir,{recursive:!0,force:!0}).catch(()=>{}),o.repos=(o.repos??[]).filter(c=>c&&c!==s),await Tc(o.dir,o.repos,o.branch),Ie(r,"retagged",{action:"remove",repo:s.repo??s.base,name:s.name,workspace:o_(o)}),await ae(),{removed:s.name}}async function i4(e,t,{repo:n,repos:r,cwd:o}={}){await Q.mkdir(dc,{recursive:!0});let s=re.join(dc,e),a=Array.isArray(r)?r.map(c=>typeof c=="string"?c.trim():"").filter(Boolean):[];if(a.length>=2)return a4(e,t,s,a);a.length===1&&!n&&(n=a[0]),typeof n=="string"&&!re.isAbsolute(n)&&/^[^/\s]+\/[^/\s]+$/.test(n)&&(n=await ms(n)??await pl(n));let i=await n_([n,o,TU]);if(i){let c=`track/${lg(t)}-${e}`;try{let l=await qs(i);await Ws(i,s,c,l),await hc(s);let u=await _e(i).catch(()=>null);return{dir:s,base:i,branch:c,kind:"worktree",baseRef:l,repo:u}}catch{await Q.rm(s,{recursive:!0,force:!0}).catch(()=>{})}}return await Q.mkdir(s,{recursive:!0}),await km(s),await hc(s),{dir:s,base:null,branch:null,kind:"repo"}}async function hc(e){try{await Q.writeFile(re.join(e,"AGENTS.md"),uc,{flag:"wx"})}catch{return}await d4(e,["/AGENTS.md"])}function u4(e,t){let n=e.map(r=>`- \`${r.name}/\`${r.repo?` \u2014 github.com/${r.repo}`:""}${r.baseRef?` (forked from ${r.baseRef})`:""}`).join(`
221
- `);return`${l4}
220
+ ${o}`,{source:"restore"})}else ma(r,o);return await ae(),{ok:!0,draft:r.draft||null,rev:r.draftRev||0}}async function Ww(e,t){if(typeof t!="string"||!t.trim())throw new Error("model (string) required");let n=t.trim(),r=we(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=Rv(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 $r({cwd:o.cwd,sessionId:o.sessionId,sessionName:r.leadBox,agent:o.agent,agentCmd:ka(o.agent)});let u=await Ov(a,r.leadBox,i);return Ie(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 r_(e){for(let t of e){if(!t||!await Us(t))continue;let n=await iv(t).catch(()=>null);if(!n)continue;if((await Q.stat(re.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:re.basename(t.base),dir:t.dir??null,base:t.base,baseRef:t.baseRef??null,repo:t.repo??null}]:[]:[]}async function Ho(e){let t=[];for(let n of Bt(e?.workspace)){if(!n?.dir)continue;let r=await Ii(n.dir,{ignorePlumbing:!0}).catch(()=>!1),o=await $i(n.dir,n.baseRef).catch(()=>0);(r||o>0)&&t.push({...n,dirty:r,ahead:o})}return t}async function o_(e){let t=e;typeof t=="string"&&!re.isAbsolute(t)&&/^[^/\s]+\/[^/\s]+$/.test(t)&&(t=await ms(t)??await pl(t));let n=await r_([t]);if(!n)throw new Error(`tagged repo "${e}" is not a usable base (need a primary checkout or a synced owner/name)`);return n}async function i4(e,t,n,r){let o=`track/${ug(t)}-${e}`,s=[];try{await Q.mkdir(n,{recursive:!0});let a=new Set([".bostrat"]);for(let i of r){let c=await o_(i);if(s.some(f=>f.base===c))throw new Error(`repo tagged twice: ${i}`);let l=await _e(c).catch(()=>null),u=re.basename(c);a.has(u)&&l&&(u=l.replace("/","-"));for(let f=2;a.has(u);f++)u=`${re.basename(c)}-${f}`;a.add(u);let d=re.join(n,u),p=await qs(c);await Ws(c,d,o,p),s.push({name:u,dir:d,base:c,baseRef:p,repo:l})}return await Tc(n,s,o),{dir:n,kind:"multi",branch:o,repos:s}}catch(a){for(let i of s)await Ot(i.base,i.dir).catch(()=>{});throw await Q.rm(n,{recursive:!0,force:!0}).catch(()=>{}),a}}async function qw(e,t){let n=await ee(),r=we(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 o_(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=re.basename(s);i.has(c)&&a&&(c=a.replace("/","-"));for(let p=2;i.has(c);p++)c=`${re.basename(s)}-${p}`;let l=re.join(o.dir,c),u=await qs(s);await cv(s,o.branch)?await lu(s,l,o.branch):await Ws(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 Tc(o.dir,o.repos,o.branch),Ie(r,"retagged",{action:"add",repo:a??s,name:c,workspace:s_(o)}),await ae(),d}async function Kw(e,t){let n=await ee(),r=we(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 Pt.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 Ii(s.dir,{ignorePlumbing:!0}).catch(()=>!1),i=await $i(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 Ot(s.base,s.dir).catch(()=>{}),await Q.rm(s.dir,{recursive:!0,force:!0}).catch(()=>{}),o.repos=(o.repos??[]).filter(c=>c&&c!==s),await Tc(o.dir,o.repos,o.branch),Ie(r,"retagged",{action:"remove",repo:s.repo??s.base,name:s.name,workspace:s_(o)}),await ae(),{removed:s.name}}async function c4(e,t,{repo:n,repos:r,cwd:o}={}){await Q.mkdir(dc,{recursive:!0});let s=re.join(dc,e),a=Array.isArray(r)?r.map(c=>typeof c=="string"?c.trim():"").filter(Boolean):[];if(a.length>=2)return i4(e,t,s,a);a.length===1&&!n&&(n=a[0]),typeof n=="string"&&!re.isAbsolute(n)&&/^[^/\s]+\/[^/\s]+$/.test(n)&&(n=await ms(n)??await pl(n));let i=await r_([n,o,AU]);if(i){let c=`track/${ug(t)}-${e}`;try{let l=await qs(i);await Ws(i,s,c,l),await hc(s);let u=await _e(i).catch(()=>null);return{dir:s,base:i,branch:c,kind:"worktree",baseRef:l,repo:u}}catch{await Q.rm(s,{recursive:!0,force:!0}).catch(()=>{})}}return await Q.mkdir(s,{recursive:!0}),await xm(s),await hc(s),{dir:s,base:null,branch:null,kind:"repo"}}async function hc(e){try{await Q.writeFile(re.join(e,"AGENTS.md"),uc,{flag:"wx"})}catch{return}await p4(e,["/AGENTS.md"])}function d4(e,t){let n=e.map(r=>`- \`${r.name}/\`${r.repo?` \u2014 github.com/${r.repo}`:""}${r.baseRef?` (forked from ${r.baseRef})`:""}`).join(`
221
+ `);return`${u4}
222
222
 
223
223
  This directory is NOT a git repo. It is a bostrat Track workspace holding one
224
224
  git worktree per tagged repo, ALL on the same branch \`${t}\`:
@@ -230,20 +230,20 @@ push / open PRs) in each repo separately, always on that shared branch. Work
230
230
  only needs to land in the repos it actually touches \u2014 an untouched repo's
231
231
  branch simply stays at its fork point and never gets pushed. When asked to run
232
232
  or preview an app, run it from that app's own repo directory.
233
- `}async function Tc(e,t,n){let r=u4(t,n);for(let o of["CLAUDE.md","AGENTS.md"])await Q.writeFile(re.join(e,o),r).catch(()=>{})}async function a_(e){let{stdout:t}=await KE("git",["-C",e,"rev-parse","--git-path","info/exclude"]);return re.resolve(e,t.trim())}async function d4(e,t){try{let n=await a_(e);await Q.mkdir(re.dirname(n),{recursive:!0});let r=await Q.readFile(n,"utf8").catch(()=>""),o=t.filter(s=>!r.split(`
233
+ `}async function Tc(e,t,n){let r=d4(t,n);for(let o of["CLAUDE.md","AGENTS.md"])await Q.writeFile(re.join(e,o),r).catch(()=>{})}async function i_(e){let{stdout:t}=await GE("git",["-C",e,"rev-parse","--git-path","info/exclude"]);return re.resolve(e,t.trim())}async function p4(e,t){try{let n=await i_(e);await Q.mkdir(re.dirname(n),{recursive:!0});let r=await Q.readFile(n,"utf8").catch(()=>""),o=t.filter(s=>!r.split(`
234
234
  `).includes(s));o.length&&await Q.appendFile(n,(r.endsWith(`
235
235
  `)||!r?"":`
236
236
  `)+o.join(`
237
237
  `)+`
238
- `)}catch{}}async function p4(e,t){try{let n=await a_(e),r=await Q.readFile(n,"utf8"),o=r.split(`
238
+ `)}catch{}}async function f4(e,t){try{let n=await i_(e),r=await Q.readFile(n,"utf8"),o=r.split(`
239
239
  `).filter(s=>s!==t);o.length!==r.split(`
240
240
  `).length&&await Q.writeFile(n,o.join(`
241
- `))}catch{}}async function Kw(){let e={refreshed:0,removed:0,codexGlobal:null};try{await Q.mkdir(jn,{recursive:!0}),await Q.writeFile(re.join(jn,"CLAUDE.md"),c4).catch(()=>{}),await Q.writeFile(re.join(jn,"AGENTS.md"),uc).catch(()=>{});let t=process.env.CODEX_HOME||re.join(process.env.HOME||"/tmp",".codex");if((await Q.stat(t).catch(()=>null))?.isDirectory()){let r=re.join(t,"AGENTS.md"),o=await Q.readFile(r,"utf8").catch(()=>null);o===null?(await Q.writeFile(r,bw,{flag:"wx"}).catch(()=>{}),e.codexGlobal="created"):yw(o)&&o!==bw&&(await Q.writeFile(r,bw).catch(()=>{}),e.codexGlobal="refreshed")}for(let r of[dc,ba]){let o=await Q.readdir(r,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(!s.isDirectory())continue;let a=re.join(r,s.name),i=re.join(a,"AGENTS.md"),c=await Q.readFile(i,"utf8").catch(()=>null);c!==null&&yw(c)&&c!==uc&&(await Q.writeFile(i,uc).catch(()=>{}),e.refreshed++);let l=re.join(a,"CLAUDE.md"),u=await Q.readFile(l,"utf8").catch(()=>null);u!==null&&yw(u)&&(await Q.rm(l,{force:!0}).catch(()=>{}),await p4(a,"/CLAUDE.md"),e.removed++)}}}catch{}return e}async function i_(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 Ot(n.base,n.dir).catch(()=>{});await Q.rm(t.dir,{recursive:!0,force:!0})}else t.kind==="worktree"&&t.base?await Ot(t.base,t.dir):await Q.rm(t.dir,{recursive:!0,force:!0})}catch{}}async function vd({name:e,cwd:t,repo:n,repos:r,agent:o="claude",skipPermissions:s=!0}){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");let a=await kc(o,s),i=await ee(),c=hd().slice(0,8),l=await i4(c,e,{repo:n,repos:r,cwd:t}),u=new Set(i.tracks.flatMap(w=>(w.boxes||[]).map(m=>m.name))),d=`${e.trim()} lead`;u.has(Ml(d))&&(d=`${e.trim().slice(0,50).trim()} ${c} lead`);let p=await _r(d,l.dir,{agentCmd:a,agent:o,freshWorkspace:!0}),f={id:c,name:e.trim(),cwd:p.cwd,workspace:l,leadBox:p.name,boxes:[tg(p,"lead","live")],events:[],createdAt:Date.now()};return Ie(f,"opened",{agent:o,box:p.name,skipPermissions:s,name:f.name,cwd:f.cwd,workspace:{base:l.base??null,branch:l.branch,kind:l.kind,...l.baseRef?{baseRef:l.baseRef}:{},...l.repo?{repo:l.repo}:{},...l.repos?{repos:l.repos.map(({name:w,base:m,baseRef:g,repo:b})=>({name:w,base:m,baseRef:g,repo:b}))}:{}}}),i.tracks.push(f),await ae(),mi({cwd:p.cwd,sessionName:p.name,agent:o,agentCmd:a,onReady:async()=>{let w=f.boxes.find(m=>m.name===f.leadBox);!w||w.readyAt||(w.readyAt=Date.now(),await ae())}}),Nt(f)}async function Gw({provider:e="claude",fresh:t=!1}={}){if(!f4.has(e))throw new Error(`unknown setup provider "${e}" (claude | codex | cursor)`);let r=(await ee()).tracks.find(u=>u.kind==="setup"&&u.setup?.provider===e&&!u.archivedAt);if(r){if(!t){let u=await Nt(r);if(u.boxes.find(p=>p.name===u.leadBox)?.state==="live")return u}await Yo(r.id).catch(()=>{})}let o=(await kc(e,!1)).replace(/\s+--(?:dangerously-skip-permissions|dangerously-bypass-approvals-and-sandbox)\b/g,""),s=hd().slice(0,8),a=re.join(jn,"setup",s);await Q.mkdir(a,{recursive:!0});let i=await _r(`Connect ${e} ${s}`,a,{agentCmd:o,agent:e,firstRun:!0});e==="codex"&&mi({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:[tg(i,"lead","live")],events:[],createdAt:Date.now()};return Ie(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 ee()).tracks.push(c),await ae(),Nt(c)}async function zw(e,t,n){await Hp(t.cwd).catch(()=>{}),await xA(e).catch(()=>{});let r=ya.get(e);r&&!r.finishedAt&&(r.error=n,r.finishedAt=Date.now()),ya.delete(e),t.handoff&&!t.handoff.finishedAt&&(t.handoff.step="error",t.handoff.error=n,t.handoff.finishedAt=Date.now());for(let a of Zo(e))a.finishedAt||(a.canceled=!0,a.finishedAt=Date.now()),await pg(a).catch(()=>{}),Pt.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 ee(),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 en(a.name).catch(()=>{})}async function Vw(e,{cascadeMocks:t=!0,cascadeRunbooks:n=!1}={}){let r=await ee(),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 HA(s),Fw(e),await zw(e,s,"track deleted"),n?await bE(e).catch(()=>{}):await yE(e).catch(()=>{}),await Nv(),await i_(s),t&&await WA(e).catch(()=>{}),t?await aE(e).catch(()=>{}):await sE(s).catch(()=>{}),Ie(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 Yo(e){let t=await ee(),n=we(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(),Fw(e),Ie(n,"archived",{boxes:n.boxes.length}),await ae(),n.kind==="setup"?(await c_(e),Nt(n)):(wc.add(e),w4(e).catch(()=>{}).finally(()=>wc.delete(e)),{...await Nt(n),archiving:!0})}async function w4(e){try{await g4(e)}catch{}await c_(e).catch(()=>{})}async function c_(e){let t=await ee(),n=we(t,e);if(!(!n||!n.archivedAt)){await zw(e,n,"track archived");for(let r of n.boxes)eo.has(r.state)||(r.state="stopped");await ae()}}async function g4(e){let t=await ee(),n=we(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 ke(n.leadBox).catch(()=>null):null;if(i?.cwd&&a)try{({text:r,items:o}=await tx(n.leadBox,i.cwd,{timeoutMs:h4})),s="lead-cli"}catch{}if(r||(r=wx(n,await K(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 nr(e,t){let n=await at(e,t).catch(()=>null);if(!n?.archiveOnMerge||!n.trackId)return!1;let r=await Jw(n);if(r.length){for(let o of r)await No(o.repo,o.number,!0).catch(()=>{});return!1}try{return await Yo(n.trackId),!0}catch(o){if(/already archived/i.test(String(o?.message||o)))return!1;throw o}}async function Jw(e){return(await Xn().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 rr(e,t){return Sd(e,t,"merged")}async function Xo(e,t){let n=await at(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 Jw(n);if(o.length){let c=[...n.followupPending||[],r];for(let l of o)await cS(l.repo,l.number,c).catch(()=>{});return null}let s=[...n.followupPending||[],r],a=we(await ee(),n.trackId);if(!a)return null;let i=s[0];return Gi(await Nt(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 Sd(e,t,n="merged"){let r=await at(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 Jw(r);if(s.length){let i=[...r.notifyPending||[],o];for(let c of s)await iS(c.repo,c.number,i).catch(()=>{});return!1}let a=[...r.notifyPending||[],o];if(!await eS(r.repo,r.number).catch(()=>!0))return!1;try{return await Dt(r.trackId,l_(a),{kind:"merge-notify"}),!0}catch{return await Po(r.repo,r.number,!0).catch(()=>{}),!1}}function l_(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 ${UE[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 ${UE[i.outcome]??i.outcome}`).join(`
241
+ `))}catch{}}async function Gw(){let e={refreshed:0,removed:0,codexGlobal:null};try{await Q.mkdir(Bn,{recursive:!0}),await Q.writeFile(re.join(Bn,"CLAUDE.md"),l4).catch(()=>{}),await Q.writeFile(re.join(Bn,"AGENTS.md"),uc).catch(()=>{});let t=process.env.CODEX_HOME||re.join(process.env.HOME||"/tmp",".codex");if((await Q.stat(t).catch(()=>null))?.isDirectory()){let r=re.join(t,"AGENTS.md"),o=await Q.readFile(r,"utf8").catch(()=>null);o===null?(await Q.writeFile(r,kw,{flag:"wx"}).catch(()=>{}),e.codexGlobal="created"):bw(o)&&o!==kw&&(await Q.writeFile(r,kw).catch(()=>{}),e.codexGlobal="refreshed")}for(let r of[dc,ba]){let o=await Q.readdir(r,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(!s.isDirectory())continue;let a=re.join(r,s.name),i=re.join(a,"AGENTS.md"),c=await Q.readFile(i,"utf8").catch(()=>null);c!==null&&bw(c)&&c!==uc&&(await Q.writeFile(i,uc).catch(()=>{}),e.refreshed++);let l=re.join(a,"CLAUDE.md"),u=await Q.readFile(l,"utf8").catch(()=>null);u!==null&&bw(u)&&(await Q.rm(l,{force:!0}).catch(()=>{}),await f4(a,"/CLAUDE.md"),e.removed++)}}}catch{}return e}async function c_(e){let t=e.workspace;if(!(!t||!t.dir))try{if(t.kind==="multi"){for(let n of Bt(t))n.base&&n.dir&&await Ot(n.base,n.dir).catch(()=>{});await Q.rm(t.dir,{recursive:!0,force:!0})}else t.kind==="worktree"&&t.base?await Ot(t.base,t.dir):await Q.rm(t.dir,{recursive:!0,force:!0})}catch{}}async function Sd({name:e,cwd:t,repo:n,repos:r,agent:o="claude",skipPermissions:s=!0}){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");let a=await kc(o,s),i=await ee(),c=wd().slice(0,8),l=await c4(c,e,{repo:n,repos:r,cwd:t}),u=new Set(i.tracks.flatMap(w=>(w.boxes||[]).map(m=>m.name))),d=`${e.trim()} lead`;u.has(Ml(d))&&(d=`${e.trim().slice(0,50).trim()} ${c} lead`);let p=await _r(d,l.dir,{agentCmd:a,agent:o,freshWorkspace:!0}),f={id:c,name:e.trim(),cwd:p.cwd,workspace:l,leadBox:p.name,boxes:[ng(p,"lead","live")],events:[],createdAt:Date.now()};return Ie(f,"opened",{agent:o,box:p.name,skipPermissions:s,name:f.name,cwd:f.cwd,workspace:{base:l.base??null,branch:l.branch,kind:l.kind,...l.baseRef?{baseRef:l.baseRef}:{},...l.repo?{repo:l.repo}:{},...l.repos?{repos:l.repos.map(({name:w,base:m,baseRef:g,repo:b})=>({name:w,base:m,baseRef:g,repo:b}))}:{}}}),i.tracks.push(f),await ae(),mi({cwd:p.cwd,sessionName:p.name,agent:o,agentCmd:a,onReady:async()=>{let w=f.boxes.find(m=>m.name===f.leadBox);!w||w.readyAt||(w.readyAt=Date.now(),await ae())}}),Nt(f)}async function zw({provider:e="claude",fresh:t=!1}={}){if(!m4.has(e))throw new Error(`unknown setup provider "${e}" (claude | codex | cursor)`);let r=(await ee()).tracks.find(u=>u.kind==="setup"&&u.setup?.provider===e&&!u.archivedAt);if(r){if(!t){let u=await Nt(r);if(u.boxes.find(p=>p.name===u.leadBox)?.state==="live")return u}await Yo(r.id).catch(()=>{})}let o=(await kc(e,!1)).replace(/\s+--(?:dangerously-skip-permissions|dangerously-bypass-approvals-and-sandbox)\b/g,""),s=wd().slice(0,8),a=re.join(Bn,"setup",s);await Q.mkdir(a,{recursive:!0});let i=await _r(`Connect ${e} ${s}`,a,{agentCmd:o,agent:e,firstRun:!0});e==="codex"&&mi({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:[ng(i,"lead","live")],events:[],createdAt:Date.now()};return Ie(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 ee()).tracks.push(c),await ae(),Nt(c)}async function Vw(e,t,n){await Wp(t.cwd).catch(()=>{}),await vA(e).catch(()=>{});let r=ya.get(e);r&&!r.finishedAt&&(r.error=n,r.finishedAt=Date.now()),ya.delete(e),t.handoff&&!t.handoff.finishedAt&&(t.handoff.step="error",t.handoff.error=n,t.handoff.finishedAt=Date.now());for(let a of Zo(e))a.finishedAt||(a.canceled=!0,a.finishedAt=Date.now()),await fg(a).catch(()=>{}),Pt.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 ee(),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 en(a.name).catch(()=>{})}async function Jw(e,{cascadeMocks:t=!0,cascadeRunbooks:n=!1}={}){let r=await ee(),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 WA(s),Uw(e),await Vw(e,s,"track deleted"),n?await kE(e).catch(()=>{}):await bE(e).catch(()=>{}),await Nv(),await c_(s),t&&await qA(e).catch(()=>{}),t?await iE(e).catch(()=>{}):await aE(s).catch(()=>{}),Ie(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 Yo(e){let t=await ee(),n=we(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(),Uw(e),Ie(n,"archived",{boxes:n.boxes.length}),await ae(),n.kind==="setup"?(await l_(e),Nt(n)):(wc.add(e),g4(e).catch(()=>{}).finally(()=>wc.delete(e)),{...await Nt(n),archiving:!0})}async function g4(e){try{await y4(e)}catch{}await l_(e).catch(()=>{})}async function l_(e){let t=await ee(),n=we(t,e);if(!(!n||!n.archivedAt)){await Vw(e,n,"track archived");for(let r of n.boxes)eo.has(r.state)||(r.state="stopped");await ae()}}async function y4(e){let t=await ee(),n=we(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 ke(n.leadBox).catch(()=>null):null;if(i?.cwd&&a)try{({text:r,items:o}=await tx(n.leadBox,i.cwd,{timeoutMs:w4})),s="lead-cli"}catch{}if(r||(r=wx(n,await K(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 nr(e,t){let n=await at(e,t).catch(()=>null);if(!n?.archiveOnMerge||!n.trackId)return!1;let r=await Yw(n);if(r.length){for(let o of r)await No(o.repo,o.number,!0).catch(()=>{});return!1}try{return await Yo(n.trackId),!0}catch(o){if(/already archived/i.test(String(o?.message||o)))return!1;throw o}}async function Yw(e){return(await Xn().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 rr(e,t){return Td(e,t,"merged")}async function Xo(e,t){let n=await at(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 Yw(n);if(o.length){let c=[...n.followupPending||[],r];for(let l of o)await cS(l.repo,l.number,c).catch(()=>{});return null}let s=[...n.followupPending||[],r],a=we(await ee(),n.trackId);if(!a)return null;let i=s[0];return Gi(await Nt(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 Td(e,t,n="merged"){let r=await at(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 Yw(r);if(s.length){let i=[...r.notifyPending||[],o];for(let c of s)await iS(c.repo,c.number,i).catch(()=>{});return!1}let a=[...r.notifyPending||[],o];if(!await eS(r.repo,r.number).catch(()=>!0))return!1;try{return await Dt(r.trackId,u_(a),{kind:"merge-notify"}),!0}catch{return await Po(r.repo,r.number,!0).catch(()=>{}),!1}}function u_(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 ${HE[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 ${HE[i.outcome]??i.outcome}`).join(`
242
242
  `),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}
243
243
  ${s}
244
- ${a}`}async function Yw(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<ai()?!1:Kn(e.name)}async function gc(e,t,n){return!t||e.archivedAt||eo.has(t.state)?!1:(await le({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 en(t.name).catch(()=>{}),t.state="stopped",Ac(e))}async function Ac(e,{freshSession:t=!1,reason:n=null}={}){let r=e.boxes.find(a=>a.name===e.leadBox);if(!r)return!1;let o=kw.get(r.name);if(o)return o;let s=y4(e,r,{freshSession:t,reason:n}).finally(()=>kw.delete(r.name));return kw.set(r.name,s),s}async function y4(e,t,{freshSession:n=!1,reason:r=null}={}){if(e.archivedAt||e.transferredTo||eo.has(t.state)||await ke(t.name))return!1;let o=n===!0,s=o?hd():null,a=o?oi($w(t.agent),s,t.name):Rw(t.agent,t.sessionId,{cwd:t.cwd,peerName:t.name}),i=await Cl(a);if(i===vs)return Ie(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:`agent "${t.agent}" is not installed on this box`}),!1;i===Ss&&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(ga(t)))}:null,l=Date.now();if(o){let u=ga(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=await _r(t.name,t.cwd,{agentCmd:a,agent:t.agent,resumeSessionId:t.sessionId,pinned:t.pinned===!0});return t.hookTokenHash=La(u.hookToken),mi({cwd:t.cwd,sessionName:t.name,agent:t.agent,agentCmd:a}),t.state="live",o&&Ie(e,"lead-refreshed",{box:t.name,agent:t.agent,fromSessionId:c.sessionId,toSessionId:s,epoch:t.epochs.length-1,reason:r||"fresh-session"}),Ie(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),Ie(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:String(u?.message||u)}),!1}}async function Td(e,{freshSession:t=!1}={}){let n=await ee(),r=we(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,wc.delete(e),Ie(r,"unarchived",{}),await Ac(r,t?{freshSession:!0,reason:"loop-fire"}:{}),await ae(),Nt(r)}async function Xw(e,t){let n=typeof t=="string"?t.trim():"";if(!n)throw new Error("name (non-empty string) required");if(n.length>Ew)throw new Error(`name too long (max ${Ew} chars)`);let r=await ee(),o=we(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 Nt(o);let s=o.name;return o.name=n,Ie(o,"renamed",{from:s,to:n}),await ae(),Nt(o)}async function Zw(){let e=await ee(),t=0;for(let n of e.tracks||[])n.transferredTo&&du(n,{at:n.transferredAt??Date.now()})&&t++;return t&&await ae(),t}async function Qw(){let e=await ee(),t=new Set((await Qt()).map(s=>s.name)),n=new Set((e.tracks||[]).filter(s=>!Ve(s)).flatMap(s=>(s.boxes||[]).map(a=>a.name))),r=0,o=!1;for(let s of e.tracks||[])if(Ve(s))for(let a of s.boxes)t.has(a.name)&&!n.has(a.name)&&(await en(a.name).catch(()=>{}),s.transferredTo?console.log(`[track] reaped orphan box ${a.name} on transferred-away track ${s.id} (\u2192 ${s.transferredTo})`):Ie(s,"orphan-reaped",{box:a.name,agent:a.agent}),r++,o=!0),!eo.has(a.state)&&a.state!=="stopped"&&(a.state="stopped",o=!0);return o&&await ae(),r}async function Ad(e,{freshSession:t=!1}={}){let n=await ee(),r=we(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`);sg(r);let o=r.boxes.find(i=>i.name===r.leadBox);if(!o)throw new Error(`track "${e}" has no lead box`);if(eo.has(o.state))throw new Error("lead box is terminal \u2014 nothing to restart");if(await ke(r.leadBox)){let i=await je(r.leadBox,{lines:tt}).catch(()=>"");if(ql(o.agent,i))throw new Error("lead is mid-turn \u2014 retry when it goes idle");await en(r.leadBox),o.state="stopped"}let a=await Ac(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 Nt(r)}async function eg(e,t,n){let r=await oe(e);if(!r)throw new Error(`track "${e}" not found`);if(!t)throw new Error("unknown offer");let o=await K(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 Ad(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 HE(e,t){if(!e?.id||!t?.box)return[];let n=(e.boxes||[]).find(r=>r.name===t.box);return Lu({trackId:e.id,boxId:t.box,epoch:0,provider:n?.agent??t.agent??null})}function ga(e){return(!Array.isArray(e.epochs)||e.epochs.length===0)&&(e.epochs=[{agent:e.agent??null,sessionId:e.sessionId??null,pinned:e.pinned===!0,startedAt:e.createdAt??null,endedAt:null}]),e.epochs}async function md(e,t){let n=await ee(),r=we(n,e);r&&(r.handoff={...r.handoff||{},...t},await ae())}function u_(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 ng(){let e=await ee(),t=!1;for(let n of e.tracks||[]){let r=n.handoff,o=u_(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=ga(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;d.push({agent:r.toAgent,sessionId:c.sessionId||null,pinned:m,startedAt:u,endedAt:null}),l.agent=r.toAgent,l.sessionId=c.sessionId||null,l.pinned=m,l.state="live",n.pendingHandoffHydrate={artifact:zo,at:u},Ie(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 le({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 le({flow:"lead-handoff",phase:"reconciled",trackId:n.id,outcome:o.step,recovered:o.recovered,fromBox:o.fromBox,toBox:o.toBox}).catch(()=>{}),i&&await en(i).catch(()=>{}),a&&await en(a).catch(()=>{})}return t&&await ae(),t}async function Ed(e,t,n=!0,r=null){let o=ya.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is already running for this Track");let s=we(await ee(),e);if(!s)throw new Error(`track "${e}" not found`);Sc(e,"handoff");let a=await kc(t,n),i=Co(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:JE(r),toBox:s.leadBox,startedAt:Date.now(),finishedAt:null,error:null};return ya.set(e,l),await md(e,{step:l.step,fromBox:l.fromBox,toAgent:t,toBox:l.toBox,skipPermissions:n,startedAt:l.startedAt,finishedAt:null,error:null}),b4(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 md(e,{step:l.step,error:l.error,finishedAt:l.finishedAt}).catch(()=>{}),le({flow:"lead-handoff",phase:"failed",trackId:e,step:l.step,error:l.error,fromBox:l.fromBox,toAgent:l.toAgent,toBox:l.toBox}).catch(()=>{})}),le({flow:"lead-handoff",phase:"started",trackId:e,fromBox:l.fromBox,toAgent:t,cwd:c.cwd}).catch(()=>{}),l}async function b4(e,t,n,r,o){let s=async(O,M={})=>{e.step=O,console.log(`[lead-handoff ${e.trackId}] step \u2192 ${O}`),await md(e.trackId,{step:O,toBox:e.toBox}),await le({flow:"lead-handoff",phase:O,trackId:e.trackId,fromBox:e.fromBox,toBox:e.toBox,toAgent:o,sessionName:M.sessionName,...M})};console.log(`[lead-handoff ${e.trackId}] ${e.fromBox}: ${n.agent} \u2192 ${o} IN PLACE`);let a=await ee(),i=we(a,e.trackId)?.boxes.find(O=>O.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",Co(c))e.checkpoint="skipped-capped";else try{await Wf(e.fromBox,{timeoutMs:zE})}catch(O){e.checkpoint="reconstructed",await le({flow:"lead-handoff",phase:"checkpoint-fallback",trackId:e.trackId,fromBox:e.fromBox,error:O?.message||String(O)}).catch(()=>{})}e.checkpoint!=="llm"&&(e.statusArtifact=await qf(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=await Xf(e.fromBox,{agentCmd:r,agent:o});await s("hydrate",{sessionName:e.fromBox});let f=t0(p.launchCmd);await $r({cwd:n.cwd,sessionId:p.sessionId,sessionName:e.fromBox,agent:o,agentCmd:ka(o),launchEcho:f}).catch(O=>{if(O?.code!=="cli-not-running")throw O});let w=Ef(await je(e.fromBox,{lines:tt}).catch(()=>""),f);if(!Ms(o,w)){await s("rollback",{sessionName:e.fromBox,fromAgent:c});let O=Rw(c,l,{skipPermissions:e.skipPermissions,cwd:n.cwd,peerName:e.fromBox});await Xf(e.fromBox,{agentCmd:O,agent:c,resumeSessionId:l,pinned:u});let M=await ee(),H=we(M,e.trackId);if(H){let P=H.boxes.find(E=>E.name===e.fromBox);P&&(P.state="live"),Ie(H,"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 m=await ee(),g=we(m,e.trackId);if(!g)throw new Error(`track "${e.trackId}" not found during handoff commit \u2014 was it deleted or archived mid-flight?`);let b=g.boxes.find(O=>O.name===e.fromBox);if(!b)throw new Error(`lead box row "${e.fromBox}" missing during handoff commit`);let x=Date.now(),y=ga(b),$=y[y.length-1];$.endedAt=x,e.reason&&($.endReason=e.reason),y.push({agent:o,sessionId:p.sessionId,pinned:p.pinned,startedAt:x,endedAt:null}),b.agent=o,b.sessionId=p.sessionId,b.pinned=p.pinned,b.state="live",b.role="lead",g.pendingHandoffHydrate={artifact:e.statusArtifact||zo,at:x},Ie(g,"lead-handoff",{from:e.fromBox,to:e.fromBox,fromAgent:c,toAgent:o,fromSessionId:l,toSessionId:p.sessionId,epoch:y.length-1,singleBox:!0,forced:p.forced||void 0,skipPermissions:e.skipPermissions,reason:e.reason,handoffStartedAt:e.startedAt,checkpoint:e.checkpoint}),await ae(),await s("done",{sessionName:e.fromBox}),await md(e.trackId,{finishedAt:Date.now(),error:null}),e.finishedAt=Date.now()}async function og(e){let t=Iw.get(e);if(t&&!t.finishedAt)throw new Error("a transfer is already running for this Track");let n=await ee(),r=we(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=ya.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is running \u2014 retry when it settles");for(let a of Pt.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 Iw.set(e,s),k4(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 k4(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&&Co(n.agent))e.checkpoint=r?"skipped-capped":"skipped-dead";else try{await Wf(t.leadBox,{timeoutMs:zE})}catch{e.checkpoint="reconstructed"}e.checkpoint!=="llm"&&await qf(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 ln(u.dir,["push","origin",o],_w);let{stdout:p}=await ln(u.dir,["rev-parse","HEAD"]);d.baseSha=p.trim(),d.pushed=!0}catch(p){d.error=String(p?.message||p).split(`
245
- `)[0]}s.push(d)}e.step="wip";let a=await iw({id:t.id,cwd:t.cwd},{force:!0}),i=await ee(),c=we(i,t.id),l=c?.boxes.find(u=>u.name===c.leadBox)||null;l&&ga(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?{ref:a.ref,sha:a.sha}:null,checkpoint:e.checkpoint,epochs:l?.epochs??[],codeless:!o||!s.some(u=>u.pushed)},e.step="ready",e.finishedAt=Date.now()}function sg(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 _d(e,{toNode:t,mode:n="transfer"}={}){if(!t||typeof t!="string")throw new Error("toNode required");let r=await ee(),o=we(r,e);if(!o)throw new Error(`track "${e}" not found`);if(o.transferredTo)return{ok:!0,alreadyTransferred:o.transferredTo};Fw(e),await zw(e,o,n==="recover"?"track recovered onto another node":"track transferred to another node");let s=Date.now();du(o,{at:s,reason:n==="recover"?"node-offline":"node-transfer"});let a=await cw({id:o.id,cwd:o.cwd});return o.transferredTo=t,o.transferredAt=s,Ie(o,"transferred-out",{toNode:t,mode:n,box:o.leadBox,...a.pushed?{rescueRef:a.ref,rescueSha:a.sha}:{}}),await ae(),{ok:!0,toNode:t,rescue:a.pushed?{ref:a.ref,sha:a.sha}:null}}async function ag(e){let t=[];for(let n of Array.isArray(e)?e:[])if(!(!n?.id||!n?.toNode))try{let r=await _d(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 WE(e,t,n){try{await lu(e,t,n)}catch{await ln(e,["worktree","prune"]).catch(()=>{}),await lu(e,t,n)}return t}function v4(e){if(typeof e!="string"||!x4.test(e)||e.includes("..")||e.includes("@{")||e.endsWith(".lock"))throw new Error("branch fails the safe-ref check")}async function ig(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&&v4(e.branch),xw.has(t))throw new Error("an adopt is already running for this Track");xw.set(t,{startedAt:Date.now()});try{return await S4({...e,trackId:t,name:n,agent:r,skipPermissions:o,mode:s})}finally{xw.delete(t)}}async function S4({trackId:e,name:t,agent:n,skipPermissions:r,mode:o,fromNode:s=null,toNode:a=null,branch:i=null,repos:c=[],wip:l=null,brief:u=null,epochs:d=[],createdAt:p=null,leadBox:f=null,reason:w=null,downSince:m=null}){let g=await kc(n,r),b=await ee(),x=we(b,e);if(x&&!x.transferredTo)throw new Error(`track "${e}" is already hosted on this node`);x&&(await cw({id:x.id,cwd:x.cwd}).catch(()=>{}),await i_(x),b.tracks.splice(b.tracks.indexOf(x),1),await ae()),await Q.mkdir(dc,{recursive:!0});let y=re.join(dc,e);await Q.rm(y,{recursive:!0,force:!0}).catch(()=>{});let $=null,O=!1,M=[];try{let H=[];if(i)for(let W of Array.isArray(c)?c:[]){let te=typeof W=="string"?W:W?.repo;if(!te||!/^[^/\s]+\/[^/\s]+$/.test(te))continue;let ie=await ms(te)??await pl(te);await ln(ie,["fetch","origin",`+refs/heads/${i}:refs/heads/${i}`],_w),H.push({slug:te,base:ie,name:typeof W=="object"?W?.name??null:null})}if(i&&H.length===1){let{base:W,slug:te}=H[0];await WE(W,y,i),M.push({base:W,dir:y}),await hc(y);let ie=await qs(W);$={dir:y,base:W,branch:i,kind:"worktree",baseRef:ie,repo:te}}else if(i&&H.length>=2){await Q.mkdir(y,{recursive:!0});let W=new Set([".bostrat"]),te=[];for(let ie of H){let J=ie.name||re.basename(ie.base);W.has(J)&&(J=ie.slug.replace("/","-"));for(let Me=2;W.has(J);Me++)J=`${re.basename(ie.base)}-${Me}`;W.add(J);let ge=re.join(y,J);await WE(ie.base,ge,i),M.push({base:ie.base,dir:ge});let Oe=await qs(ie.base);te.push({name:J,dir:ge,base:ie.base,baseRef:Oe,repo:ie.slug})}await Tc(y,te,i),$={dir:y,kind:"multi",branch:i,repos:te}}else O=!0,await Q.mkdir(y,{recursive:!0}),await km(y),await hc(y),$={dir:y,base:null,branch:null,kind:"repo"};let P=!1,E=null,R=null;if(l?.sha&&$.kind==="worktree")try{await ln(y,["fetch","origin",aw(e)],_w);let{stdout:W}=await ln(y,["rev-parse","FETCH_HEAD^"]),{stdout:te}=await ln(y,["rev-parse","HEAD"]),ie=W.trim()===te.trim();ie||await ln(y,["merge-base","--is-ancestor",te.trim(),W.trim()]).then(()=>!0,()=>!1)&&(await ln(y,["reset","--hard",W.trim()]),R={from:te.trim(),to:W.trim()},ie=!0),ie?(await ln(y,["read-tree","--reset","-u","FETCH_HEAD"]),await ln(y,["reset","-q"]),P=!0):E="snapshot does not parent the fetched branch head"}catch(W){E=String(W?.message||W).split(`
246
- `)[0]}else l?.sha&&(E="wip snapshots cover single-repo worktrees only");await RE({id:e,cwd:y}).catch(()=>({restored:!1}));let G=re.join(y,zo),V=null;(await Al(y)).restored?V="checkpoint":typeof u=="string"&&u.trim()&&(await Q.mkdir(re.dirname(G),{recursive:!0}),await Q.writeFile(G,u),V="brief");let _=new Set(b.tracks.flatMap(W=>(W.boxes||[]).map(te=>te.name))),N=null;f&&!_.has(f)&&!await ke(f).catch(()=>null)?N=f:(N=`${t.trim()} lead`,_.has(Ml(N))&&(N=`${t.trim().slice(0,50).trim()} ${e} lead`));let U=await _r(N,y,{agentCmd:g,agent:n});mi({cwd:U.cwd,sessionName:U.name,agent:n,agentCmd:g});let z=Date.now(),ue=tg(U,"lead","live"),pe=(Array.isArray(d)?d:[]).filter(W=>W&&typeof W=="object").map(W=>({...W})),Se=pe[pe.length-1];Se&&Se.endedAt==null&&(Se.endedAt=z,Se.endReason==null&&(Se.endReason=o==="recover"?"node-offline":"node-transfer")),pe.push({agent:n,sessionId:U.sessionId??null,pinned:U.pinned===!0,startedAt:z,endedAt:null}),ue.epochs=pe;let Ae={id:e,name:t.trim(),cwd:U.cwd,workspace:$,leadBox:U.name,boxes:[ue],events:[],createdAt:Number.isFinite(p)?p:z,...V?{pendingHandoffHydrate:{artifact:zo,at:z}}:{}};return Ie(Ae,"transferred-in",{box:U.name,agent:n,fromNode:s,toNode:a,mode:o,reason:w,...o==="recover"?{downSince:Number.isFinite(m)?m:null}:{},branch:$.branch??null,wip:P,...R?{wipAdvanced:R}:{},epoch:pe.length-1,name:Ae.name,cwd:Ae.cwd,workspace:{base:$.base??null,branch:$.branch??null,kind:$.kind,...$.baseRef?{baseRef:$.baseRef}:{},...$.repo?{repo:$.repo}:{},...$.repos?{repos:$.repos.map(({name:W,base:te,baseRef:ie,repo:J})=>({name:W,base:te,baseRef:ie,repo:J}))}:{}}}),b.tracks.push(Ae),await ae(),{...await Nt(Ae),adopt:{wipApplied:P,wipSkipped:E,...R?{wipAdvanced:R}:{},codeless:O,artifactSource:V}}}catch(H){for(let P of M)await Ot(P.base,P.dir).catch(()=>{});throw await Q.rm(y,{recursive:!0,force:!0}).catch(()=>{}),H}}async function d_(e,t,n){let r=await ee(),o=we(r,e);o&&(o.subtasks=o.subtasks||{},o.subtasks[t]={...o.subtasks[t]||{},...n},await ae())}async function pa(e,t){e.step=t,await Ec(e)}function p_(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 f_(e){return!!e&&!e.finishedAt&&!e.canceled&&e.step==="working"&&!!e.box&&!!e.dir&&!!e.base&&!!e.branch}async function _4(e,t,n){if(!f_(n)||Pt.has(t)||!await ke(n.box).catch(()=>null))return!1;try{await Q.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 Pt.set(t,s),h_(s,o).catch(a=>m_(s,a)),!0}async function cg(){let e=await ee(),t=!1;for(let n of e.tracks||[]){for(let[r,o]of Object.entries(n.subtasks||{})){if(Pt.has(r))continue;if(await _4(n,r,o)){t=!0,Ie(n,"subtask-resumed",{box:o.box,agent:o.agent,task:o.task,subtaskId:r,resumedStep:o.step}),await le({flow:"subtask",phase:"resumed",trackId:n.id,subtaskId:r,box:o.box,branch:o.branch}).catch(()=>{});continue}let s=o.step,a=p_(o);if(!a)continue;t=!0,n.subtasks[r]=a;let i=n.boxes.find(c=>c.subtaskId===r);i&&!eo.has(i.state)&&(i.state="canceled"),Ie(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 le({flow:"subtask",phase:"reconciled",trackId:n.id,subtaskId:r,outcome:a.step,recovered:a.recovered,box:o.box,branch:o.branch}).catch(()=>{}),await qE(n,o.box,o.dir)}for(let r of n.boxes){if(r.role!=="subtask"||eo.has(r.state)||Pt.has(r.subtaskId)||n.subtasks?.[r.subtaskId])continue;t=!0,r.state="canceled";let o=r.subtaskId?re.join(ba,`${n.id}-${r.subtaskId}`):null;await le({flow:"subtask",phase:"reaped-legacy-orphan",trackId:n.id,subtaskId:r.subtaskId,box:r.name}).catch(()=>{}),await qE(n,r.name,o)}}return t=await I4(e)||t,t&&await ae(),t}async function qE(e,t,n){if(t&&await en(t).catch(()=>{}),!n)return;if(e.workspace?.kind==="multi"){for(let o of jt(e.workspace)){let s=re.join(n,o.name);await Ot(o.base,s).then(()=>!0,()=>!1)||await Ot(o.dir,s).catch(()=>{})}await Q.rm(n,{recursive:!0,force:!0}).catch(()=>{});return}let r=await ke(e.leadBox).catch(()=>null);r?.cwd&&await Ot(r.cwd,n).catch(()=>{})}async function I4(e){let t;try{t=await Q.readdir(ba)}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 Pt.values())o.dir&&n.add(re.basename(o.dir));let r=!1;for(let o of t){if(n.has(o))continue;let s=re.join(ba,o),a=(e.tracks||[]).find(i=>o.startsWith(`${i.id}-`));if(a?.workspace?.kind==="multi"){for(let i of jt(a.workspace))await Ot(i.base,re.join(s,i.name)).catch(()=>{});await Q.rm(s,{recursive:!0,force:!0}).catch(()=>{})}else{let i=a?await ke(a.leadBox).catch(()=>null):null;i?.cwd?await Ot(i.cwd,s).catch(()=>{}):await Q.rm(s,{recursive:!0,force:!0}).catch(()=>{})}await le({flow:"subtask",phase:"swept-orphan-worktree",dir:s}).catch(()=>{}),r=!0}return r}async function ug(e,{agent:t,task:n,skipPermissions:r=!0,reason:o=null}={}){if(typeof n!="string"||!Fs(n))throw new Error("task (string) required");let s=await kc(t,r),a=Co(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=we(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=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 Us(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 Us(c.cwd))throw new Error(`subtask delegation needs the lead's workspace to be a git repo (got ${c.cwd})`);let d=hd().slice(0,8),p={id:d,trackId:e,trackName:i.name,agent:t,task:Fs(n),skipPermissions:r,reason:JE(o),step:"snapshot",leadBox:i.leadBox,box:null,branch:`bostrat/${lg(i.name)}-${d}`,base:null,repos:u,dir:re.join(ba,`${e}-${d}`),stat:null,conflicts:[],applied:null,startedAt:Date.now(),finishedAt:null,error:null,canceled:!1,forceMerge:!1};return Pt.set(d,p),await Ec(p),$4(p,c,s).catch(f=>m_(p,f)),p}async function m_(e,t){e.failedStep=e.step,e.error=t instanceof yc?"canceled":t?.message||String(t),e.step=t instanceof yc?"canceled":"error",e.finishedAt=Date.now(),await pg(e).catch(()=>{}),await Ec(e).catch(()=>{}),await M4(e).catch(()=>{})}function $d(e){let t=Pt.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 dg(e){let t=Pt.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 $4(e,t,n){if(await pa(e,"snapshot"),e.repos){for(let s of e.repos)s.base=await Hs(s.leadDir,`bostrat: snapshot for subtask ${e.id}`);await Ec(e)}else e.base=await Hs(t.cwd,`bostrat: snapshot for subtask ${e.id}`);if(await pa(e,"spawn"),await Q.mkdir(ba,{recursive:!0}),e.repos){await Q.mkdir(e.dir,{recursive:!0});for(let a of e.repos)await Ws(a.leadDir,re.join(e.dir,a.name),e.branch,a.base);let s=jt((we(await ee(),e.trackId)||{}).workspace);await Tc(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 Ws(t.cwd,e.dir,e.branch,e.base),await hc(e.dir);await R4(e,t);let r=e.trackName.slice(0,38).trim(),o=await _r(`${r} ${e.agent} sub ${e.id}`,e.dir,{agentCmd:n,agent:e.agent});e.box=o.name,await O4(e,o),await YE(e.trackId,o.name,EU(e.task,!!e.repos),{kind:"subtask"}),await h_(e,t)}async function h_(e,t){await pa(e,"working");let n=re.join(e.dir,fd);if(await P4(n,e),e.canceled)throw new yc;if(await pa(e,"merge"),e.repos){let s={files:0,insertions:0,deletions:0},a=[],i=[],c=!0;for(let l of e.repos){let u=re.join(e.dir,l.name);await bm(u,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:HE({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),l.stat=await vm(l.leadDir,l.base,e.branch,da),l.files=await Sm(l.leadDir,l.base,e.branch,da);let d=await Tm(l.leadDir,l.base,e.branch,da);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=>re.join(l.name,p))),i.push(...l.conflicts.map(p=>p.startsWith("patch did not apply cleanly")?`${l.name}: ${p}`:re.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:HE({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),e.stat=await vm(t.cwd,e.base,e.branch,da),e.files=await Sm(t.cwd,e.base,e.branch,da);let s=await Tm(t.cwd,e.base,e.branch,da);e.applied=s.applied,e.conflicts=s.conflicts}await Ec(e);let r=await N4(e,t,n);await pa(e,"resume"),await YE(e.trackId,e.leadBox,_U(e.task,e.stat,e.conflicts,r),{kind:"subtask-resume"}),await pa(e,"reap"),await pg(e),e.step="done";let o=Date.now();await d_(e.trackId,e.id,{...Id(e),finishedAt:o}),await C4(e,o),e.finishedAt=o}async function R4(e,t){let n=re.join(e.dir,re.dirname(pc));await Q.mkdir(n,{recursive:!0});let r="";try{r=await Bk(t.cwd,t.sessionId)}catch{}if(!r)try{r=await Q.readFile(re.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}
244
+ ${a}`}async function Xw(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<ai()?!1:Kn(e.name)}async function gc(e,t,n){return!t||e.archivedAt||eo.has(t.state)?!1:(await le({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 en(t.name).catch(()=>{}),t.state="stopped",Ac(e))}async function Ac(e,{freshSession:t=!1,reason:n=null}={}){let r=e.boxes.find(a=>a.name===e.leadBox);if(!r)return!1;let o=xw.get(r.name);if(o)return o;let s=b4(e,r,{freshSession:t,reason:n}).finally(()=>xw.delete(r.name));return xw.set(r.name,s),s}async function b4(e,t,{freshSession:n=!1,reason:r=null}={}){if(e.archivedAt||e.transferredTo||eo.has(t.state)||await ke(t.name))return!1;let o=n===!0,s=o?wd():null,a=o?oi(Rw(t.agent),s,t.name):Ow(t.agent,t.sessionId,{cwd:t.cwd,peerName:t.name}),i=await Cl(a);if(i===vs)return Ie(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:`agent "${t.agent}" is not installed on this box`}),!1;i===Ss&&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(ga(t)))}:null,l=Date.now();if(o){let u=ga(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=await _r(t.name,t.cwd,{agentCmd:a,agent:t.agent,resumeSessionId:t.sessionId,pinned:t.pinned===!0});return t.hookTokenHash=La(u.hookToken),mi({cwd:t.cwd,sessionName:t.name,agent:t.agent,agentCmd:a}),t.state="live",o&&Ie(e,"lead-refreshed",{box:t.name,agent:t.agent,fromSessionId:c.sessionId,toSessionId:s,epoch:t.epochs.length-1,reason:r||"fresh-session"}),Ie(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),Ie(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:String(u?.message||u)}),!1}}async function Ad(e,{freshSession:t=!1}={}){let n=await ee(),r=we(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,wc.delete(e),Ie(r,"unarchived",{}),await Ac(r,t?{freshSession:!0,reason:"loop-fire"}:{}),await ae(),Nt(r)}async function Zw(e,t){let n=typeof t=="string"?t.trim():"";if(!n)throw new Error("name (non-empty string) required");if(n.length>_w)throw new Error(`name too long (max ${_w} chars)`);let r=await ee(),o=we(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 Nt(o);let s=o.name;return o.name=n,Ie(o,"renamed",{from:s,to:n}),await ae(),Nt(o)}async function Qw(){let e=await ee(),t=0;for(let n of e.tracks||[])n.transferredTo&&du(n,{at:n.transferredAt??Date.now()})&&t++;return t&&await ae(),t}async function eg(){let e=await ee(),t=new Set((await Qt()).map(s=>s.name)),n=new Set((e.tracks||[]).filter(s=>!Ve(s)).flatMap(s=>(s.boxes||[]).map(a=>a.name))),r=0,o=!1;for(let s of e.tracks||[])if(Ve(s))for(let a of s.boxes)t.has(a.name)&&!n.has(a.name)&&(await en(a.name).catch(()=>{}),s.transferredTo?console.log(`[track] reaped orphan box ${a.name} on transferred-away track ${s.id} (\u2192 ${s.transferredTo})`):Ie(s,"orphan-reaped",{box:a.name,agent:a.agent}),r++,o=!0),!eo.has(a.state)&&a.state!=="stopped"&&(a.state="stopped",o=!0);return o&&await ae(),r}async function Ed(e,{freshSession:t=!1}={}){let n=await ee(),r=we(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`);ag(r);let o=r.boxes.find(i=>i.name===r.leadBox);if(!o)throw new Error(`track "${e}" has no lead box`);if(eo.has(o.state))throw new Error("lead box is terminal \u2014 nothing to restart");if(await ke(r.leadBox)){let i=await Be(r.leadBox,{lines:tt}).catch(()=>"");if(ql(o.agent,i))throw new Error("lead is mid-turn \u2014 retry when it goes idle");await en(r.leadBox),o.state="stopped"}let a=await Ac(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 Nt(r)}async function tg(e,t,n){let r=await oe(e);if(!r)throw new Error(`track "${e}" not found`);if(!t)throw new Error("unknown offer");let o=await K(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 Ed(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 WE(e,t){if(!e?.id||!t?.box)return[];let n=(e.boxes||[]).find(r=>r.name===t.box);return Fu({trackId:e.id,boxId:t.box,epoch:0,provider:n?.agent??t.agent??null})}function ga(e){return(!Array.isArray(e.epochs)||e.epochs.length===0)&&(e.epochs=[{agent:e.agent??null,sessionId:e.sessionId??null,pinned:e.pinned===!0,startedAt:e.createdAt??null,endedAt:null}]),e.epochs}async function hd(e,t){let n=await ee(),r=we(n,e);r&&(r.handoff={...r.handoff||{},...t},await ae())}function d_(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 rg(){let e=await ee(),t=!1;for(let n of e.tracks||[]){let r=n.handoff,o=d_(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=ga(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;d.push({agent:r.toAgent,sessionId:c.sessionId||null,pinned:m,startedAt:u,endedAt:null}),l.agent=r.toAgent,l.sessionId=c.sessionId||null,l.pinned=m,l.state="live",n.pendingHandoffHydrate={artifact:zo,at:u},Ie(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 le({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 le({flow:"lead-handoff",phase:"reconciled",trackId:n.id,outcome:o.step,recovered:o.recovered,fromBox:o.fromBox,toBox:o.toBox}).catch(()=>{}),i&&await en(i).catch(()=>{}),a&&await en(a).catch(()=>{})}return t&&await ae(),t}async function _d(e,t,n=!0,r=null){let o=ya.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is already running for this Track");let s=we(await ee(),e);if(!s)throw new Error(`track "${e}" not found`);Sc(e,"handoff");let a=await kc(t,n),i=Co(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:YE(r),toBox:s.leadBox,startedAt:Date.now(),finishedAt:null,error:null};return ya.set(e,l),await hd(e,{step:l.step,fromBox:l.fromBox,toAgent:t,toBox:l.toBox,skipPermissions:n,startedAt:l.startedAt,finishedAt:null,error:null}),k4(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 hd(e,{step:l.step,error:l.error,finishedAt:l.finishedAt}).catch(()=>{}),le({flow:"lead-handoff",phase:"failed",trackId:e,step:l.step,error:l.error,fromBox:l.fromBox,toAgent:l.toAgent,toBox:l.toBox}).catch(()=>{})}),le({flow:"lead-handoff",phase:"started",trackId:e,fromBox:l.fromBox,toAgent:t,cwd:c.cwd}).catch(()=>{}),l}async function k4(e,t,n,r,o){let s=async(O,M={})=>{e.step=O,console.log(`[lead-handoff ${e.trackId}] step \u2192 ${O}`),await hd(e.trackId,{step:O,toBox:e.toBox}),await le({flow:"lead-handoff",phase:O,trackId:e.trackId,fromBox:e.fromBox,toBox:e.toBox,toAgent:o,sessionName:M.sessionName,...M})};console.log(`[lead-handoff ${e.trackId}] ${e.fromBox}: ${n.agent} \u2192 ${o} IN PLACE`);let a=await ee(),i=we(a,e.trackId)?.boxes.find(O=>O.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",Co(c))e.checkpoint="skipped-capped";else try{await qf(e.fromBox,{timeoutMs:VE})}catch(O){e.checkpoint="reconstructed",await le({flow:"lead-handoff",phase:"checkpoint-fallback",trackId:e.trackId,fromBox:e.fromBox,error:O?.message||String(O)}).catch(()=>{})}e.checkpoint!=="llm"&&(e.statusArtifact=await Kf(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=await Zf(e.fromBox,{agentCmd:r,agent:o});await s("hydrate",{sessionName:e.fromBox});let f=t0(p.launchCmd);await $r({cwd:n.cwd,sessionId:p.sessionId,sessionName:e.fromBox,agent:o,agentCmd:ka(o),launchEcho:f}).catch(O=>{if(O?.code!=="cli-not-running")throw O});let w=_f(await Be(e.fromBox,{lines:tt}).catch(()=>""),f);if(!Ms(o,w)){await s("rollback",{sessionName:e.fromBox,fromAgent:c});let O=Ow(c,l,{skipPermissions:e.skipPermissions,cwd:n.cwd,peerName:e.fromBox});await Zf(e.fromBox,{agentCmd:O,agent:c,resumeSessionId:l,pinned:u});let M=await ee(),H=we(M,e.trackId);if(H){let P=H.boxes.find(E=>E.name===e.fromBox);P&&(P.state="live"),Ie(H,"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 m=await ee(),g=we(m,e.trackId);if(!g)throw new Error(`track "${e.trackId}" not found during handoff commit \u2014 was it deleted or archived mid-flight?`);let b=g.boxes.find(O=>O.name===e.fromBox);if(!b)throw new Error(`lead box row "${e.fromBox}" missing during handoff commit`);let x=Date.now(),y=ga(b),$=y[y.length-1];$.endedAt=x,e.reason&&($.endReason=e.reason),y.push({agent:o,sessionId:p.sessionId,pinned:p.pinned,startedAt:x,endedAt:null}),b.agent=o,b.sessionId=p.sessionId,b.pinned=p.pinned,b.state="live",b.role="lead",g.pendingHandoffHydrate={artifact:e.statusArtifact||zo,at:x},Ie(g,"lead-handoff",{from:e.fromBox,to:e.fromBox,fromAgent:c,toAgent:o,fromSessionId:l,toSessionId:p.sessionId,epoch:y.length-1,singleBox:!0,forced:p.forced||void 0,skipPermissions:e.skipPermissions,reason:e.reason,handoffStartedAt:e.startedAt,checkpoint:e.checkpoint}),await ae(),await s("done",{sessionName:e.fromBox}),await hd(e.trackId,{finishedAt:Date.now(),error:null}),e.finishedAt=Date.now()}async function sg(e){let t=$w.get(e);if(t&&!t.finishedAt)throw new Error("a transfer is already running for this Track");let n=await ee(),r=we(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=ya.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is running \u2014 retry when it settles");for(let a of Pt.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 $w.set(e,s),x4(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 x4(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&&Co(n.agent))e.checkpoint=r?"skipped-capped":"skipped-dead";else try{await qf(t.leadBox,{timeoutMs:VE})}catch{e.checkpoint="reconstructed"}e.checkpoint!=="llm"&&await Kf(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 ln(u.dir,["push","origin",o],Iw);let{stdout:p}=await ln(u.dir,["rev-parse","HEAD"]);d.baseSha=p.trim(),d.pushed=!0}catch(p){d.error=String(p?.message||p).split(`
245
+ `)[0]}s.push(d)}e.step="wip";let a=await cw({id:t.id,cwd:t.cwd},{force:!0}),i=await ee(),c=we(i,t.id),l=c?.boxes.find(u=>u.name===c.leadBox)||null;l&&ga(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?{ref:a.ref,sha:a.sha}:null,checkpoint:e.checkpoint,epochs:l?.epochs??[],codeless:!o||!s.some(u=>u.pushed)},e.step="ready",e.finishedAt=Date.now()}function ag(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 Id(e,{toNode:t,mode:n="transfer"}={}){if(!t||typeof t!="string")throw new Error("toNode required");let r=await ee(),o=we(r,e);if(!o)throw new Error(`track "${e}" not found`);if(o.transferredTo)return{ok:!0,alreadyTransferred:o.transferredTo};Uw(e),await Vw(e,o,n==="recover"?"track recovered onto another node":"track transferred to another node");let s=Date.now();du(o,{at:s,reason:n==="recover"?"node-offline":"node-transfer"});let a=await lw({id:o.id,cwd:o.cwd});return o.transferredTo=t,o.transferredAt=s,Ie(o,"transferred-out",{toNode:t,mode:n,box:o.leadBox,...a.pushed?{rescueRef:a.ref,rescueSha:a.sha}:{}}),await ae(),{ok:!0,toNode:t,rescue:a.pushed?{ref:a.ref,sha:a.sha}:null}}async function ig(e){let t=[];for(let n of Array.isArray(e)?e:[])if(!(!n?.id||!n?.toNode))try{let r=await Id(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 qE(e,t,n){try{await lu(e,t,n)}catch{await ln(e,["worktree","prune"]).catch(()=>{}),await lu(e,t,n)}return t}function S4(e){if(typeof e!="string"||!v4.test(e)||e.includes("..")||e.includes("@{")||e.endsWith(".lock"))throw new Error("branch fails the safe-ref check")}async function cg(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&&S4(e.branch),vw.has(t))throw new Error("an adopt is already running for this Track");vw.set(t,{startedAt:Date.now()});try{return await T4({...e,trackId:t,name:n,agent:r,skipPermissions:o,mode:s})}finally{vw.delete(t)}}async function T4({trackId:e,name:t,agent:n,skipPermissions:r,mode:o,fromNode:s=null,toNode:a=null,branch:i=null,repos:c=[],wip:l=null,brief:u=null,epochs:d=[],createdAt:p=null,leadBox:f=null,reason:w=null,downSince:m=null}){let g=await kc(n,r),b=await ee(),x=we(b,e);if(x&&!x.transferredTo)throw new Error(`track "${e}" is already hosted on this node`);x&&(await lw({id:x.id,cwd:x.cwd}).catch(()=>{}),await c_(x),b.tracks.splice(b.tracks.indexOf(x),1),await ae()),await Q.mkdir(dc,{recursive:!0});let y=re.join(dc,e);await Q.rm(y,{recursive:!0,force:!0}).catch(()=>{});let $=null,O=!1,M=[];try{let H=[];if(i)for(let W of Array.isArray(c)?c:[]){let te=typeof W=="string"?W:W?.repo;if(!te||!/^[^/\s]+\/[^/\s]+$/.test(te))continue;let ie=await ms(te)??await pl(te);await ln(ie,["fetch","origin",`+refs/heads/${i}:refs/heads/${i}`],Iw),H.push({slug:te,base:ie,name:typeof W=="object"?W?.name??null:null})}if(i&&H.length===1){let{base:W,slug:te}=H[0];await qE(W,y,i),M.push({base:W,dir:y}),await hc(y);let ie=await qs(W);$={dir:y,base:W,branch:i,kind:"worktree",baseRef:ie,repo:te}}else if(i&&H.length>=2){await Q.mkdir(y,{recursive:!0});let W=new Set([".bostrat"]),te=[];for(let ie of H){let J=ie.name||re.basename(ie.base);W.has(J)&&(J=ie.slug.replace("/","-"));for(let Me=2;W.has(J);Me++)J=`${re.basename(ie.base)}-${Me}`;W.add(J);let ge=re.join(y,J);await qE(ie.base,ge,i),M.push({base:ie.base,dir:ge});let Oe=await qs(ie.base);te.push({name:J,dir:ge,base:ie.base,baseRef:Oe,repo:ie.slug})}await Tc(y,te,i),$={dir:y,kind:"multi",branch:i,repos:te}}else O=!0,await Q.mkdir(y,{recursive:!0}),await xm(y),await hc(y),$={dir:y,base:null,branch:null,kind:"repo"};let P=!1,E=null,R=null;if(l?.sha&&$.kind==="worktree")try{await ln(y,["fetch","origin",iw(e)],Iw);let{stdout:W}=await ln(y,["rev-parse","FETCH_HEAD^"]),{stdout:te}=await ln(y,["rev-parse","HEAD"]),ie=W.trim()===te.trim();ie||await ln(y,["merge-base","--is-ancestor",te.trim(),W.trim()]).then(()=>!0,()=>!1)&&(await ln(y,["reset","--hard",W.trim()]),R={from:te.trim(),to:W.trim()},ie=!0),ie?(await ln(y,["read-tree","--reset","-u","FETCH_HEAD"]),await ln(y,["reset","-q"]),P=!0):E="snapshot does not parent the fetched branch head"}catch(W){E=String(W?.message||W).split(`
246
+ `)[0]}else l?.sha&&(E="wip snapshots cover single-repo worktrees only");await OE({id:e,cwd:y}).catch(()=>({restored:!1}));let G=re.join(y,zo),V=null;(await Al(y)).restored?V="checkpoint":typeof u=="string"&&u.trim()&&(await Q.mkdir(re.dirname(G),{recursive:!0}),await Q.writeFile(G,u),V="brief");let _=new Set(b.tracks.flatMap(W=>(W.boxes||[]).map(te=>te.name))),N=null;f&&!_.has(f)&&!await ke(f).catch(()=>null)?N=f:(N=`${t.trim()} lead`,_.has(Ml(N))&&(N=`${t.trim().slice(0,50).trim()} ${e} lead`));let U=await _r(N,y,{agentCmd:g,agent:n});mi({cwd:U.cwd,sessionName:U.name,agent:n,agentCmd:g});let z=Date.now(),ue=ng(U,"lead","live"),pe=(Array.isArray(d)?d:[]).filter(W=>W&&typeof W=="object").map(W=>({...W})),Se=pe[pe.length-1];Se&&Se.endedAt==null&&(Se.endedAt=z,Se.endReason==null&&(Se.endReason=o==="recover"?"node-offline":"node-transfer")),pe.push({agent:n,sessionId:U.sessionId??null,pinned:U.pinned===!0,startedAt:z,endedAt:null}),ue.epochs=pe;let Ae={id:e,name:t.trim(),cwd:U.cwd,workspace:$,leadBox:U.name,boxes:[ue],events:[],createdAt:Number.isFinite(p)?p:z,...V?{pendingHandoffHydrate:{artifact:zo,at:z}}:{}};return Ie(Ae,"transferred-in",{box:U.name,agent:n,fromNode:s,toNode:a,mode:o,reason:w,...o==="recover"?{downSince:Number.isFinite(m)?m:null}:{},branch:$.branch??null,wip:P,...R?{wipAdvanced:R}:{},epoch:pe.length-1,name:Ae.name,cwd:Ae.cwd,workspace:{base:$.base??null,branch:$.branch??null,kind:$.kind,...$.baseRef?{baseRef:$.baseRef}:{},...$.repo?{repo:$.repo}:{},...$.repos?{repos:$.repos.map(({name:W,base:te,baseRef:ie,repo:J})=>({name:W,base:te,baseRef:ie,repo:J}))}:{}}}),b.tracks.push(Ae),await ae(),{...await Nt(Ae),adopt:{wipApplied:P,wipSkipped:E,...R?{wipAdvanced:R}:{},codeless:O,artifactSource:V}}}catch(H){for(let P of M)await Ot(P.base,P.dir).catch(()=>{});throw await Q.rm(y,{recursive:!0,force:!0}).catch(()=>{}),H}}async function p_(e,t,n){let r=await ee(),o=we(r,e);o&&(o.subtasks=o.subtasks||{},o.subtasks[t]={...o.subtasks[t]||{},...n},await ae())}async function pa(e,t){e.step=t,await Ec(e)}function f_(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 m_(e){return!!e&&!e.finishedAt&&!e.canceled&&e.step==="working"&&!!e.box&&!!e.dir&&!!e.base&&!!e.branch}async function I4(e,t,n){if(!m_(n)||Pt.has(t)||!await ke(n.box).catch(()=>null))return!1;try{await Q.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 Pt.set(t,s),w_(s,o).catch(a=>h_(s,a)),!0}async function lg(){let e=await ee(),t=!1;for(let n of e.tracks||[]){for(let[r,o]of Object.entries(n.subtasks||{})){if(Pt.has(r))continue;if(await I4(n,r,o)){t=!0,Ie(n,"subtask-resumed",{box:o.box,agent:o.agent,task:o.task,subtaskId:r,resumedStep:o.step}),await le({flow:"subtask",phase:"resumed",trackId:n.id,subtaskId:r,box:o.box,branch:o.branch}).catch(()=>{});continue}let s=o.step,a=f_(o);if(!a)continue;t=!0,n.subtasks[r]=a;let i=n.boxes.find(c=>c.subtaskId===r);i&&!eo.has(i.state)&&(i.state="canceled"),Ie(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 le({flow:"subtask",phase:"reconciled",trackId:n.id,subtaskId:r,outcome:a.step,recovered:a.recovered,box:o.box,branch:o.branch}).catch(()=>{}),await KE(n,o.box,o.dir)}for(let r of n.boxes){if(r.role!=="subtask"||eo.has(r.state)||Pt.has(r.subtaskId)||n.subtasks?.[r.subtaskId])continue;t=!0,r.state="canceled";let o=r.subtaskId?re.join(ba,`${n.id}-${r.subtaskId}`):null;await le({flow:"subtask",phase:"reaped-legacy-orphan",trackId:n.id,subtaskId:r.subtaskId,box:r.name}).catch(()=>{}),await KE(n,r.name,o)}}return t=await $4(e)||t,t&&await ae(),t}async function KE(e,t,n){if(t&&await en(t).catch(()=>{}),!n)return;if(e.workspace?.kind==="multi"){for(let o of Bt(e.workspace)){let s=re.join(n,o.name);await Ot(o.base,s).then(()=>!0,()=>!1)||await Ot(o.dir,s).catch(()=>{})}await Q.rm(n,{recursive:!0,force:!0}).catch(()=>{});return}let r=await ke(e.leadBox).catch(()=>null);r?.cwd&&await Ot(r.cwd,n).catch(()=>{})}async function $4(e){let t;try{t=await Q.readdir(ba)}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 Pt.values())o.dir&&n.add(re.basename(o.dir));let r=!1;for(let o of t){if(n.has(o))continue;let s=re.join(ba,o),a=(e.tracks||[]).find(i=>o.startsWith(`${i.id}-`));if(a?.workspace?.kind==="multi"){for(let i of Bt(a.workspace))await Ot(i.base,re.join(s,i.name)).catch(()=>{});await Q.rm(s,{recursive:!0,force:!0}).catch(()=>{})}else{let i=a?await ke(a.leadBox).catch(()=>null):null;i?.cwd?await Ot(i.cwd,s).catch(()=>{}):await Q.rm(s,{recursive:!0,force:!0}).catch(()=>{})}await le({flow:"subtask",phase:"swept-orphan-worktree",dir:s}).catch(()=>{}),r=!0}return r}async function dg(e,{agent:t,task:n,skipPermissions:r=!0,reason:o=null}={}){if(typeof n!="string"||!Fs(n))throw new Error("task (string) required");let s=await kc(t,r),a=Co(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=we(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 Us(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 Us(c.cwd))throw new Error(`subtask delegation needs the lead's workspace to be a git repo (got ${c.cwd})`);let d=wd().slice(0,8),p={id:d,trackId:e,trackName:i.name,agent:t,task:Fs(n),skipPermissions:r,reason:YE(o),step:"snapshot",leadBox:i.leadBox,box:null,branch:`bostrat/${ug(i.name)}-${d}`,base:null,repos:u,dir:re.join(ba,`${e}-${d}`),stat:null,conflicts:[],applied:null,startedAt:Date.now(),finishedAt:null,error:null,canceled:!1,forceMerge:!1};return Pt.set(d,p),await Ec(p),R4(p,c,s).catch(f=>h_(p,f)),p}async function h_(e,t){e.failedStep=e.step,e.error=t instanceof yc?"canceled":t?.message||String(t),e.step=t instanceof yc?"canceled":"error",e.finishedAt=Date.now(),await fg(e).catch(()=>{}),await Ec(e).catch(()=>{}),await N4(e).catch(()=>{})}function Rd(e){let t=Pt.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 pg(e){let t=Pt.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 R4(e,t,n){if(await pa(e,"snapshot"),e.repos){for(let s of e.repos)s.base=await Hs(s.leadDir,`bostrat: snapshot for subtask ${e.id}`);await Ec(e)}else e.base=await Hs(t.cwd,`bostrat: snapshot for subtask ${e.id}`);if(await pa(e,"spawn"),await Q.mkdir(ba,{recursive:!0}),e.repos){await Q.mkdir(e.dir,{recursive:!0});for(let a of e.repos)await Ws(a.leadDir,re.join(e.dir,a.name),e.branch,a.base);let s=Bt((we(await ee(),e.trackId)||{}).workspace);await Tc(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 Ws(t.cwd,e.dir,e.branch,e.base),await hc(e.dir);await O4(e,t);let r=e.trackName.slice(0,38).trim(),o=await _r(`${r} ${e.agent} sub ${e.id}`,e.dir,{agentCmd:n,agent:e.agent});e.box=o.name,await C4(e,o),await XE(e.trackId,o.name,_U(e.task,!!e.repos),{kind:"subtask"}),await w_(e,t)}async function w_(e,t){await pa(e,"working");let n=re.join(e.dir,md);if(await D4(n,e),e.canceled)throw new yc;if(await pa(e,"merge"),e.repos){let s={files:0,insertions:0,deletions:0},a=[],i=[],c=!0;for(let l of e.repos){let u=re.join(e.dir,l.name);await km(u,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:WE({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),l.stat=await Sm(l.leadDir,l.base,e.branch,da),l.files=await Tm(l.leadDir,l.base,e.branch,da);let d=await Am(l.leadDir,l.base,e.branch,da);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=>re.join(l.name,p))),i.push(...l.conflicts.map(p=>p.startsWith("patch did not apply cleanly")?`${l.name}: ${p}`:re.join(l.name,p))),d.applied||(c=!1)}e.stat=s,e.files=a,e.conflicts=i,e.applied=c}else{await km(e.dir,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:WE({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),e.stat=await Sm(t.cwd,e.base,e.branch,da),e.files=await Tm(t.cwd,e.base,e.branch,da);let s=await Am(t.cwd,e.base,e.branch,da);e.applied=s.applied,e.conflicts=s.conflicts}await Ec(e);let r=await P4(e,t,n);await pa(e,"resume"),await XE(e.trackId,e.leadBox,IU(e.task,e.stat,e.conflicts,r),{kind:"subtask-resume"}),await pa(e,"reap"),await fg(e),e.step="done";let o=Date.now();await p_(e.trackId,e.id,{...$d(e),finishedAt:o}),await M4(e,o),e.finishedAt=o}async function O4(e,t){let n=re.join(e.dir,re.dirname(pc));await Q.mkdir(n,{recursive:!0});let r="";try{r=await jk(t.cwd,t.sessionId)}catch{}if(!r)try{r=await Q.readFile(re.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}
247
247
 
248
248
  **Delegated task:** ${e.task}
249
249
 
@@ -254,15 +254,15 @@ ${a}`}async function Yw(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<
254
254
  ## Conversation so far (lead \u2192 you)
255
255
 
256
256
  ${r}
257
- `;await Q.writeFile(re.join(e.dir,pc),o)}async function O4(e,t){let n=await ee(),r=we(n,e.trackId);r&&(r.boxes.push({name:t.name,agent:t.agent,role:"subtask",state:"live",cwd:t.cwd,sessionId:t.sessionId,hookTokenHash:La(t.hookToken),createdAt:Date.now(),subtaskId:e.id,branch:e.branch,task:e.task}),Ie(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]||{},...Id(e)},await ae())}async function C4(e,t=e.finishedAt){let n=await ee(),r=we(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),Ie(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 M4(e){let t=await ee(),n=we(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"),Ie(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]||{},...Id(e)},await ae()}async function N4(e,t,n){let r=`.bostrat/handoff/subtask-${e.id}.md`;try{let o=re.join(t.cwd,r);await Q.mkdir(re.dirname(o),{recursive:!0}),await Q.copyFile(n,o)}catch{}return r}async function pg(e){if(e.dir&&await Hp(e.dir).catch(()=>{}),e.box&&await en(e.box).catch(()=>{}),e.repos&&e.dir){for(let t of e.repos)await Ot(t.leadDir,re.join(e.dir,t.name)).catch(()=>{});await Q.rm(e.dir,{recursive:!0,force:!0}).catch(()=>{})}else if(e.dir){let n=(await ke(e.leadBox).catch(()=>null))?.cwd;n&&await Ot(n,e.dir).catch(()=>{})}}async function P4(e,t){let n=(t.startedAt||Date.now())+T4;for(;;){if(t.canceled||t.forceMerge)return;try{await Q.access(e);return}catch{}if(Date.now()>n)throw new Error("subtask timed out without signaling completion (no result digest written)");await Jo(A4)}}function Jo(e){return new Promise(t=>setTimeout(t,e))}var KE,jn,GE,SU,dc,TU,wd,bc,Qr,zo,zE,AU,fd,pc,EU,_U,Vt,mw,we,hw,Ie,ww,gw,RU,eo,LE,MU,NU,PU,DU,LU,ha,FE,qU,KU,GU,zU,VU,fa,fc,ZU,e4,t4,o4,o_,mc,s_,c4,uc,yw,l4,bw,f4,wc,m4,h4,UE,kw,Ew,tg,ya,xa,_w,ln,Iw,rg,x4,xw,T4,A4,ba,da,Pt,E4,Zo,Id,Ec,lg,yc,or=q(()=>{Va();ct();Gf();gx();hi();vr();Fl();vx();pt();kn();ds();Ll();am();vo();mm();wm();sv();yi();Rf();Ul();Lf();nn();uu();kr();An();wi();hu();Cv();Om();qT();Ql();Xl();GT();Th();de();_h();Uu();ed();Fi();Mo();rd();ca();Zh();ld();sw();Zn();zu();AE();lw();OE();El();PE();jE();fw();KE=vU(xU),jn=process.env.BOSTRAT_STATE_DIR||re.join(process.env.HOME||"/tmp",".bostrat"),GE=re.join(jn,"tracks.json"),SU=re.join(jn,"events.jsonl"),dc=re.join(jn,"workspaces"),TU=process.env.BOSTRAT_DEFAULT_REPO||null,wd={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"}},bc=Object.keys(wd);Qr={at:0,value:null};zo=".bostrat/handoff/latest.md",zE=Number(process.env.BOSTRAT_HANDOFF_CHECKPOINT_TIMEOUT_MS)||9e4;AU=/\(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\.\)$/;fd=".bostrat/handoff/subtask-result.md",pc=".bostrat/handoff/lead-context.md",EU=(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 ${pc} \u2014 read that first for context. Your scoped task:
257
+ `;await Q.writeFile(re.join(e.dir,pc),o)}async function C4(e,t){let n=await ee(),r=we(n,e.trackId);r&&(r.boxes.push({name:t.name,agent:t.agent,role:"subtask",state:"live",cwd:t.cwd,sessionId:t.sessionId,hookTokenHash:La(t.hookToken),createdAt:Date.now(),subtaskId:e.id,branch:e.branch,task:e.task}),Ie(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]||{},...$d(e)},await ae())}async function M4(e,t=e.finishedAt){let n=await ee(),r=we(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),Ie(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 N4(e){let t=await ee(),n=we(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"),Ie(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]||{},...$d(e)},await ae()}async function P4(e,t,n){let r=`.bostrat/handoff/subtask-${e.id}.md`;try{let o=re.join(t.cwd,r);await Q.mkdir(re.dirname(o),{recursive:!0}),await Q.copyFile(n,o)}catch{}return r}async function fg(e){if(e.dir&&await Wp(e.dir).catch(()=>{}),e.box&&await en(e.box).catch(()=>{}),e.repos&&e.dir){for(let t of e.repos)await Ot(t.leadDir,re.join(e.dir,t.name)).catch(()=>{});await Q.rm(e.dir,{recursive:!0,force:!0}).catch(()=>{})}else if(e.dir){let n=(await ke(e.leadBox).catch(()=>null))?.cwd;n&&await Ot(n,e.dir).catch(()=>{})}}async function D4(e,t){let n=(t.startedAt||Date.now())+A4;for(;;){if(t.canceled||t.forceMerge)return;try{await Q.access(e);return}catch{}if(Date.now()>n)throw new Error("subtask timed out without signaling completion (no result digest written)");await Jo(E4)}}function Jo(e){return new Promise(t=>setTimeout(t,e))}var GE,Bn,zE,TU,dc,AU,gd,bc,Qr,zo,VE,EU,md,pc,_U,IU,Vt,hw,we,ww,Ie,gw,yw,OU,eo,FE,NU,PU,DU,BU,FU,ha,UE,KU,GU,zU,VU,JU,fa,fc,QU,t4,n4,s4,s_,mc,a_,l4,uc,bw,u4,kw,m4,wc,h4,w4,HE,xw,_w,ng,ya,xa,Iw,ln,$w,og,v4,vw,A4,E4,ba,da,Pt,_4,Zo,$d,Ec,ug,yc,or=q(()=>{Va();ct();zf();gx();hi();vr();Fl();vx();pt();kn();ds();Ll();im();vo();hm();gm();sv();yi();Of();Ul();Ff();nn();uu();kr();An();wi();hu();Cv();Cm();KT();Ql();Xl();zT();Ah();de();Ih();Hu();td();Fi();Mo();od();ca();Qh();ud();aw();Zn();Vu();EE();uw();CE();El();DE();jE();mw();GE=SU(vU),Bn=process.env.BOSTRAT_STATE_DIR||re.join(process.env.HOME||"/tmp",".bostrat"),zE=re.join(Bn,"tracks.json"),TU=re.join(Bn,"events.jsonl"),dc=re.join(Bn,"workspaces"),AU=process.env.BOSTRAT_DEFAULT_REPO||null,gd={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"}},bc=Object.keys(gd);Qr={at:0,value:null};zo=".bostrat/handoff/latest.md",VE=Number(process.env.BOSTRAT_HANDOFF_CHECKPOINT_TIMEOUT_MS)||9e4;EU=/\(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\.\)$/;md=".bostrat/handoff/subtask-result.md",pc=".bostrat/handoff/lead-context.md",_U=(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 ${pc} \u2014 read that first for context. Your scoped task:
258
258
 
259
259
  ${e}
260
260
 
261
- 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 ${fd} (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 ${pc} \u2014 read that first for context. Your scoped task:
261
+ 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 ${md} (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 ${pc} \u2014 read that first for context. Your scoped task:
262
262
 
263
263
  ${e}
264
264
 
265
- 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 ${fd} 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.`,_U=(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."),Vt=null,mw=null;we=(e,t)=>e.tracks.find(n=>n.id===t)||null,hw=Promise.resolve();Ie=(e,t,n={})=>{let r={at:Date.now(),type:t,...n};return e.events.push(r),IU(e.id,r),Pv(e,r),r};Hk(async({sessionName:e,from:t,to:n,version:r,status:o,error:s})=>{let i=(await ee()).tracks.find(c=>c.leadBox===e||(c.boxes||[]).some(l=>l.name===e));i&&(Ie(i,"codex-update",{box:e,from:t,to:r||n,status:o,...s?{error:s}:{}}),await ae().catch(()=>{}))});ww=re.join(jn,"plane-link","update-notice.json");gw=(e,t,n)=>t!=null&&n.some(r=>e===r.box&&t>=r.from&&t<=r.to),RU=new Set(["stuck","wrong-approach","too-slow","want-different-model","context-refresh","cost","parallelize","other"]);eo=new Set(["merged","conflict","canceled","failed","handed-off"]),LE=new Map;MU=5e3;NU={claude:[/^\[Request interrupted by user(?: for tool use)?\]$/i],codex:[/^\[?Request interrupted/i,/^Conversation interrupted/i],cursor:[/^\[?Request interrupted/i]};PU=[/^\/model(?:\s|$)/i,/<command-(?:name|message|args)>[^<]*\bmodel\b/i,/^Model changed to\b/i];DU=10*6e4;LU=1500,ha=new Map;FE="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.";qU=4e3,KU=3,GU=[300,350,400],zU=1e3,VU=12,fa=new Map,fc=new Map;ZU=[250,400,500,600];e4=3e4,t4=[350,650,900];o4=12e4;o_=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}))});mc="# bostrat workspace",s_=`${mc}
265
+ 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 ${md} 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.`,IU=(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."),Vt=null,hw=null;we=(e,t)=>e.tracks.find(n=>n.id===t)||null,ww=Promise.resolve();Ie=(e,t,n={})=>{let r={at:Date.now(),type:t,...n};return e.events.push(r),$U(e.id,r),Pv(e,r),r};Hk(async({sessionName:e,from:t,to:n,version:r,status:o,error:s})=>{let i=(await ee()).tracks.find(c=>c.leadBox===e||(c.boxes||[]).some(l=>l.name===e));i&&(Ie(i,"codex-update",{box:e,from:t,to:r||n,status:o,...s?{error:s}:{}}),await ae().catch(()=>{}))});gw=re.join(Bn,"plane-link","update-notice.json");yw=(e,t,n)=>t!=null&&n.some(r=>e===r.box&&t>=r.from&&t<=r.to),OU=new Set(["stuck","wrong-approach","too-slow","want-different-model","context-refresh","cost","parallelize","other"]);eo=new Set(["merged","conflict","canceled","failed","handed-off"]),FE=new Map;NU=5e3;PU={claude:[/^\[Request interrupted by user(?: for tool use)?\]$/i],codex:[/^\[?Request interrupted/i,/^Conversation interrupted/i],cursor:[/^\[?Request interrupted/i]};DU=[/^\/model(?:\s|$)/i,/<command-(?:name|message|args)>[^<]*\bmodel\b/i,/^Model changed to\b/i];BU=10*6e4;FU=1500,ha=new Map;UE="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.";KU=4e3,GU=3,zU=[300,350,400],VU=1e3,JU=12,fa=new Map,fc=new Map;QU=[250,400,500,600];t4=3e4,n4=[350,650,900];s4=12e4;s_=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}))});mc="# bostrat workspace",a_=`${mc}
266
266
 
267
267
  TRACK MEMORY: if \`.bostrat/memory/MEMORY.md\` exists in your workspace, read it
268
268
  before substantive work \u2014 it is the shared cross-provider memory for this repo
@@ -640,16 +640,16 @@ for the same follow-up at the same moment twice; run bostrat-followup ls first
640
640
  specifics (no PR numbers, URLs, SHAs, tags \u2014 the card supplies them), and HOLD
641
641
  HERE after proposing until the operator answers the card. Bostrat never runs a
642
642
  follow-up on its own; the operator's tap is the gate.
643
- `,c4=s_,uc=s_+$0;yw=e=>typeof e=="string"&&(e===mc||e.startsWith(`${mc}
644
- `)),l4="# bostrat multi-repo workspace";bw=uc.replace(`${mc}
643
+ `,l4=a_,uc=a_+$0;bw=e=>typeof e=="string"&&(e===mc||e.startsWith(`${mc}
644
+ `)),u4="# bostrat multi-repo workspace";kw=uc.replace(`${mc}
645
645
  `,`${mc}
646
646
 
647
647
  (Global copy managed by bostrat \u2014 rewritten on service start; edits will be lost.)
648
648
  SCOPE: these instructions apply ONLY when your working directory is under
649
649
  ~/.bostrat/workspaces/ or ~/.bostrat/worktrees/ \u2014 a bostrat-orchestrated box.
650
650
  When working anywhere else, ignore everything below.
651
- `);f4=new Set(["claude","codex","cursor"]);wc=new Set,m4=e=>wc.has(e);h4=9e4;UE={merged:"merged",closed:"closed on GitHub WITHOUT merging",lost:"no longer found on GitHub (deleted, or its repo left the grant)"};kw=new Map;Ew=120;tg=(e,t,n)=>({name:e.name,agent:e.agent,role:t,state:n,cwd:e.cwd,sessionId:e.sessionId,pinned:e.pinned===!0,hookTokenHash:La(e.hookToken),createdAt:Date.now()});ya=new Map,xa=e=>ya.get(e)||(Vt?we(Vt,e)?.handoff:null)||null;_w=6e4,ln=(e,t,n=15e3)=>KE("git",["-C",e,...t],{timeout:n,maxBuffer:8*1024*1024}),Iw=new Map,rg=e=>Iw.get(e)||null;x4=/^[A-Za-z0-9][A-Za-z0-9._/-]{0,200}$/;xw=new Map;T4=Number(process.env.BOSTRAT_SUBTASK_TIMEOUT_MS)||18e5,A4=Number(process.env.BOSTRAT_SUBTASK_POLL_MS)||3e3,ba=re.join(jn,"worktrees"),da=[pc,fd],Pt=new Map,E4=e=>Pt.get(e)||(Vt?Vt.tracks.map(t=>t.subtasks?.[e]).find(Boolean):null)||null,Zo=e=>{let t=new Map([...Pt.values()].filter(r=>r.trackId===e).map(r=>[r.id,r])),n=Vt?we(Vt,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)},Id=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});Ec=e=>d_(e.trackId,e.id,Id(e));lg=e=>e.trim().replace(/\s+/g,"-").replace(/[^A-Za-z0-9._-]/g,"").toLowerCase()||"track",yc=class extends Error{}});ct();import Te from"node:path";import wt from"node:fs";import EK from"node:readline";import{fileURLToPath as _K}from"node:url";import Ut from"express";import IK from"node:http";import $K from"node:https";import gp from"node:os";import{randomUUID as RK}from"node:crypto";import{WebSocketServer as OK}from"ws";ct();import BM from"node-pty";async function wk(e,t,n={}){if(!Be(t)){jl(e,`invalid session name: ${t}`),e.close(1008,"invalid session name");return}if(!await Er()){jl(e,`host tmux server not running on ${Rt}`),e.close(1011,"tmux server unavailable");return}if(!await ke(t)){jl(e,`session "${t}" not found`),e.close(1008,"session not found");return}let r=hk(n.cols,120,gk),o=hk(n.rows,32,yk),s;try{s=BM.spawn(X,["-S",Rt,"attach-session","-d","-t",t],{name:"xterm-256color",cols:r,rows:o,cwd:process.env.HOME||"/",env:{...process.env,TERM:"xterm-256color"}})}catch(a){jl(e,`failed to spawn tmux attach: ${a.message}`),e.close(1011,"spawn failed");return}s.onData(a=>{e.readyState===e.OPEN&&nf(e,{type:"data",data:a})}),s.onExit(({exitCode:a,signal:i})=>{e.readyState===e.OPEN&&(nf(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"&&HM(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{}UM(t)})}var LM=6,FM=250;async function UM(e,t=LM,n=FM){for(let r=0;r<t;r++){if(await bo(e).catch(()=>!0))return!0;await new Promise(o=>setTimeout(o,n))}return!1}var gk=20,yk=6;function HM(e,t){return Number.isFinite(Number(e))&&Number.isFinite(Number(t))&&Number(e)>=gk&&Number(t)>=yk}function hk(e,t,n){let r=Number(e);return!Number.isFinite(r)||r<n?t:Math.min(500,r|0)}function nf(e,t){try{e.send(JSON.stringify(t))}catch{}}function jl(e,t){nf(e,{type:"error",message:t})}function bk(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}}nn();Ll();Gf();or();import{createRequire as CK}from"node:module";var D4=e=>!!e&&!e.finishedAt&&!e.canceled&&!e.error;function fg({tracks:e=[],views:t=[],queuedOf:n=()=>[],jobsOf:r=()=>[]}={}){let o=[];for(let s of e)!s||s.archivedAt&&!s.archiving||s.transferredTo||(s.working&&o.push(`working:${s.id}`),s.prompted&&o.push(`prompted:${s.id}`),(n(s.id)??[]).length&&o.push(`queued:${s.id}`),(s.boxes||[]).some(a=>a?.role==="subtask"&&a?.state==="live")&&o.push(`subtask:${s.id}`),(r(s.id)??[]).length&&o.push(`job:${s.id}`),Object.values(s.subtasks||{}).some(D4)&&o.push(`merge-back:${s.id}`));return t.some(s=>s?.state==="live"||s?.state==="starting")&&o.push("views"),{busy:o.length>0,reasons:o}}de();am();ct();import F4 from"node:fs/promises";import mg from"node:fs/promises";var j4=100;async function B4(e){let t;try{t=await mg.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/j4*1e3,ioBytes:await L4(e)}}async function L4(e){let t;try{t=await mg.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 g_(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 mg.readdir("/proc")}catch{return null}let r=new Map;await Promise.all(n.map(async l=>{if(!/^\d+$/.test(l))return;let u=await B4(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 U4=Number(process.env.BOSTRAT_JOB_CHECK_MS)||15*6e4,H4=Number(process.env.BOSTRAT_JOB_STALL_CHECKS)||3,W4=Number(process.env.BOSTRAT_JOB_CPU_RATE_MIN)||25,q4=Number(process.env.BOSTRAT_JOB_IO_RATE_MIN)||64*1024,K4=5*6e4,b_={readOpenJobs:Hx,statFile:async e=>{try{let t=await F4.stat(e);return{size:t.size,mtimeMs:Math.round(t.mtimeMs)}}catch{return null}},updatedAt:e=>jr(e.agent).updatedAt(e),panePids:pk,treeStats:g_,appendEvent:C},un=new Map,y_=new Map,hg=new Map,wg=(e,t,n)=>`${e}|${t}|${n}`;function k_(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 x_(e,t,n){let r=null;try{r=await n.updatedAt(e)}catch{r=null}let o=y_.get(e.name);if(o&&o.mtime===r&&t-o.at<K4)return o.jobs;let s=[];try{s=await n.readOpenJobs(e)}catch{s=[]}return y_.set(e.name,{at:t,mtime:r,jobs:s}),s}async function G4(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 z4(e,t){return e?.outputFile?await t.statFile(e.outputFile):null}function V4(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>=W4||t.ioBytes!=null&&e.ioBytes!=null&&(t.ioBytes-e.ioBytes)/n>=q4}function v_(e,t,n,r){let o=[];for(let s of n){let a=wg(e.id,t.name,s.id),i=un.get(a);i?i.job=s:un.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 S_(e,{now:t=Date.now(),deps:n=b_}={}){let r=new Map,o=new Set;for(let{track:s,box:a}of k_(e)){let i=await x_(a,t,n);for(let l of i)o.add(wg(s.id,a.name,l.id));let c=v_(s,a,i,t).filter(l=>!un.get(l).stalled).map(l=>un.get(l).job);c.length&&r.set(s.id,[...r.get(s.id)??[],...c])}for(let s of[...un.keys()])o.has(s)||un.delete(s);return r}async function J4(e,{now:t=Date.now(),deps:n=b_}={}){let r={checked:0,progressing:0,quiet:0,stalled:[]},o=k_(e),s=new Set(o.map(({box:a})=>a.name));for(let[a,i]of[...un])s.has(i.boxName)||un.delete(a);for(let{track:a,box:i}of o){let c=await x_(i,t,n),l=new Set(c.map(w=>wg(a.id,i.name,w.id)));for(let[w,m]of[...un])m.boxName===i.name&&!l.has(w)&&un.delete(w);if(!c.length){hg.delete(i.name);continue}let u=v_(a,i,c,t),d=await G4(i,t,n),p=hg.get(i.name);hg.set(i.name,d);let f=V4(p,d);for(let w of u){let m=un.get(w);r.checked++;let g=await z4(m.job,n),b=!!g&&!!m.file&&(g.size>m.file.size||g.mtimeMs>m.file.mtimeMs),x=!!g&&!m.file;if(m.file=g??m.file,f||b||x){m.quiet=0,m.lastProgressAt=t,m.stalled=!1,r.progressing++;continue}if(m.stalled||(m.quiet++,r.quiet++,m.quiet<H4))continue;m.stalled=!0,m.stalledAt=t,r.stalled.push(w);let $=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:$,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($/6e4)}m over ${m.quiet} check(s) \u2014 released; the node may sleep`)}}return r}function T_({listTracks:e,intervalMs:t=U4}={}){let n=!1,o=setInterval(async()=>{if(!n){n=!0;try{await J4(await e())}catch(s){console.error(`[job-watch] sweep: ${s?.message||s}`)}finally{n=!1}}},t);return o.unref?.(),o}import D_ from"node:fs";import no from"node:fs/promises";import p2 from"node:os";import dt from"node:path";import{spawn as f2}from"node:child_process";import{createRequire as m2}from"node:module";de();hu();import M_ from"node:fs";import Ic from"node:fs/promises";import Z4 from"node:http";import pn from"node:path";import Od from"node:os";import{createRequire as Q4}from"node:module";import yg from"ws";import Y4 from"node:path";import X4 from"node:os";var _c=process.env.BOSTRAT_STATE_DIR||Y4.join(process.env.HOME||X4.tmpdir(),".bostrat");function gg(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 A_(e=process.env){if(!e.BOSTRAT_PLANE_URL)return null;let t=gg(e);return t==="127.0.0.1"||t==="::1"||t==="localhost"?null:{host:t}}function E_(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}var dn=(()=>{try{return Q4(import.meta.url)("../package.json").version||null}catch{return null}})(),__=process.env.BOSTRAT_STATE_DIR||pn.join(process.env.HOME||Od.tmpdir(),".bostrat");function Qo({env:e=process.env,pkgDir:t=pn.resolve(pn.dirname(new URL(import.meta.url).pathname),".."),exists:n=M_.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(pn.join(t,"..",".git"))?"git-checkout":"dev"}function $c(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 Rd(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 e2({home:e=process.env.HOME||Od.homedir(),env:t=process.env}={}){let n=r=>{try{return M_.statSync(r),!0}catch{return!1}};return{claude:n(pn.join(e,".claude",".credentials.json")),codex:n(pn.join(t.CODEX_HOME||pn.join(e,".codex"),"auth.json"))}}var ut=1,I_=1e3,$_=3e4,t2=6e4,n2=1500,r2=500,to=100,o2=2e3,s2=25e3,a2=6e4,N_=(e,t)=>{let n=Number(e);return Number.isFinite(n)&&n>0?n:t},i2=N_(process.env.BOSTRAT_PLANE_DELIVERY_TIMEOUT_MS,18e4),c2=3e4,R_=10*6e4,l2=400,O_=250,u2=N_(process.env.BOSTRAT_PLANE_INGEST_TIMEOUT_MS,1e4),bg=4,d2=6e4,C_=6e4;function P_({url:e,token:t,nodeId:n=Od.hostname(),name:r=Od.hostname(),listTracks:o,detectAgents:s=null,onTracksTransferred:a=null,sampleMetrics:i=null,deliverySample:c=null,onHashKey:l=null,metricsMs:u=d2,onUpdateAvailable:d=null,onUpdatePolicy:p=null,onHelloRefused:f=null,updatePolicy:w=null,installKind:m=Qo(),selfUrl:g=`http://127.0.0.1:${process.env.PORT||3362}`,apiToken:b=null,onDegraded:x=null,onRecovered:y=null,onConnected:$=null,ingestMode:O=["ws","http","auto"].includes(process.env.BOSTRAT_PLANE_INGEST)?process.env.BOSTRAT_PLANE_INGEST:"auto",deliveryTimeoutMs:M=i2,unackedRetryMs:H=a2,pingMs:P=s2,maxInflightEvents:E=l2,httpTimeoutMs:R=u2,stallBackoffMinMs:G=c2,fetchImpl:V=globalThis.fetch,log:A=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=E_(e);let _=g.replace(/^http/,"ws"),N=new Set,U=new Map,z=new Map,ue=pn.join(__,"plane-link","cursor.json"),pe=pn.join(__,"plane-link","dead-letter.ndjson"),Se=e.replace(/^ws(s?):\/\//,"http$1://").replace(/\/v1\/node\/?$/,""),Ae={},W={},te=new Map,ie=null,J=null,ge=0,Oe=0,Me=0,I=Promise.resolve(),j="ws",fe=0,Pe=!1,Ce=0,wn=!1,gt=to,gr=new Set,gn=[],k=null,h=null,v=!1,D=!1,ce=I_,ye=null,De=null,St=null,qe=null,rt=null,kp=!1,sl=0;async function hO(){try{Ae=JSON.parse(await Ic.readFile(ue,"utf8"))}catch{Ae={}}}function wO(){kp=!0,!St&&(St=setTimeout(async()=>{if(St=null,!!kp){kp=!1;try{await Ic.mkdir(pn.dirname(ue),{recursive:!0}),await Ic.writeFile(ue,JSON.stringify(Ae))}catch(L){A.error("[plane-link] cursor flush failed:",L?.message||L)}}},o2),St.unref?.())}function it(L){return!h||h.readyState!==yg.OPEN?!1:(h.send(JSON.stringify(L)),!0)}function Da(L){let F=Date.now();for(let{trackId:T,event:B}of L){let Y=te.get(B.id);te.set(B.id,{trackId:T,seq:B.seq,event:B,sentAt:F,firstSentAt:Y?.firstSentAt??F,retryAt:F+H,tries:(Y?.tries??0)+1,nacks:Y?.nacks??0})}return j==="http"?(kO(L),!0):it({v:ut,ch:"events",type:"append",events:L})}function gO(L){let F=null;for(let T of te.values())T.trackId===L&&(F==null||T.seq<F)&&(F=T.seq);return F}function xp(L){let F=W[L];if(F==null)return;let T=gO(L),B=T==null?F:Math.min(F,T-1);B>(Ae[L]??0)&&(Ae[L]=B,wO())}function ja(){if(ie=Date.now(),J!=null){let L=Date.now()-J;A.log(`[plane-link] spine sync recovered after ${Math.round(L/1e3)}s degraded (${ge} stall redial(s))`);let F=J;J=null,ge=0,Oe=0,Pe=!1,Ce=0;try{y?.({since:F,downMs:L})}catch(T){A.error(`[plane-link] onRecovered failed: ${T?.message||T}`)}}}function vp(L){if(!Array.isArray(L)||!L.length)return;let F=new Set;for(let T of L){let B=te.get(T);B&&(te.delete(T),(W[B.trackId]??0)<B.seq&&(W[B.trackId]=B.seq),F.add(B.trackId))}for(let T of F)xp(T);ja()}function Wy(L,F){Me++;let T={at:Date.now(),trackId:L.trackId,seq:L.seq,id:L.event?.id??null,type:L.event?.type??null,reason:F,event:L.event??null};A.error(`[plane-link] DEAD-LETTER ${L.trackId} seq ${L.seq} (${T.type??"?"}): plane rejected it permanently (${F}) \u2014 kept in ${pe}`),I=I.then(async()=>{await Ic.mkdir(pn.dirname(pe),{recursive:!0}),await Ic.appendFile(pe,JSON.stringify(T)+`
652
- `)}).catch(B=>A.error(`[plane-link] dead-letter write failed: ${B?.message||B}`))}function qy(L,F,T,B=null){if(!Array.isArray(L)||!L.length)return;let Y=new Set,xe=Date.now();for(let Ee of L){let Ue=te.get(Ee);Ue&&(T?(te.delete(Ee),Wy(Ue,F),(W[Ue.trackId]??0)<Ue.seq&&(W[Ue.trackId]=Ue.seq),Y.add(Ue.trackId)):(Ue.nacks++,Ue.retryAt=xe+Math.max(1e3,Number(B)||H)))}for(let Ee of Y)xp(Ee);ja()}function Ky(L=Date.now()){let F=1/0;for(let T of te.values())T.firstSentAt<F&&(F=T.firstSentAt);return F===1/0?0:L-F}function Gy(){if(!v||!te.size)return;let L=Date.now(),F=Ky(L);if(F<M||ie!=null&&L-ie<M||j==="http"&&Pe||Oe>L)return;ge++;let T=Math.min(G*2**(ge-1),R_);if(J==null){J=L-F,A.error(`[plane-link] DEGRADED: no ack or nack for ${Math.round(F/1e3)}s with ${te.size} event(s) in flight (${j} door) \u2014 the plane is not answering appends`);try{x?.({since:J,unacked:te.size,oldestAgeMs:F,mode:j})}catch(B){A.error(`[plane-link] onDegraded failed: ${B?.message||B}`)}}if(j==="http"){Pe=!0,Ce=L+T,A.error(`[plane-link] ingest circuit OPEN (stall #${ge}); probing /v1/ingest/health in ${Math.round(T/1e3)}s`);return}Oe=L+T,A.error(`[plane-link] closing the link and redialing in ${Math.round(T/1e3)}s (stall redial #${ge})`);try{h?.terminate()}catch{}}function Sp(){if(!v)return;let L=Date.now();if(j==="http"&&Pe)return;let F=[...te.values()].filter(B=>B.event&&B.retryAt<=L&&!(j==="http"&&gr.has(B.trackId)));if(!F.length)return;F.sort((B,Y)=>B.trackId===Y.trackId?B.seq-Y.seq:B.trackId<Y.trackId?-1:1),A.log(`[plane-link] re-sending ${F.length} unacked event(s) the plane never confirmed`);let T=j==="http"?gt:to;if(j==="http"){let B=new Map;for(let Y of F)(B.get(Y.trackId)??B.set(Y.trackId,[]).get(Y.trackId)).push(Y);for(let[,Y]of B){if(fe>=bg)return;Da(Y.slice(0,T).map(xe=>({trackId:xe.trackId,event:xe.event})))}return}for(let B=0;B<F.length;B+=T){let Y=F.slice(B,B+T).map(xe=>({trackId:xe.trackId,event:xe.event}));if(!Da(Y))return}}async function yO(L=null){for(;;){if(!v)return!1;let F=te.size<E,T=j!=="http"||fe<bg&&!Pe&&(!L||!gr.has(L));if(F&&T)return!0;await new Promise(B=>setTimeout(B,100))}}function Tp(){if(k=null,!v||!gn.length)return;let L=gn;if(gn=[],j!=="http"){for(let T=0;T<L.length;T+=to)Da(L.slice(T,T+to));return}let F=new Map;for(let T of L)(F.get(T.trackId)??F.set(T.trackId,[]).get(T.trackId)).push(T);for(let[T,B]of F){if(gr.has(T)||fe>=bg||Pe){gn.push(...B);continue}for(let Y=0;Y<B.length;Y+=gt)Da(B.slice(Y,Y+gt))}gn.length&&!k&&(k=setTimeout(Tp,O_),k.unref?.())}let bO=L=>{let F=new Map;for(let{trackId:T,event:B}of L)(F.get(T)??F.set(T,[]).get(T)).push(B);return[...F].map(([T,B])=>({trackId:T,events:B}))},us=(L,F,T,{progress:B})=>{let Y=Date.now();for(let{event:xe}of L){let Ee=te.get(xe.id);Ee&&(Ee.nacks++,Ee.retryAt=Y+Math.max(1e3,T||H))}B&&ja()};async function kO(L){let F=new Set(L.map(T=>T.trackId));for(let T of F)gr.add(T);fe++;try{let T=await V(`${Se}/v1/ingest`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/json"},body:JSON.stringify({node:n,batches:bO(L)}),signal:AbortSignal.timeout(R)}),B=(Number(T.headers.get("retry-after"))||0)*1e3;if(T.status===200){let Y=await T.json();gt=to;for(let xe of Y.results??[]){vp(xe.acked??[]);let Ee=(Ue,Tt)=>{let Ht=new Map;for(let Qe of Ue??[])(Ht.get(Qe.reason)??Ht.set(Qe.reason,[]).get(Qe.reason)).push(Qe.id);for(let[Qe,Xy]of Ht)qy(Xy,Qe,Tt,Y.retryAfterMs??null)};Ee(xe.rejected,!0),Ee(xe.deferred,!1)}vp(Y.discarded??[]),ja();return}if(T.status===429){us(L,"overloaded",B||5e3,{progress:!0});return}if(T.status===413&&L.length>1){gt=Math.max(1,Math.floor(L.length/2)),A.error(`[plane-link] ingest request too large (${L.length} events) \u2014 halving batches to ${gt}`),us(L,"too_large",1e3,{progress:!0});return}if(T.status===413){let Y=te.get(L[0].event.id);Y&&(te.delete(Y.event.id),Wy(Y,"too_large"),(W[Y.trackId]??0)<Y.seq&&(W[Y.trackId]=Y.seq),xp(Y.trackId)),ja();return}if(T.status===401||T.status===403){if(Date.now()-sl>=C_){sl=Date.now();let Y="";try{Y=(await T.json())?.error??""}catch{}A.error(`[plane-link] plane refused ingest (HTTP ${T.status}${Y?`: ${Y}`:""}) \u2014 events are held locally and retried; check this node's token/binding`)}us(L,`http_${T.status}`,6e4,{progress:!1});return}if(T.status===400){A.error(`[plane-link] plane rejected an ingest request as malformed (400) \u2014 holding ${L.length} event(s) for retry; this is a bug, not data`),us(L,"http_400",6e4,{progress:!1});return}us(L,`http_${T.status}`,B||5e3,{progress:!1})}catch(T){let B=T?.name==="TimeoutError"||T?.name==="AbortError";B&&L.length>1&&(gt=Math.max(1,Math.floor(L.length/2)),A.error(`[plane-link] ingest request of ${L.length} event(s) outlived its ${R} ms deadline \u2014 halving batches to ${gt}`)),us(L,B?"timeout":"network",5e3,{progress:!1})}finally{fe--;for(let T of F)gr.delete(T)}}async function xO(){if(j!=="http"||!Pe||!v||wn)return;let L=Date.now();if(!(Ce>L)){wn=!0;try{let F=await V(`${Se}/v1/ingest/health`,{headers:{authorization:`Bearer ${t}`},signal:AbortSignal.timeout(R)});if(!F.ok)throw new Error(`HTTP ${F.status}`);A.log("[plane-link] ingest door answering \u2014 closing the circuit and re-sending"),Pe=!1,Ce=0,Oe=Date.now()+R+H+1e3;for(let T of te.values())T.retryAt=Math.min(T.retryAt,Date.now());Sp()}catch(F){ge++;let T=Math.min(G*2**(ge-1),R_);Ce=Date.now()+T,A.error(`[plane-link] ingest door still not answering (${F?.message||F}); next probe in ${Math.round(T/1e3)}s`)}finally{wn=!1}}}function zy(){let L=Date.now();return{mode:j,unacked:te.size,oldestUnackedAgeMs:Ky(L),lastProgressAt:ie,degradedSince:J,stallRedials:ge,deadLettered:Me,http:j==="http"?{inFlight:fe,circuitOpen:Pe,nextProbeInMs:Pe?Math.max(0,Ce-L):0,batchCap:gt}:null}}async function Vy(){if(!i)return;let L;try{L=await i()}catch(T){A.error("[plane-link] metrics sample failed:",T?.message||T);return}let F=null;try{F=c?.()??null}catch{}L&&it({v:ut,ch:"ctl",type:"metrics",metrics:{...L,planeLink:zy(),...F?{delivery:F}:{}}})}function vO(){i&&(rt&&clearInterval(rt),Vy(),rt=setInterval(Vy,u),rt.unref?.())}async function SO(){let L;try{L=await o()}catch(F){A.error("[plane-link] backfill listTracks failed:",F?.message||F);return}it({v:ut,ch:"ctl",type:"tracks",ids:L.filter(F=>!F.transferredTo).map(F=>F.id).filter(F=>typeof F=="string")});for(let F of L){if(!v)return;let T;try{T=await K(F)}catch{continue}let B=Ae[F.id]??0,Y=T.filter(Ee=>Ee.seq>B&&typeof Ee.id=="string"),xe=j==="http"?gt:to;for(let Ee=0;Ee<Y.length;Ee+=xe){if(!await yO(F.id))return;let Ue=Y.slice(Ee,Ee+Math.min(xe,j==="http"?gt:to)).map(Tt=>({trackId:F.id,event:Tt}));if(!Da(Ue))return}}}function Jy(L){!v||!L?.trackId||typeof L.id!="string"||(gn.push({trackId:L.trackId,event:L}),k||(k=setTimeout(Tp,O_),k.unref?.()))}let Ba=new Map;async function TO(L){let{reqId:F,method:T,path:B,headers:Y={},body:xe}=L,Ee=Object.fromEntries(Object.entries(Y).filter(([,Tt])=>Tt!=null)),Ue=new AbortController;Ba.set(F,Ue);try{if(L.host){await AO(L,Ee,Ue);return}b&&(Ee["x-bostrat-token"]=b);let Tt=await fetch(g+B,{method:T,headers:Ee,body:xe?Buffer.from(xe,"base64"):void 0,signal:Ue.signal}),Ht=Object.fromEntries(Tt.headers);for(let Qe of["connection","keep-alive","transfer-encoding","upgrade","content-encoding","content-length"])delete Ht[Qe];if(Ht["content-type"]||(Ht["content-type"]="application/octet-stream"),it({v:ut,ch:"control",type:"http_head",reqId:F,status:Tt.status,headers:Ht}),Tt.body){for await(let Qe of Tt.body)if(!it({v:ut,ch:"control",type:"http_data",reqId:F,data:Buffer.from(Qe).toString("base64")}))break}it({v:ut,ch:"control",type:"http_end",reqId:F,error:null})}finally{Ba.delete(F)}}function AO(L,F,T){let{reqId:B,method:Y,path:xe,body:Ee}=L,Ue=new URL(g);return new Promise(Tt=>{let Ht=Z4.request({host:Ue.hostname,port:Ue.port,method:Y,path:xe,headers:{...F,host:L.host},signal:T.signal},Qe=>{let{connection:Xy,"keep-alive":YK,"transfer-encoding":XK,upgrade:ZK,...EO}=Qe.headers;it({v:ut,ch:"control",type:"http_head",reqId:B,status:Qe.statusCode||502,headers:EO}),Qe.on("data",_O=>{it({v:ut,ch:"control",type:"http_data",reqId:B,data:Buffer.from(_O).toString("base64")})||Qe.destroy()}),Qe.on("end",()=>{it({v:ut,ch:"control",type:"http_end",reqId:B,error:null}),Tt()}),Qe.on("error",()=>{it({v:ut,ch:"control",type:"http_end",reqId:B,error:"view upstream error"}),Tt()})});Ht.on("error",Qe=>{it({v:ut,ch:"control",type:"http_end",reqId:B,error:Qe?.message||"view request failed"}),Tt()}),Ee&&Ht.write(Buffer.from(Ee,"base64")),Ht.end()})}function Yy(){if(D)return;h=new yg(e,{headers:{authorization:`Bearer ${t}`}}),h.on("open",async()=>{let F=null;try{F=await s?.()||null}catch{F=null}it({v:ut,ch:"ctl",type:"hello",nodeId:n,name:r,platform:process.platform,version:dn,installKind:m,...typeof w=="function"?{updatePolicy:w()}:w?{updatePolicy:w}:{},providers:e2(),...F?{agents:F}:{}})}),h.on("message",F=>{let T;try{T=JSON.parse(F)}catch{return}if(T.ch==="ctl"&&T.type==="hello_ok"){v=!0,ce=I_,ye=null,A.log(`[plane-link] connected to plane as ${n}`);try{$?.()}catch{}if(typeof T.hashKey=="string"&&T.hashKey)try{l?.(T.hashKey)}catch{}T.minNodeVersion&&dn&&$c(dn,T.minNodeVersion)&&A.error(`[plane-link] this node is bostrat-node ${dn}; the plane asks for \u2265${T.minNodeVersion} \u2014 update with: ${Rd(m)}`);try{p?.(typeof T.updatePolicy=="string"?T.updatePolicy:null)}catch{}let B=typeof T.latestNodeVersion=="string"?T.latestNodeVersion:null;if(B&&dn&&$c(dn,B)&&!N.has(B)){N.add(B),A.log(`[plane-link] bostrat-node ${B} is available (this node runs ${dn}) \u2014 ${Rd(m)}`);try{d?.({current:dn,latest:B,min:T.minNodeVersion??null,installKind:m,required:!!(T.minNodeVersion&&$c(dn,T.minNodeVersion))})}catch(xe){A.error(`[plane-link] update notice failed: ${xe?.message||xe}`)}}let Y=T.ingest==="http";j=O==="ws"?"ws":O==="http"||Y?"http":"ws",O==="http"&&!Y&&A.error("[plane-link] BOSTRAT_PLANE_INGEST=http but this plane offers no HTTPS ingest door \u2014 events will fail until it does"),j==="http"&&A.log("[plane-link] spine rides the HTTPS ingest door"),Pe=!1,Ce=0,gt=to,qe&&clearInterval(qe),qe=setInterval(()=>{it({v:ut,ch:"ctl",type:"ping"}),Gy(),xO().catch(()=>{}),Sp(),gn.length&&!k&&Tp()},P),qe.unref?.(),vO(),SO().catch(xe=>A.error("[plane-link] backfill failed:",xe?.message||xe));return}if(T.ch==="ctl"&&T.type==="hello_refused"){let B=typeof T.minNodeVersion=="string"?T.minNodeVersion:null,Y=typeof T.latestNodeVersion=="string"?T.latestNodeVersion:null;A.error(`[plane-link] plane REFUSED this node: bostrat-node ${dn??"?"} is below its minimum ${B??"?"} \u2014 ${T.fix||Rd(m)}`),ce=$_,ye=0;try{f?.({current:dn,min:B,latest:Y,fix:T.fix||Rd(m),installKind:m})}catch(xe){A.error(`[plane-link] refusal handler failed: ${xe?.message||xe}`)}return}if(T.ch==="ctl"&&T.type==="update_policy"){try{p?.(typeof T.mode=="string"?T.mode:null)}catch{}return}if(T.ch==="ctl"&&T.type==="usage_caps"){mu(T.caps??{},{source:"plane",updatedAt:T.updatedAt??Date.now()}).then(B=>A.log(`[plane-link] spend caps ${Object.keys(B.caps).length?`updated (${Object.keys(B.caps).join(", ")})`:"cleared"} from plane`)).catch(B=>A.error("[plane-link] spend-caps push rejected:",B?.message||B));return}if(T.ch==="ctl"&&T.type==="transferred"&&Array.isArray(T.tracks)){Promise.resolve().then(()=>a?.(T.tracks)).catch(B=>A.error("[plane-link] transfer notice failed:",B?.message||B));return}if(T.ch==="events"&&T.type==="ack"&&Array.isArray(T.ids)){vp(T.ids);return}if(T.ch==="events"&&T.type==="nack"&&Array.isArray(T.ids)){qy(T.ids,T.reason,T.permanent===!0,T.retryAfterMs??null);return}if(T.ch==="control"&&T.type==="http_open"){TO(T).catch(B=>it({v:ut,ch:"control",type:"http_end",reqId:T.reqId,error:B?.message||"tunnel error"}));return}if(T.ch==="control"&&T.type==="http_cancel"){Ba.get(T.reqId)?.abort();return}if(T.ch==="attach"&&T.type==="open"){let B=new yg(_+T.path,Array.isArray(T.protocols)?T.protocols:[],T.host?{headers:{host:T.host}}:void 0);U.set(T.streamId,B),z.set(T.streamId,[]),B.on("open",()=>{let xe=z.get(T.streamId)||[];z.delete(T.streamId);for(let{buf:Ee,bin:Ue}of xe)B.send(Ee,{binary:Ue})}),B.on("message",(xe,Ee)=>{let Ue=Ee?xe:Buffer.from(String(xe));it({v:ut,ch:"attach",type:"data",streamId:T.streamId,data:Ue.toString("base64"),...Ee?{bin:!0}:{}})});let Y=()=>{z.delete(T.streamId),U.delete(T.streamId)&&it({v:ut,ch:"attach",type:"close",streamId:T.streamId})};B.on("close",Y),B.on("error",Y);return}if(T.ch==="attach"&&T.type==="data"){let B=U.get(T.streamId);if(!B)return;let Y=Buffer.from(T.data,"base64"),xe=T.bin===!0,Ee=z.get(T.streamId);Ee?Ee.push({buf:Y,bin:xe}):B.send(Y,{binary:xe});return}if(T.ch==="attach"&&T.type==="close"){let B=U.get(T.streamId);U.delete(T.streamId),z.delete(T.streamId),B?.close();return}});let L=()=>{v&&A.log("[plane-link] disconnected from plane"),v=!1,qe&&(clearInterval(qe),qe=null),rt&&(clearInterval(rt),rt=null),te.clear(),W={},gn=[],k&&(clearTimeout(k),k=null),gr.clear();for(let B of U.values())B.close();U.clear(),z.clear();for(let B of Ba.values())B.abort();if(Ba.clear(),D||De)return;ye==null&&(ye=Date.now());let F=Date.now()-ye<t2,T=Math.max(F?n2+Math.random()*r2:ce,Oe-Date.now());De=setTimeout(()=>{De=null,Yy()},T),De.unref?.(),F||(ce=Math.min(ce*2,$_))};h.on("close",L),h.on("error",F=>{let T=/Unexpected server response: (\d+)/.exec(F?.message||"")?.[1];(T==="401"||T==="403")&&Date.now()-sl>=C_&&(sl=Date.now(),A.error(`[plane-link] plane refused this node's credentials (HTTP ${T}) \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)`)),L()})}return ot.on("event",Jy),hO().then(Yy),{stop:()=>{D=!0,ot.off("event",Jy),De&&clearTimeout(De),St&&clearTimeout(St),qe&&clearInterval(qe),rt&&clearInterval(rt),k&&clearTimeout(k),it({v:ut,ch:"ctl",type:"bye",reason:"shutdown"}),h?.close()},status:()=>({connected:v,nodeId:n,cursor:{...Ae},inflight:te.size,...zy()}),_tick:()=>{Gy(),Sp()}}}Fl();var Cd=(()=>{try{return m2(import.meta.url)("../package.json").version||null}catch{return null}})(),h2=process.env.BOSTRAT_STATE_DIR||dt.join(process.env.HOME||p2.tmpdir(),".bostrat"),j_=dt.join(h2,"self-update"),Md=dt.join(j_,"status.json"),w2=1440*6e4,g2=6e4,Rc=new Set(["npm-global","git-checkout"]);function B_({kind:e=Qo(),env:t=process.env}={}){let n=String(t.BOSTRAT_UPDATE_POLICY||"").trim();return["auto","prompt","off"].includes(n)?n:Rc.has(e)?e==="git-checkout"||y2(t)?"auto":"prompt":"off"}function y2(e=process.env){return!!(e.INVOCATION_ID||e.XPC_SERVICE_NAME&&e.XPC_SERVICE_NAME!=="0")}var Bt=e=>`'${String(e).replace(/'/g,"'\\''")}'`;function b2({kind:e,to:t,from:n=Cd,statusFile:r=Md,logFile:o=dt.join(j_,"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||dt.resolve(dt.dirname(new URL(import.meta.url).pathname),"..",".."),startedAt:u=Date.now()}={}){if(!Rc.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,b="")=>`write_status ${Bt(g)} ${b}`,p=process.platform==="darwin"?`launchctl kickstart -k gui/${c}/${i}`:`systemctl --user restart ${Bt(i)}`,f=`
651
+ `);m4=new Set(["claude","codex","cursor"]);wc=new Set,h4=e=>wc.has(e);w4=9e4;HE={merged:"merged",closed:"closed on GitHub WITHOUT merging",lost:"no longer found on GitHub (deleted, or its repo left the grant)"};xw=new Map;_w=120;ng=(e,t,n)=>({name:e.name,agent:e.agent,role:t,state:n,cwd:e.cwd,sessionId:e.sessionId,pinned:e.pinned===!0,hookTokenHash:La(e.hookToken),createdAt:Date.now()});ya=new Map,xa=e=>ya.get(e)||(Vt?we(Vt,e)?.handoff:null)||null;Iw=6e4,ln=(e,t,n=15e3)=>GE("git",["-C",e,...t],{timeout:n,maxBuffer:8*1024*1024}),$w=new Map,og=e=>$w.get(e)||null;v4=/^[A-Za-z0-9][A-Za-z0-9._/-]{0,200}$/;vw=new Map;A4=Number(process.env.BOSTRAT_SUBTASK_TIMEOUT_MS)||18e5,E4=Number(process.env.BOSTRAT_SUBTASK_POLL_MS)||3e3,ba=re.join(Bn,"worktrees"),da=[pc,md],Pt=new Map,_4=e=>Pt.get(e)||(Vt?Vt.tracks.map(t=>t.subtasks?.[e]).find(Boolean):null)||null,Zo=e=>{let t=new Map([...Pt.values()].filter(r=>r.trackId===e).map(r=>[r.id,r])),n=Vt?we(Vt,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)},$d=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});Ec=e=>p_(e.trackId,e.id,$d(e));ug=e=>e.trim().replace(/\s+/g,"-").replace(/[^A-Za-z0-9._-]/g,"").toLowerCase()||"track",yc=class extends Error{}});ct();import Te from"node:path";import wt from"node:fs";import _K from"node:readline";import{fileURLToPath as IK}from"node:url";import Ut from"express";import $K from"node:http";import RK from"node:https";import yp from"node:os";import{randomUUID as OK}from"node:crypto";import{WebSocketServer as CK}from"ws";ct();import LM from"node-pty";async function wk(e,t,n={}){if(!je(t)){Bl(e,`invalid session name: ${t}`),e.close(1008,"invalid session name");return}if(!await Er()){Bl(e,`host tmux server not running on ${Rt}`),e.close(1011,"tmux server unavailable");return}if(!await ke(t)){Bl(e,`session "${t}" not found`),e.close(1008,"session not found");return}let r=hk(n.cols,120,gk),o=hk(n.rows,32,yk),s;try{s=LM.spawn(X,["-S",Rt,"attach-session","-d","-t",t],{name:"xterm-256color",cols:r,rows:o,cwd:process.env.HOME||"/",env:{...process.env,TERM:"xterm-256color"}})}catch(a){Bl(e,`failed to spawn tmux attach: ${a.message}`),e.close(1011,"spawn failed");return}s.onData(a=>{e.readyState===e.OPEN&&rf(e,{type:"data",data:a})}),s.onExit(({exitCode:a,signal:i})=>{e.readyState===e.OPEN&&(rf(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"&&WM(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{}HM(t)})}var FM=6,UM=250;async function HM(e,t=FM,n=UM){for(let r=0;r<t;r++){if(await bo(e).catch(()=>!0))return!0;await new Promise(o=>setTimeout(o,n))}return!1}var gk=20,yk=6;function WM(e,t){return Number.isFinite(Number(e))&&Number.isFinite(Number(t))&&Number(e)>=gk&&Number(t)>=yk}function hk(e,t,n){let r=Number(e);return!Number.isFinite(r)||r<n?t:Math.min(500,r|0)}function rf(e,t){try{e.send(JSON.stringify(t))}catch{}}function Bl(e,t){rf(e,{type:"error",message:t})}function bk(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}}nn();Ll();zf();or();import{createRequire as MK}from"node:module";var B4=e=>!!e&&!e.finishedAt&&!e.canceled&&!e.error;function mg({tracks:e=[],views:t=[],queuedOf:n=()=>[],jobsOf:r=()=>[]}={}){let o=[];for(let s of e)!s||s.archivedAt&&!s.archiving||s.transferredTo||(s.working&&o.push(`working:${s.id}`),s.prompted&&o.push(`prompted:${s.id}`),(n(s.id)??[]).length&&o.push(`queued:${s.id}`),(s.boxes||[]).some(a=>a?.role==="subtask"&&a?.state==="live")&&o.push(`subtask:${s.id}`),(r(s.id)??[]).length&&o.push(`job:${s.id}`),Object.values(s.subtasks||{}).some(B4)&&o.push(`merge-back:${s.id}`));return t.some(s=>s?.state==="live"||s?.state==="starting")&&o.push("views"),{busy:o.length>0,reasons:o}}de();im();ct();import U4 from"node:fs/promises";import hg from"node:fs/promises";var j4=100;async function L4(e){let t;try{t=await hg.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/j4*1e3,ioBytes:await F4(e)}}async function F4(e){let t;try{t=await hg.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 y_(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 hg.readdir("/proc")}catch{return null}let r=new Map;await Promise.all(n.map(async l=>{if(!/^\d+$/.test(l))return;let u=await L4(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 H4=Number(process.env.BOSTRAT_JOB_CHECK_MS)||15*6e4,W4=Number(process.env.BOSTRAT_JOB_STALL_CHECKS)||3,q4=Number(process.env.BOSTRAT_JOB_CPU_RATE_MIN)||25,K4=Number(process.env.BOSTRAT_JOB_IO_RATE_MIN)||64*1024,G4=5*6e4,k_={readOpenJobs:Hx,statFile:async e=>{try{let t=await U4.stat(e);return{size:t.size,mtimeMs:Math.round(t.mtimeMs)}}catch{return null}},updatedAt:e=>Br(e.agent).updatedAt(e),panePids:pk,treeStats:y_,appendEvent:C},un=new Map,b_=new Map,wg=new Map,gg=(e,t,n)=>`${e}|${t}|${n}`;function x_(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 v_(e,t,n){let r=null;try{r=await n.updatedAt(e)}catch{r=null}let o=b_.get(e.name);if(o&&o.mtime===r&&t-o.at<G4)return o.jobs;let s=[];try{s=await n.readOpenJobs(e)}catch{s=[]}return b_.set(e.name,{at:t,mtime:r,jobs:s}),s}async function z4(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 V4(e,t){return e?.outputFile?await t.statFile(e.outputFile):null}function J4(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>=q4||t.ioBytes!=null&&e.ioBytes!=null&&(t.ioBytes-e.ioBytes)/n>=K4}function S_(e,t,n,r){let o=[];for(let s of n){let a=gg(e.id,t.name,s.id),i=un.get(a);i?i.job=s:un.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 T_(e,{now:t=Date.now(),deps:n=k_}={}){let r=new Map,o=new Set;for(let{track:s,box:a}of x_(e)){let i=await v_(a,t,n);for(let l of i)o.add(gg(s.id,a.name,l.id));let c=S_(s,a,i,t).filter(l=>!un.get(l).stalled).map(l=>un.get(l).job);c.length&&r.set(s.id,[...r.get(s.id)??[],...c])}for(let s of[...un.keys()])o.has(s)||un.delete(s);return r}async function Y4(e,{now:t=Date.now(),deps:n=k_}={}){let r={checked:0,progressing:0,quiet:0,stalled:[]},o=x_(e),s=new Set(o.map(({box:a})=>a.name));for(let[a,i]of[...un])s.has(i.boxName)||un.delete(a);for(let{track:a,box:i}of o){let c=await v_(i,t,n),l=new Set(c.map(w=>gg(a.id,i.name,w.id)));for(let[w,m]of[...un])m.boxName===i.name&&!l.has(w)&&un.delete(w);if(!c.length){wg.delete(i.name);continue}let u=S_(a,i,c,t),d=await z4(i,t,n),p=wg.get(i.name);wg.set(i.name,d);let f=J4(p,d);for(let w of u){let m=un.get(w);r.checked++;let g=await V4(m.job,n),b=!!g&&!!m.file&&(g.size>m.file.size||g.mtimeMs>m.file.mtimeMs),x=!!g&&!m.file;if(m.file=g??m.file,f||b||x){m.quiet=0,m.lastProgressAt=t,m.stalled=!1,r.progressing++;continue}if(m.stalled||(m.quiet++,r.quiet++,m.quiet<W4))continue;m.stalled=!0,m.stalledAt=t,r.stalled.push(w);let $=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:$,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($/6e4)}m over ${m.quiet} check(s) \u2014 released; the node may sleep`)}}return r}function A_({listTracks:e,intervalMs:t=H4}={}){let n=!1,o=setInterval(async()=>{if(!n){n=!0;try{await Y4(await e())}catch(s){console.error(`[job-watch] sweep: ${s?.message||s}`)}finally{n=!1}}},t);return o.unref?.(),o}import B_ from"node:fs";import no from"node:fs/promises";import f2 from"node:os";import dt from"node:path";import{spawn as m2}from"node:child_process";import{createRequire as h2}from"node:module";de();hu();import N_ from"node:fs";import Ic from"node:fs/promises";import Q4 from"node:http";import pn from"node:path";import Cd from"node:os";import{createRequire as e2}from"node:module";import bg from"ws";import X4 from"node:path";import Z4 from"node:os";var _c=process.env.BOSTRAT_STATE_DIR||X4.join(process.env.HOME||Z4.tmpdir(),".bostrat");function yg(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 E_(e=process.env){if(!e.BOSTRAT_PLANE_URL)return null;let t=yg(e);return t==="127.0.0.1"||t==="::1"||t==="localhost"?null:{host:t}}function __(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}var dn=(()=>{try{return e2(import.meta.url)("../package.json").version||null}catch{return null}})(),I_=process.env.BOSTRAT_STATE_DIR||pn.join(process.env.HOME||Cd.tmpdir(),".bostrat");function Qo({env:e=process.env,pkgDir:t=pn.resolve(pn.dirname(new URL(import.meta.url).pathname),".."),exists:n=N_.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(pn.join(t,"..",".git"))?"git-checkout":"dev"}function $c(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 Od(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 t2({home:e=process.env.HOME||Cd.homedir(),env:t=process.env}={}){let n=r=>{try{return N_.statSync(r),!0}catch{return!1}};return{claude:n(pn.join(e,".claude",".credentials.json")),codex:n(pn.join(t.CODEX_HOME||pn.join(e,".codex"),"auth.json"))}}var ut=1,$_=1e3,R_=3e4,n2=6e4,r2=1500,o2=500,to=100,s2=2e3,a2=25e3,i2=6e4,P_=(e,t)=>{let n=Number(e);return Number.isFinite(n)&&n>0?n:t},c2=P_(process.env.BOSTRAT_PLANE_DELIVERY_TIMEOUT_MS,18e4),l2=3e4,O_=10*6e4,u2=400,C_=250,d2=P_(process.env.BOSTRAT_PLANE_INGEST_TIMEOUT_MS,1e4),kg=4,p2=6e4,M_=6e4;function D_({url:e,token:t,nodeId:n=Cd.hostname(),name:r=Cd.hostname(),listTracks:o,detectAgents:s=null,onTracksTransferred:a=null,sampleMetrics:i=null,deliverySample:c=null,onHashKey:l=null,metricsMs:u=p2,onUpdateAvailable:d=null,onUpdatePolicy:p=null,onHelloRefused:f=null,updatePolicy:w=null,installKind:m=Qo(),selfUrl:g=`http://127.0.0.1:${process.env.PORT||3362}`,apiToken:b=null,onDegraded:x=null,onRecovered:y=null,onConnected:$=null,ingestMode:O=["ws","http","auto"].includes(process.env.BOSTRAT_PLANE_INGEST)?process.env.BOSTRAT_PLANE_INGEST:"auto",deliveryTimeoutMs:M=c2,unackedRetryMs:H=i2,pingMs:P=a2,maxInflightEvents:E=u2,httpTimeoutMs:R=d2,stallBackoffMinMs:G=l2,fetchImpl:V=globalThis.fetch,log:A=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=__(e);let _=g.replace(/^http/,"ws"),N=new Set,U=new Map,z=new Map,ue=pn.join(I_,"plane-link","cursor.json"),pe=pn.join(I_,"plane-link","dead-letter.ndjson"),Se=e.replace(/^ws(s?):\/\//,"http$1://").replace(/\/v1\/node\/?$/,""),Ae={},W={},te=new Map,ie=null,J=null,ge=0,Oe=0,Me=0,I=Promise.resolve(),B="ws",fe=0,Pe=!1,Ce=0,wn=!1,gt=to,gr=new Set,gn=[],k=null,h=null,v=!1,D=!1,ce=$_,ye=null,De=null,St=null,qe=null,rt=null,xp=!1,sl=0;async function wO(){try{Ae=JSON.parse(await Ic.readFile(ue,"utf8"))}catch{Ae={}}}function gO(){xp=!0,!St&&(St=setTimeout(async()=>{if(St=null,!!xp){xp=!1;try{await Ic.mkdir(pn.dirname(ue),{recursive:!0}),await Ic.writeFile(ue,JSON.stringify(Ae))}catch(L){A.error("[plane-link] cursor flush failed:",L?.message||L)}}},s2),St.unref?.())}function it(L){return!h||h.readyState!==bg.OPEN?!1:(h.send(JSON.stringify(L)),!0)}function Da(L){let F=Date.now();for(let{trackId:T,event:j}of L){let Y=te.get(j.id);te.set(j.id,{trackId:T,seq:j.seq,event:j,sentAt:F,firstSentAt:Y?.firstSentAt??F,retryAt:F+H,tries:(Y?.tries??0)+1,nacks:Y?.nacks??0})}return B==="http"?(xO(L),!0):it({v:ut,ch:"events",type:"append",events:L})}function yO(L){let F=null;for(let T of te.values())T.trackId===L&&(F==null||T.seq<F)&&(F=T.seq);return F}function vp(L){let F=W[L];if(F==null)return;let T=yO(L),j=T==null?F:Math.min(F,T-1);j>(Ae[L]??0)&&(Ae[L]=j,gO())}function Ba(){if(ie=Date.now(),J!=null){let L=Date.now()-J;A.log(`[plane-link] spine sync recovered after ${Math.round(L/1e3)}s degraded (${ge} stall redial(s))`);let F=J;J=null,ge=0,Oe=0,Pe=!1,Ce=0;try{y?.({since:F,downMs:L})}catch(T){A.error(`[plane-link] onRecovered failed: ${T?.message||T}`)}}}function Sp(L){if(!Array.isArray(L)||!L.length)return;let F=new Set;for(let T of L){let j=te.get(T);j&&(te.delete(T),(W[j.trackId]??0)<j.seq&&(W[j.trackId]=j.seq),F.add(j.trackId))}for(let T of F)vp(T);Ba()}function Wy(L,F){Me++;let T={at:Date.now(),trackId:L.trackId,seq:L.seq,id:L.event?.id??null,type:L.event?.type??null,reason:F,event:L.event??null};A.error(`[plane-link] DEAD-LETTER ${L.trackId} seq ${L.seq} (${T.type??"?"}): plane rejected it permanently (${F}) \u2014 kept in ${pe}`),I=I.then(async()=>{await Ic.mkdir(pn.dirname(pe),{recursive:!0}),await Ic.appendFile(pe,JSON.stringify(T)+`
652
+ `)}).catch(j=>A.error(`[plane-link] dead-letter write failed: ${j?.message||j}`))}function qy(L,F,T,j=null){if(!Array.isArray(L)||!L.length)return;let Y=new Set,xe=Date.now();for(let Ee of L){let Ue=te.get(Ee);Ue&&(T?(te.delete(Ee),Wy(Ue,F),(W[Ue.trackId]??0)<Ue.seq&&(W[Ue.trackId]=Ue.seq),Y.add(Ue.trackId)):(Ue.nacks++,Ue.retryAt=xe+Math.max(1e3,Number(j)||H)))}for(let Ee of Y)vp(Ee);Ba()}function Ky(L=Date.now()){let F=1/0;for(let T of te.values())T.firstSentAt<F&&(F=T.firstSentAt);return F===1/0?0:L-F}function Gy(){if(!v||!te.size)return;let L=Date.now(),F=Ky(L);if(F<M||ie!=null&&L-ie<M||B==="http"&&Pe||Oe>L)return;ge++;let T=Math.min(G*2**(ge-1),O_);if(J==null){J=L-F,A.error(`[plane-link] DEGRADED: no ack or nack for ${Math.round(F/1e3)}s with ${te.size} event(s) in flight (${B} door) \u2014 the plane is not answering appends`);try{x?.({since:J,unacked:te.size,oldestAgeMs:F,mode:B})}catch(j){A.error(`[plane-link] onDegraded failed: ${j?.message||j}`)}}if(B==="http"){Pe=!0,Ce=L+T,A.error(`[plane-link] ingest circuit OPEN (stall #${ge}); probing /v1/ingest/health in ${Math.round(T/1e3)}s`);return}Oe=L+T,A.error(`[plane-link] closing the link and redialing in ${Math.round(T/1e3)}s (stall redial #${ge})`);try{h?.terminate()}catch{}}function Tp(){if(!v)return;let L=Date.now();if(B==="http"&&Pe)return;let F=[...te.values()].filter(j=>j.event&&j.retryAt<=L&&!(B==="http"&&gr.has(j.trackId)));if(!F.length)return;F.sort((j,Y)=>j.trackId===Y.trackId?j.seq-Y.seq:j.trackId<Y.trackId?-1:1),A.log(`[plane-link] re-sending ${F.length} unacked event(s) the plane never confirmed`);let T=B==="http"?gt:to;if(B==="http"){let j=new Map;for(let Y of F)(j.get(Y.trackId)??j.set(Y.trackId,[]).get(Y.trackId)).push(Y);for(let[,Y]of j){if(fe>=kg)return;Da(Y.slice(0,T).map(xe=>({trackId:xe.trackId,event:xe.event})))}return}for(let j=0;j<F.length;j+=T){let Y=F.slice(j,j+T).map(xe=>({trackId:xe.trackId,event:xe.event}));if(!Da(Y))return}}async function bO(L=null){for(;;){if(!v)return!1;let F=te.size<E,T=B!=="http"||fe<kg&&!Pe&&(!L||!gr.has(L));if(F&&T)return!0;await new Promise(j=>setTimeout(j,100))}}function Ap(){if(k=null,!v||!gn.length)return;let L=gn;if(gn=[],B!=="http"){for(let T=0;T<L.length;T+=to)Da(L.slice(T,T+to));return}let F=new Map;for(let T of L)(F.get(T.trackId)??F.set(T.trackId,[]).get(T.trackId)).push(T);for(let[T,j]of F){if(gr.has(T)||fe>=kg||Pe){gn.push(...j);continue}for(let Y=0;Y<j.length;Y+=gt)Da(j.slice(Y,Y+gt))}gn.length&&!k&&(k=setTimeout(Ap,C_),k.unref?.())}let kO=L=>{let F=new Map;for(let{trackId:T,event:j}of L)(F.get(T)??F.set(T,[]).get(T)).push(j);return[...F].map(([T,j])=>({trackId:T,events:j}))},us=(L,F,T,{progress:j})=>{let Y=Date.now();for(let{event:xe}of L){let Ee=te.get(xe.id);Ee&&(Ee.nacks++,Ee.retryAt=Y+Math.max(1e3,T||H))}j&&Ba()};async function xO(L){let F=new Set(L.map(T=>T.trackId));for(let T of F)gr.add(T);fe++;try{let T=await V(`${Se}/v1/ingest`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/json"},body:JSON.stringify({node:n,batches:kO(L)}),signal:AbortSignal.timeout(R)}),j=(Number(T.headers.get("retry-after"))||0)*1e3;if(T.status===200){let Y=await T.json();gt=to;for(let xe of Y.results??[]){Sp(xe.acked??[]);let Ee=(Ue,Tt)=>{let Ht=new Map;for(let Qe of Ue??[])(Ht.get(Qe.reason)??Ht.set(Qe.reason,[]).get(Qe.reason)).push(Qe.id);for(let[Qe,Xy]of Ht)qy(Xy,Qe,Tt,Y.retryAfterMs??null)};Ee(xe.rejected,!0),Ee(xe.deferred,!1)}Sp(Y.discarded??[]),Ba();return}if(T.status===429){us(L,"overloaded",j||5e3,{progress:!0});return}if(T.status===413&&L.length>1){gt=Math.max(1,Math.floor(L.length/2)),A.error(`[plane-link] ingest request too large (${L.length} events) \u2014 halving batches to ${gt}`),us(L,"too_large",1e3,{progress:!0});return}if(T.status===413){let Y=te.get(L[0].event.id);Y&&(te.delete(Y.event.id),Wy(Y,"too_large"),(W[Y.trackId]??0)<Y.seq&&(W[Y.trackId]=Y.seq),vp(Y.trackId)),Ba();return}if(T.status===401||T.status===403){if(Date.now()-sl>=M_){sl=Date.now();let Y="";try{Y=(await T.json())?.error??""}catch{}A.error(`[plane-link] plane refused ingest (HTTP ${T.status}${Y?`: ${Y}`:""}) \u2014 events are held locally and retried; check this node's token/binding`)}us(L,`http_${T.status}`,6e4,{progress:!1});return}if(T.status===400){A.error(`[plane-link] plane rejected an ingest request as malformed (400) \u2014 holding ${L.length} event(s) for retry; this is a bug, not data`),us(L,"http_400",6e4,{progress:!1});return}us(L,`http_${T.status}`,j||5e3,{progress:!1})}catch(T){let j=T?.name==="TimeoutError"||T?.name==="AbortError";j&&L.length>1&&(gt=Math.max(1,Math.floor(L.length/2)),A.error(`[plane-link] ingest request of ${L.length} event(s) outlived its ${R} ms deadline \u2014 halving batches to ${gt}`)),us(L,j?"timeout":"network",5e3,{progress:!1})}finally{fe--;for(let T of F)gr.delete(T)}}async function vO(){if(B!=="http"||!Pe||!v||wn)return;let L=Date.now();if(!(Ce>L)){wn=!0;try{let F=await V(`${Se}/v1/ingest/health`,{headers:{authorization:`Bearer ${t}`},signal:AbortSignal.timeout(R)});if(!F.ok)throw new Error(`HTTP ${F.status}`);A.log("[plane-link] ingest door answering \u2014 closing the circuit and re-sending"),Pe=!1,Ce=0,Oe=Date.now()+R+H+1e3;for(let T of te.values())T.retryAt=Math.min(T.retryAt,Date.now());Tp()}catch(F){ge++;let T=Math.min(G*2**(ge-1),O_);Ce=Date.now()+T,A.error(`[plane-link] ingest door still not answering (${F?.message||F}); next probe in ${Math.round(T/1e3)}s`)}finally{wn=!1}}}function zy(){let L=Date.now();return{mode:B,unacked:te.size,oldestUnackedAgeMs:Ky(L),lastProgressAt:ie,degradedSince:J,stallRedials:ge,deadLettered:Me,http:B==="http"?{inFlight:fe,circuitOpen:Pe,nextProbeInMs:Pe?Math.max(0,Ce-L):0,batchCap:gt}:null}}async function Vy(){if(!i)return;let L;try{L=await i()}catch(T){A.error("[plane-link] metrics sample failed:",T?.message||T);return}let F=null;try{F=c?.()??null}catch{}L&&it({v:ut,ch:"ctl",type:"metrics",metrics:{...L,planeLink:zy(),...F?{delivery:F}:{}}})}function SO(){i&&(rt&&clearInterval(rt),Vy(),rt=setInterval(Vy,u),rt.unref?.())}async function TO(){let L;try{L=await o()}catch(F){A.error("[plane-link] backfill listTracks failed:",F?.message||F);return}it({v:ut,ch:"ctl",type:"tracks",ids:L.filter(F=>!F.transferredTo).map(F=>F.id).filter(F=>typeof F=="string")});for(let F of L){if(!v)return;let T;try{T=await K(F)}catch{continue}let j=Ae[F.id]??0,Y=T.filter(Ee=>Ee.seq>j&&typeof Ee.id=="string"),xe=B==="http"?gt:to;for(let Ee=0;Ee<Y.length;Ee+=xe){if(!await bO(F.id))return;let Ue=Y.slice(Ee,Ee+Math.min(xe,B==="http"?gt:to)).map(Tt=>({trackId:F.id,event:Tt}));if(!Da(Ue))return}}}function Jy(L){!v||!L?.trackId||typeof L.id!="string"||(gn.push({trackId:L.trackId,event:L}),k||(k=setTimeout(Ap,C_),k.unref?.()))}let ja=new Map;async function AO(L){let{reqId:F,method:T,path:j,headers:Y={},body:xe}=L,Ee=Object.fromEntries(Object.entries(Y).filter(([,Tt])=>Tt!=null)),Ue=new AbortController;ja.set(F,Ue);try{if(L.host){await EO(L,Ee,Ue);return}b&&(Ee["x-bostrat-token"]=b);let Tt=await fetch(g+j,{method:T,headers:Ee,body:xe?Buffer.from(xe,"base64"):void 0,signal:Ue.signal}),Ht=Object.fromEntries(Tt.headers);for(let Qe of["connection","keep-alive","transfer-encoding","upgrade","content-encoding","content-length"])delete Ht[Qe];if(Ht["content-type"]||(Ht["content-type"]="application/octet-stream"),it({v:ut,ch:"control",type:"http_head",reqId:F,status:Tt.status,headers:Ht}),Tt.body){for await(let Qe of Tt.body)if(!it({v:ut,ch:"control",type:"http_data",reqId:F,data:Buffer.from(Qe).toString("base64")}))break}it({v:ut,ch:"control",type:"http_end",reqId:F,error:null})}finally{ja.delete(F)}}function EO(L,F,T){let{reqId:j,method:Y,path:xe,body:Ee}=L,Ue=new URL(g);return new Promise(Tt=>{let Ht=Q4.request({host:Ue.hostname,port:Ue.port,method:Y,path:xe,headers:{...F,host:L.host},signal:T.signal},Qe=>{let{connection:Xy,"keep-alive":XK,"transfer-encoding":ZK,upgrade:QK,..._O}=Qe.headers;it({v:ut,ch:"control",type:"http_head",reqId:j,status:Qe.statusCode||502,headers:_O}),Qe.on("data",IO=>{it({v:ut,ch:"control",type:"http_data",reqId:j,data:Buffer.from(IO).toString("base64")})||Qe.destroy()}),Qe.on("end",()=>{it({v:ut,ch:"control",type:"http_end",reqId:j,error:null}),Tt()}),Qe.on("error",()=>{it({v:ut,ch:"control",type:"http_end",reqId:j,error:"view upstream error"}),Tt()})});Ht.on("error",Qe=>{it({v:ut,ch:"control",type:"http_end",reqId:j,error:Qe?.message||"view request failed"}),Tt()}),Ee&&Ht.write(Buffer.from(Ee,"base64")),Ht.end()})}function Yy(){if(D)return;h=new bg(e,{headers:{authorization:`Bearer ${t}`}}),h.on("open",async()=>{let F=null;try{F=await s?.()||null}catch{F=null}it({v:ut,ch:"ctl",type:"hello",nodeId:n,name:r,platform:process.platform,version:dn,installKind:m,...typeof w=="function"?{updatePolicy:w()}:w?{updatePolicy:w}:{},providers:t2(),...F?{agents:F}:{}})}),h.on("message",F=>{let T;try{T=JSON.parse(F)}catch{return}if(T.ch==="ctl"&&T.type==="hello_ok"){v=!0,ce=$_,ye=null,A.log(`[plane-link] connected to plane as ${n}`);try{$?.()}catch{}if(typeof T.hashKey=="string"&&T.hashKey)try{l?.(T.hashKey)}catch{}T.minNodeVersion&&dn&&$c(dn,T.minNodeVersion)&&A.error(`[plane-link] this node is bostrat-node ${dn}; the plane asks for \u2265${T.minNodeVersion} \u2014 update with: ${Od(m)}`);try{p?.(typeof T.updatePolicy=="string"?T.updatePolicy:null)}catch{}let j=typeof T.latestNodeVersion=="string"?T.latestNodeVersion:null;if(j&&dn&&$c(dn,j)&&!N.has(j)){N.add(j),A.log(`[plane-link] bostrat-node ${j} is available (this node runs ${dn}) \u2014 ${Od(m)}`);try{d?.({current:dn,latest:j,min:T.minNodeVersion??null,installKind:m,required:!!(T.minNodeVersion&&$c(dn,T.minNodeVersion))})}catch(xe){A.error(`[plane-link] update notice failed: ${xe?.message||xe}`)}}let Y=T.ingest==="http";B=O==="ws"?"ws":O==="http"||Y?"http":"ws",O==="http"&&!Y&&A.error("[plane-link] BOSTRAT_PLANE_INGEST=http but this plane offers no HTTPS ingest door \u2014 events will fail until it does"),B==="http"&&A.log("[plane-link] spine rides the HTTPS ingest door"),Pe=!1,Ce=0,gt=to,qe&&clearInterval(qe),qe=setInterval(()=>{it({v:ut,ch:"ctl",type:"ping"}),Gy(),vO().catch(()=>{}),Tp(),gn.length&&!k&&Ap()},P),qe.unref?.(),SO(),TO().catch(xe=>A.error("[plane-link] backfill failed:",xe?.message||xe));return}if(T.ch==="ctl"&&T.type==="hello_refused"){let j=typeof T.minNodeVersion=="string"?T.minNodeVersion:null,Y=typeof T.latestNodeVersion=="string"?T.latestNodeVersion:null;A.error(`[plane-link] plane REFUSED this node: bostrat-node ${dn??"?"} is below its minimum ${j??"?"} \u2014 ${T.fix||Od(m)}`),ce=R_,ye=0;try{f?.({current:dn,min:j,latest:Y,fix:T.fix||Od(m),installKind:m})}catch(xe){A.error(`[plane-link] refusal handler failed: ${xe?.message||xe}`)}return}if(T.ch==="ctl"&&T.type==="update_policy"){try{p?.(typeof T.mode=="string"?T.mode:null)}catch{}return}if(T.ch==="ctl"&&T.type==="usage_caps"){mu(T.caps??{},{source:"plane",updatedAt:T.updatedAt??Date.now()}).then(j=>A.log(`[plane-link] spend caps ${Object.keys(j.caps).length?`updated (${Object.keys(j.caps).join(", ")})`:"cleared"} from plane`)).catch(j=>A.error("[plane-link] spend-caps push rejected:",j?.message||j));return}if(T.ch==="ctl"&&T.type==="transferred"&&Array.isArray(T.tracks)){Promise.resolve().then(()=>a?.(T.tracks)).catch(j=>A.error("[plane-link] transfer notice failed:",j?.message||j));return}if(T.ch==="events"&&T.type==="ack"&&Array.isArray(T.ids)){Sp(T.ids);return}if(T.ch==="events"&&T.type==="nack"&&Array.isArray(T.ids)){qy(T.ids,T.reason,T.permanent===!0,T.retryAfterMs??null);return}if(T.ch==="control"&&T.type==="http_open"){AO(T).catch(j=>it({v:ut,ch:"control",type:"http_end",reqId:T.reqId,error:j?.message||"tunnel error"}));return}if(T.ch==="control"&&T.type==="http_cancel"){ja.get(T.reqId)?.abort();return}if(T.ch==="attach"&&T.type==="open"){let j=new bg(_+T.path,Array.isArray(T.protocols)?T.protocols:[],T.host?{headers:{host:T.host}}:void 0);U.set(T.streamId,j),z.set(T.streamId,[]),j.on("open",()=>{let xe=z.get(T.streamId)||[];z.delete(T.streamId);for(let{buf:Ee,bin:Ue}of xe)j.send(Ee,{binary:Ue})}),j.on("message",(xe,Ee)=>{let Ue=Ee?xe:Buffer.from(String(xe));it({v:ut,ch:"attach",type:"data",streamId:T.streamId,data:Ue.toString("base64"),...Ee?{bin:!0}:{}})});let Y=()=>{z.delete(T.streamId),U.delete(T.streamId)&&it({v:ut,ch:"attach",type:"close",streamId:T.streamId})};j.on("close",Y),j.on("error",Y);return}if(T.ch==="attach"&&T.type==="data"){let j=U.get(T.streamId);if(!j)return;let Y=Buffer.from(T.data,"base64"),xe=T.bin===!0,Ee=z.get(T.streamId);Ee?Ee.push({buf:Y,bin:xe}):j.send(Y,{binary:xe});return}if(T.ch==="attach"&&T.type==="close"){let j=U.get(T.streamId);U.delete(T.streamId),z.delete(T.streamId),j?.close();return}});let L=()=>{v&&A.log("[plane-link] disconnected from plane"),v=!1,qe&&(clearInterval(qe),qe=null),rt&&(clearInterval(rt),rt=null),te.clear(),W={},gn=[],k&&(clearTimeout(k),k=null),gr.clear();for(let j of U.values())j.close();U.clear(),z.clear();for(let j of ja.values())j.abort();if(ja.clear(),D||De)return;ye==null&&(ye=Date.now());let F=Date.now()-ye<n2,T=Math.max(F?r2+Math.random()*o2:ce,Oe-Date.now());De=setTimeout(()=>{De=null,Yy()},T),De.unref?.(),F||(ce=Math.min(ce*2,R_))};h.on("close",L),h.on("error",F=>{let T=/Unexpected server response: (\d+)/.exec(F?.message||"")?.[1];(T==="401"||T==="403")&&Date.now()-sl>=M_&&(sl=Date.now(),A.error(`[plane-link] plane refused this node's credentials (HTTP ${T}) \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)`)),L()})}return ot.on("event",Jy),wO().then(Yy),{stop:()=>{D=!0,ot.off("event",Jy),De&&clearTimeout(De),St&&clearTimeout(St),qe&&clearInterval(qe),rt&&clearInterval(rt),k&&clearTimeout(k),it({v:ut,ch:"ctl",type:"bye",reason:"shutdown"}),h?.close()},status:()=>({connected:v,nodeId:n,cursor:{...Ae},inflight:te.size,...zy()}),_tick:()=>{Gy(),Tp()}}}Fl();var Md=(()=>{try{return h2(import.meta.url)("../package.json").version||null}catch{return null}})(),w2=process.env.BOSTRAT_STATE_DIR||dt.join(process.env.HOME||f2.tmpdir(),".bostrat"),j_=dt.join(w2,"self-update"),Nd=dt.join(j_,"status.json"),g2=1440*6e4,y2=6e4,Rc=new Set(["npm-global","git-checkout"]);function L_({kind:e=Qo(),env:t=process.env}={}){let n=String(t.BOSTRAT_UPDATE_POLICY||"").trim();return["auto","prompt","off"].includes(n)?n:Rc.has(e)?e==="git-checkout"||b2(t)?"auto":"prompt":"off"}function b2(e=process.env){return!!(e.INVOCATION_ID||e.XPC_SERVICE_NAME&&e.XPC_SERVICE_NAME!=="0")}var jt=e=>`'${String(e).replace(/'/g,"'\\''")}'`;function k2({kind:e,to:t,from:n=Md,statusFile:r=Nd,logFile:o=dt.join(j_,"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||dt.resolve(dt.dirname(new URL(import.meta.url).pathname),"..",".."),startedAt:u=Date.now()}={}){if(!Rc.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,b="")=>`write_status ${jt(g)} ${b}`,p=process.platform==="darwin"?`launchctl kickstart -k gui/${c}/${i}`:`systemctl --user restart ${jt(i)}`,f=`
653
653
  health() {
654
654
  for i in $(seq 1 45); do
655
655
  sleep 1
@@ -660,20 +660,20 @@ health() {
660
660
  # bostrat-node self-update one-shot \u2014 written by agent/src/self-update.js.
661
661
  # ${n??"?"} \u2192 ${t} (${e}). Status: ${r}
662
662
  set -u
663
- FROM=${Bt(n??"")}
664
- TO=${Bt(t)}
665
- STATUS_FILE=${Bt(r)}
663
+ FROM=${jt(n??"")}
664
+ TO=${jt(t)}
665
+ STATUS_FILE=${jt(r)}
666
666
  STARTED_AT=${Number(u)}
667
667
  write_status() { # <status> [error]
668
668
  local err="\${2:-}"
669
669
  err="\${err//\\\\/\\\\\\\\}"; err="\${err//\\"/\\\\\\"}"
670
670
  printf '{"status":"%s","from":"%s","to":"%s","kind":"%s","startedAt":%s,"updatedAt":%s%s}\\n' \\
671
- "$1" "$FROM" "$TO" ${Bt(e)} "$STARTED_AT" "$(date +%s000)" \\
671
+ "$1" "$FROM" "$TO" ${jt(e)} "$STARTED_AT" "$(date +%s000)" \\
672
672
  "\${err:+,\\"error\\":\\"$err\\"}" > "$STATUS_FILE.tmp" && mv "$STATUS_FILE.tmp" "$STATUS_FILE"
673
673
  }
674
674
  ${f}
675
- `;if(e==="npm-global"){let g=a?dt.join(a,"bin","npm"):"npm",b=a?`export PATH=${Bt(dt.join(a,"bin"))}:"$PATH"
676
- `:"",x=a?` --prefix ${Bt(a)}`:"",y=$=>`${Bt(g)} install -g "bostrat-node@${$}" --no-audit --no-fund${x}`;return w+b+`
675
+ `;if(e==="npm-global"){let g=a?dt.join(a,"bin","npm"):"npm",b=a?`export PATH=${jt(dt.join(a,"bin"))}:"$PATH"
676
+ `:"",x=a?` --prefix ${jt(a)}`:"",y=$=>`${jt(g)} install -g "bostrat-node@${$}" --no-audit --no-fund${x}`;return w+b+`
677
677
  ${d("updating",'"" ')}
678
678
  if ! ${y("$TO")}; then
679
679
  ${d("failed",'"npm install failed"')}
@@ -696,8 +696,8 @@ if [ -n "$FROM" ] && ${y("$FROM")} && ${p} && health; then
696
696
  fi
697
697
  ${d("failed",'"agent did not answer after the update AND the rollback"')}
698
698
  exit 1
699
- `}let m=g=>`( cd ${Bt(l)} && git fetch -q origin main --tags && git show origin/main:scripts/deploy-pi.sh > "$TMP_SCRIPT" && bash "$TMP_SCRIPT" "v${g}" )`;return w+`
700
- LIVE=${Bt(l)}
699
+ `}let m=g=>`( cd ${jt(l)} && git fetch -q origin main --tags && git show origin/main:scripts/deploy-pi.sh > "$TMP_SCRIPT" && bash "$TMP_SCRIPT" "v${g}" )`;return w+`
700
+ LIVE=${jt(l)}
701
701
  TMP_SCRIPT="$(mktemp)"
702
702
  trap 'rm -f "$TMP_SCRIPT"' EXIT
703
703
  # "restarting" is written BEFORE deploy-pi.sh runs (it does fetch \u2192 build \u2192
@@ -714,65 +714,65 @@ if [ -n "$FROM" ] && ${m("$FROM")}; then
714
714
  fi
715
715
  ${d("failed",'"deploy-pi.sh v$TO failed AND the rollback failed"')}
716
716
  exit 1
717
- `}async function Oc(e=Md){try{return JSON.parse(await no.readFile(e,"utf8"))}catch{return null}}var k2=new Set(["updating","restarting","rolling-back"]),Nd=e=>!!(e&&k2.has(e.status));async function Pd({to:e,from:t=Cd,kind:n=Qo(),reason:r="manual",statusFile:o=Md,spawnImpl:s=f2,now:a=Date.now,npmPrefix:i=void 0,log:c=console}={}){if(!e)return{ok:!1,reason:"no target version"};if(!Rc.has(n))return{ok:!1,reason:`install kind "${n}" updates elsewhere`};if(t&&!$c(t,e))return{ok:!1,reason:`already on ${t} (target ${e})`};let l=await Oc(o);if(Nd(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 no.mkdir(dt.dirname(o),{recursive:!0});let u=i!==void 0?i:n==="npm-global"?kf(await x2())||dt.resolve(dt.dirname(process.execPath),".."):null,d=b2({kind:n,to:e,from:t,statusFile:o,npmPrefix:u,startedAt:a()}),p=dt.join(dt.dirname(o),`update-${e}.sh`),f=dt.join(dt.dirname(o),"last.log");await no.writeFile(p,d,{mode:448}),await no.writeFile(o,JSON.stringify({status:"updating",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a()}));let w=D_.existsSync("/run/systemd/system")&&await v2("systemd-run")?["systemd-run",["--user","--collect","--quiet",`--unit=bostrat-self-update-${e}`,"--property=KillMode=process","bash",p]]:["setsid",["-f","bash","-c",`exec bash ${Bt(p)} >> ${Bt(f)} 2>&1`]];try{s(w[0],w[1],{detached:!0,stdio:"ignore"}).unref?.()}catch(m){return await no.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 x2(){try{return await no.realpath(new URL(import.meta.url).pathname)}catch{return""}}async function v2(e){for(let t of String(process.env.PATH||"").split(dt.delimiter))try{return await no.access(dt.join(t,e),D_.constants.X_OK),!0}catch{}return!1}var S2=45*6e4;async function L_({statusFile:e=Md,current:t=Cd,now:n=Date.now,staleMs:r=S2}={}){let o=await Oc(e);if(!o)return null;let s=a=>no.writeFile(e,JSON.stringify(a)).catch(()=>{});if(Nd(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 F_({isBusy:e,start:t=Pd,onStuck:n=null,onStarted:r=null,tickMs:o=g2,stuckMs:s=w2,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=Cd,kind:m=Qo()}){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}}}de();pt();var U_=(...e)=>fetch(...e);function H_(e=process.env){return!!($e(e)&&e.BOSTRAT_PLANE_TOKEN)}async function kg(e=process.env){if(!H_(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 U_(`${$e(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 xg(e=process.env){if(!H_(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 U_(`${$e(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 va(e,t=process.env){let n=String(e??"").trim();if(!n)throw new Error("a circuit name or id is required");let r=await kg(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 Dd(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}})}de();pt();var T2=(...e)=>fetch(...e);async function jd(e,t,n,r=process.env){if(!($e(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 T2(`${$e(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 A2(e,t=process.env){return jd("POST","/v1/circuits",{name:e},t).then(n=>n.circuit)}async function W_({circuitRef:e,newCircuitName:t,name:n,markdown:r},o=process.env){let s=t?await A2(t,o):await va(e,o),a=await jd("POST","/v1/blueprints",{circuitId:s.id,name:n,markdown:r},o);return{circuit:s,...a}}async function vg(e,t=process.env){let n=await va(e,t),r=await jd("GET",`/v1/blueprints/${encodeURIComponent(n.id)}`,null,t);return{circuit:n,...r}}async function Sg(e,t=process.env){return(await jd("GET","/v1/circuits",null,t)).memberships?.[e]??null}async function q_(e,t,n,r=process.env){let{blueprint:o,items:s}=await vg(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}}de();pt();var E2=(...e)=>fetch(...e);async function _2(e,t,n,r=process.env){if(!($e(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 E2(`${$e(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 K_=72,Tg=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>K_)throw new Error(`the title is the choice as a LABEL \u2014 ${K_} 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 ${Tg} chars) a reader can act on without opening the record`);if(c.length>Tg)throw new Error(`the summary is one sentence \u2014 ${Tg} 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 z_(e,t=process.env){return _2("GET",`/v1/decisions?track=${encodeURIComponent(e)}`,null,t)}sw();de();import jc from"node:fs/promises";import Gd from"node:path";import yH from"node:os";vr();import I2 from"node:fs/promises";import V_ from"node:path";import $2 from"node:os";var J_=()=>V_.join(process.env.BOSTRAT_STATE_DIR||V_.join(process.env.HOME||$2.tmpdir(),".bostrat"),"integrations.json");async function hr(){try{return JSON.parse(await I2.readFile(J_(),"utf8"))||{}}catch{return{}}}var Bd=["linked","prOpened","prMerged","create"],Ag=["prompt","auto","off"],R2={create:["prompt","off"]},Y_=e=>R2[e]??Ag;function Ld(e){let t=e.linear||{},n=t.transitions===!0?"auto":"prompt",r={};for(let o of Bd){let s=Y_(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 es(){let e=await hr(),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:Ld(e),defaultTeam:n}:null}async function Fd(){let e=await hr(),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:Ld(e)}}async function Eg(){return Ld(await hr())}async function X_(e){let t=Object.entries(e||{});if(!t.length)throw new Error(`nothing to set \u2014 phases: ${Bd.join(", ")}`);for(let[r,o]of t){if(!Bd.includes(r))throw new Error(`unknown phase "${r}" \u2014 configurable phases: ${Bd.join(", ")}`);let s=Y_(r);if(!s.includes(o))throw new Error(s.length<Ag.length?`mode "${o}" not allowed for "${r}" \u2014 ${r} is always confirmed (modes: ${s.join(", ")})`:`unknown mode "${o}" \u2014 modes: ${Ag.join(", ")}`)}let n=await hr();return n.ticketFlow={...Ld(n),...Object.fromEntries(t)},n.linear&&(delete n.linear.ticketFlow,delete n.linear.transitions),await Et(J_(),n,{mode:384}),n.ticketFlow}async function Cc(){let e=(await hr()).deepgram||{},t=process.env.DEEPGRAM_API_KEY||e.apiKey;return t?{apiKey:t}:null}async function O2(){let e=(await hr()).openai||{},t=process.env.BOSTRAT_OPENAI_API_KEY||e.apiKey;return t?{apiKey:t}:null}var C2={openai:{model:"gpt-realtime-2.1-mini",voice:"marin"}};async function Ud(){let t=(await hr()).voiceChat||{},n=t.provider||"openai",r=C2[n];if(!r)return null;let o=n==="openai"?await O2():null;return o?{provider:n,model:t.model||r.model,voice:t.voice||r.voice,apiKey:o.apiKey}:null}async function Z_(){let e=(await hr()).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 ts(){let e=(await hr()).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}}de();Tr();Pr();ca();import Nc from"node:fs/promises";import iI from"node:path";import rH from"node:os";import{randomUUID as cI}from"node:crypto";var Ig={};Ap(Ig,{createComment:()=>U2,findIssueUrl:()=>D2,issueStates:()=>q2,mdToAdf:()=>tI,moveIssue:()=>K2,parseIssueRef:()=>P2,resolveIssue:()=>j2,uploadImage:()=>H2,upsertCard:()=>B2,whoami:()=>_g});var Sa=e=>String(e.baseUrl||"").replace(/\/$/,""),eI=e=>`Basic ${Buffer.from(`${e.email}:${e.apiToken}`).toString("base64")}`;async function ns(e,t,n,r){let o=await fetch(`${Sa(e)}${n}`,{method:t,headers:{authorization:eI(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 M2=/\/browse\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,N2=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function P2(e){let t=String(e||"").trim();if(/^https?:\/\//i.test(t)){let r=t.match(M2);return r?r[1].toUpperCase():null}let n=t.match(N2);return n?n[1]:null}function D2(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 j2(e,t){let n;try{n=await ns(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:`${Sa(e)}/browse/${n.key}`,state:n.fields?.status?.name??null}}async function B2(e,t,{url:n,title:r,subtitle:o}){await ns(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 L2=/(!\[[^\]]*\]\([^)\s]+\)|\*\*[^*\n]+\*\*|`[^`\n]+`|_[^_\n]+_|https?:\/\/[^\s)]+)/g;function F2(e){let t=[],n=0;for(let r of e.matchAll(L2)){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 tI(e){let t=String(e??"").split(/\n{2,}/).map(n=>n.trim()).filter(Boolean).map(n=>{let r=[];return n.split(`
718
- `).forEach((o,s)=>{s>0&&r.push({type:"hardBreak"}),r.push(...F2(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 U2(e,t,n){let r=await ns(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/comment`,{body:tI(n)});return r?.id?`${Sa(e)}/browse/${t.key}?focusedCommentId=${r.id}`:null}async function _g(e){let t=await ns(e,"GET","/rest/api/3/myself"),n=null;try{n=new URL(Sa(e)).host}catch{n=e.baseUrl??null}return{user:t?.displayName??t?.emailAddress??null,org:n}}async function H2(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(`${Sa(e)}/rest/api/3/issue/${encodeURIComponent(t)}/attachments`,{method:"POST",headers:{authorization:eI(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??`${Sa(e)}/rest/api/3/attachment/content/${c.id}`}var W2={new:"unstarted",indeterminate:"started",done:"completed"},Q_=e=>W2[e?.key]??"started";async function q2(e,t){let n=encodeURIComponent(t.key),[r,o]=await Promise.all([ns(e,"GET",`/rest/api/3/issue/${n}?fields=status`),ns(e,"GET",`/rest/api/3/issue/${n}/transitions`)]),s=r?.fields?.status??null,a=s?{id:`status:${s.id}`,name:s.name,type:Q_(s.statusCategory)}:null,i=(o?.transitions??[]).map((c,l)=>({id:c.id,name:c.to?.name??c.name,type:Q_(c.to?.statusCategory),position:l}));return{current:a,states:i}}async function K2(e,t,n){await ns(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/transitions`,{transition:{id:String(n)}})}var Cg={};Ap(Cg,{createComment:()=>Q2,createIssue:()=>Og,createProject:()=>Rg,findIssueUrl:()=>Y2,issueStates:()=>tH,moveIssue:()=>nH,parseIssueRef:()=>J2,resolveIssue:()=>X2,teams:()=>Ta,uploadImage:()=>eH,upsertCard:()=>Z2,whoami:()=>$g});var G2=()=>process.env.BOSTRAT_LINEAR_API_URL||"https://api.linear.app/graphql";async function Ln(e,t,n={}){let r=await fetch(G2(),{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 z2=/linear\.app\/[^/\s]+\/issue\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,V2=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function J2(e){let t=String(e||"").trim(),n=t.match(z2);if(n)return n[1].toUpperCase();let r=t.match(V2);return r?r[1]:null}function Y2(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 X2(e,t){let r=(await Ln(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 Z2(e,t,{url:n,title:r,subtitle:o}){let s=await Ln(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 Q2(e,t,n){let r=await Ln(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 $g(e){let t=await Ln(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 eH(e,{filename:t,contentType:n,buffer:r}){let o=await Ln(e,`mutation($contentType: String!, $filename: String!, $size: Int!) {
717
+ `}async function Oc(e=Nd){try{return JSON.parse(await no.readFile(e,"utf8"))}catch{return null}}var x2=new Set(["updating","restarting","rolling-back"]),Pd=e=>!!(e&&x2.has(e.status));async function Dd({to:e,from:t=Md,kind:n=Qo(),reason:r="manual",statusFile:o=Nd,spawnImpl:s=m2,now:a=Date.now,npmPrefix:i=void 0,log:c=console}={}){if(!e)return{ok:!1,reason:"no target version"};if(!Rc.has(n))return{ok:!1,reason:`install kind "${n}" updates elsewhere`};if(t&&!$c(t,e))return{ok:!1,reason:`already on ${t} (target ${e})`};let l=await Oc(o);if(Pd(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 no.mkdir(dt.dirname(o),{recursive:!0});let u=i!==void 0?i:n==="npm-global"?xf(await v2())||dt.resolve(dt.dirname(process.execPath),".."):null,d=k2({kind:n,to:e,from:t,statusFile:o,npmPrefix:u,startedAt:a()}),p=dt.join(dt.dirname(o),`update-${e}.sh`),f=dt.join(dt.dirname(o),"last.log");await no.writeFile(p,d,{mode:448}),await no.writeFile(o,JSON.stringify({status:"updating",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a()}));let w=B_.existsSync("/run/systemd/system")&&await S2("systemd-run")?["systemd-run",["--user","--collect","--quiet",`--unit=bostrat-self-update-${e}`,"--property=KillMode=process","bash",p]]:["setsid",["-f","bash","-c",`exec bash ${jt(p)} >> ${jt(f)} 2>&1`]];try{s(w[0],w[1],{detached:!0,stdio:"ignore"}).unref?.()}catch(m){return await no.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 v2(){try{return await no.realpath(new URL(import.meta.url).pathname)}catch{return""}}async function S2(e){for(let t of String(process.env.PATH||"").split(dt.delimiter))try{return await no.access(dt.join(t,e),B_.constants.X_OK),!0}catch{}return!1}var T2=45*6e4;async function F_({statusFile:e=Nd,current:t=Md,now:n=Date.now,staleMs:r=T2}={}){let o=await Oc(e);if(!o)return null;let s=a=>no.writeFile(e,JSON.stringify(a)).catch(()=>{});if(Pd(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 U_({isBusy:e,start:t=Dd,onStuck:n=null,onStarted:r=null,tickMs:o=y2,stuckMs:s=g2,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=Md,kind:m=Qo()}){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}}}de();pt();var H_=(...e)=>fetch(...e);function W_(e=process.env){return!!($e(e)&&e.BOSTRAT_PLANE_TOKEN)}async function xg(e=process.env){if(!W_(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 H_(`${$e(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 vg(e=process.env){if(!W_(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 H_(`${$e(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 va(e,t=process.env){let n=String(e??"").trim();if(!n)throw new Error("a circuit name or id is required");let r=await xg(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 Bd(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}})}de();pt();var A2=(...e)=>fetch(...e);async function jd(e,t,n,r=process.env){if(!($e(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 A2(`${$e(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 E2(e,t=process.env){return jd("POST","/v1/circuits",{name:e},t).then(n=>n.circuit)}async function q_({circuitRef:e,newCircuitName:t,name:n,markdown:r},o=process.env){let s=t?await E2(t,o):await va(e,o),a=await jd("POST","/v1/blueprints",{circuitId:s.id,name:n,markdown:r},o);return{circuit:s,...a}}async function Sg(e,t=process.env){let n=await va(e,t),r=await jd("GET",`/v1/blueprints/${encodeURIComponent(n.id)}`,null,t);return{circuit:n,...r}}async function Tg(e,t=process.env){return(await jd("GET","/v1/circuits",null,t)).memberships?.[e]??null}async function K_(e,t,n,r=process.env){let{blueprint:o,items:s}=await Sg(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}}de();pt();var _2=(...e)=>fetch(...e);async function I2(e,t,n,r=process.env){if(!($e(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 _2(`${$e(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 G_=72,Ag=160;async function z_(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>G_)throw new Error(`the title is the choice as a LABEL \u2014 ${G_} 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 ${Ag} chars) a reader can act on without opening the record`);if(c.length>Ag)throw new Error(`the summary is one sentence \u2014 ${Ag} 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 V_(e,t=process.env){return I2("GET",`/v1/decisions?track=${encodeURIComponent(e)}`,null,t)}aw();de();import Bc from"node:fs/promises";import zd from"node:path";import bH from"node:os";vr();import $2 from"node:fs/promises";import J_ from"node:path";import R2 from"node:os";var Y_=()=>J_.join(process.env.BOSTRAT_STATE_DIR||J_.join(process.env.HOME||R2.tmpdir(),".bostrat"),"integrations.json");async function hr(){try{return JSON.parse(await $2.readFile(Y_(),"utf8"))||{}}catch{return{}}}var Ld=["linked","prOpened","prMerged","create"],Eg=["prompt","auto","off"],O2={create:["prompt","off"]},X_=e=>O2[e]??Eg;function Fd(e){let t=e.linear||{},n=t.transitions===!0?"auto":"prompt",r={};for(let o of Ld){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 es(){let e=await hr(),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:Fd(e),defaultTeam:n}:null}async function Ud(){let e=await hr(),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:Fd(e)}}async function _g(){return Fd(await hr())}async function Z_(e){let t=Object.entries(e||{});if(!t.length)throw new Error(`nothing to set \u2014 phases: ${Ld.join(", ")}`);for(let[r,o]of t){if(!Ld.includes(r))throw new Error(`unknown phase "${r}" \u2014 configurable phases: ${Ld.join(", ")}`);let s=X_(r);if(!s.includes(o))throw new Error(s.length<Eg.length?`mode "${o}" not allowed for "${r}" \u2014 ${r} is always confirmed (modes: ${s.join(", ")})`:`unknown mode "${o}" \u2014 modes: ${Eg.join(", ")}`)}let n=await hr();return n.ticketFlow={...Fd(n),...Object.fromEntries(t)},n.linear&&(delete n.linear.ticketFlow,delete n.linear.transitions),await Et(Y_(),n,{mode:384}),n.ticketFlow}async function Cc(){let e=(await hr()).deepgram||{},t=process.env.DEEPGRAM_API_KEY||e.apiKey;return t?{apiKey:t}:null}async function C2(){let e=(await hr()).openai||{},t=process.env.BOSTRAT_OPENAI_API_KEY||e.apiKey;return t?{apiKey:t}:null}var M2={openai:{model:"gpt-realtime-2.1-mini",voice:"marin"}};async function Hd(){let t=(await hr()).voiceChat||{},n=t.provider||"openai",r=M2[n];if(!r)return null;let o=n==="openai"?await C2():null;return o?{provider:n,model:t.model||r.model,voice:t.voice||r.voice,apiKey:o.apiKey}:null}async function Q_(){let e=(await hr()).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 ts(){let e=(await hr()).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}}de();Tr();Pr();ca();import Nc from"node:fs/promises";import cI from"node:path";import oH from"node:os";import{randomUUID as lI}from"node:crypto";var $g={};Ep($g,{createComment:()=>H2,findIssueUrl:()=>B2,issueStates:()=>K2,mdToAdf:()=>nI,moveIssue:()=>G2,parseIssueRef:()=>D2,resolveIssue:()=>j2,uploadImage:()=>W2,upsertCard:()=>L2,whoami:()=>Ig});var Sa=e=>String(e.baseUrl||"").replace(/\/$/,""),tI=e=>`Basic ${Buffer.from(`${e.email}:${e.apiToken}`).toString("base64")}`;async function ns(e,t,n,r){let o=await fetch(`${Sa(e)}${n}`,{method:t,headers:{authorization:tI(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 N2=/\/browse\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,P2=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function D2(e){let t=String(e||"").trim();if(/^https?:\/\//i.test(t)){let r=t.match(N2);return r?r[1].toUpperCase():null}let n=t.match(P2);return n?n[1]:null}function B2(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 j2(e,t){let n;try{n=await ns(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:`${Sa(e)}/browse/${n.key}`,state:n.fields?.status?.name??null}}async function L2(e,t,{url:n,title:r,subtitle:o}){await ns(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 F2=/(!\[[^\]]*\]\([^)\s]+\)|\*\*[^*\n]+\*\*|`[^`\n]+`|_[^_\n]+_|https?:\/\/[^\s)]+)/g;function U2(e){let t=[],n=0;for(let r of e.matchAll(F2)){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 nI(e){let t=String(e??"").split(/\n{2,}/).map(n=>n.trim()).filter(Boolean).map(n=>{let r=[];return n.split(`
718
+ `).forEach((o,s)=>{s>0&&r.push({type:"hardBreak"}),r.push(...U2(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 H2(e,t,n){let r=await ns(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/comment`,{body:nI(n)});return r?.id?`${Sa(e)}/browse/${t.key}?focusedCommentId=${r.id}`:null}async function Ig(e){let t=await ns(e,"GET","/rest/api/3/myself"),n=null;try{n=new URL(Sa(e)).host}catch{n=e.baseUrl??null}return{user:t?.displayName??t?.emailAddress??null,org:n}}async function W2(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(`${Sa(e)}/rest/api/3/issue/${encodeURIComponent(t)}/attachments`,{method:"POST",headers:{authorization:tI(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??`${Sa(e)}/rest/api/3/attachment/content/${c.id}`}var q2={new:"unstarted",indeterminate:"started",done:"completed"},eI=e=>q2[e?.key]??"started";async function K2(e,t){let n=encodeURIComponent(t.key),[r,o]=await Promise.all([ns(e,"GET",`/rest/api/3/issue/${n}?fields=status`),ns(e,"GET",`/rest/api/3/issue/${n}/transitions`)]),s=r?.fields?.status??null,a=s?{id:`status:${s.id}`,name:s.name,type:eI(s.statusCategory)}:null,i=(o?.transitions??[]).map((c,l)=>({id:c.id,name:c.to?.name??c.name,type:eI(c.to?.statusCategory),position:l}));return{current:a,states:i}}async function G2(e,t,n){await ns(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/transitions`,{transition:{id:String(n)}})}var Mg={};Ep(Mg,{createComment:()=>eH,createIssue:()=>Cg,createProject:()=>Og,findIssueUrl:()=>X2,issueStates:()=>nH,moveIssue:()=>rH,parseIssueRef:()=>Y2,resolveIssue:()=>Z2,teams:()=>Ta,uploadImage:()=>tH,upsertCard:()=>Q2,whoami:()=>Rg});var z2=()=>process.env.BOSTRAT_LINEAR_API_URL||"https://api.linear.app/graphql";async function Ln(e,t,n={}){let r=await fetch(z2(),{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 V2=/linear\.app\/[^/\s]+\/issue\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,J2=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function Y2(e){let t=String(e||"").trim(),n=t.match(V2);if(n)return n[1].toUpperCase();let r=t.match(J2);return r?r[1]:null}function X2(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 Z2(e,t){let r=(await Ln(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 Q2(e,t,{url:n,title:r,subtitle:o}){let s=await Ln(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 eH(e,t,n){let r=await Ln(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 Rg(e){let t=await Ln(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 tH(e,{filename:t,contentType:n,buffer:r}){let o=await Ln(e,`mutation($contentType: String!, $filename: String!, $size: Int!) {
719
719
  fileUpload(contentType: $contentType, filename: $filename, size: $size) {
720
720
  success
721
721
  uploadFile { uploadUrl assetUrl headers { key value } }
722
722
  }
723
- }`,{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 tH(e,t){let n=await Ln(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 nH(e,t,n){if(!(await Ln(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 Ta(e){return((await Ln(e,"query { teams(first: 100) { nodes { id key name } } }")).teams?.nodes??[]).map(n=>({id:n.id,key:n.key,name:n.name}))}var nI=255;async function Rg(e,{teamId:t,name:n,description:r}){let o=r||null,s=!!o&&o.length>nI,a=s?`${o.slice(0,nI-1).trimEnd()}\u2026`:o,i=await Ln(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 Og(e,{teamId:t,title:n,description:r,projectId:o,priority:s}){let a=await Ln(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}}Ki();var lI={linear:{api:Cg,config:es},jira:{api:Ig,config:Fd}};async function Lg(){let e=[];for(let[t,{api:n,config:r}]of Object.entries(lI)){let o=await r();o&&e.push({name:t,api:n,cfg:o})}return e}async function rs(e){let t=lI[e?.provider];if(!t)return null;let n=await t.config();return n?{name:e.provider,api:t.api,cfg:n}:null}function Fg(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 uI=()=>process.env.BOSTRAT_STATE_DIR||iI.join(process.env.HOME||rH.tmpdir(),".bostrat"),Dg=()=>iI.join(uI(),"tickets.json"),dI=()=>(process.env.BOSTRAT_PUBLIC_URL||"http://bostrat.globopi").replace(/\/$/,""),Hd=e=>`${dI()}/track/${e}`,ro=null,Mg=null,Ng=Promise.resolve();async function Dc(){return ro||(Mg??=Nc.readFile(Dg(),"utf8").then(e=>({tickets:JSON.parse(e)?.tickets??{},existed:!0})).catch(()=>({tickets:{},existed:!1})).then(async({tickets:e,existed:t})=>{if(ro=e,!t&&Fe()){let{records:n,source:r}=await st("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;ro[s]=i}Object.keys(ro).length&&await jg().catch(()=>{})}}return ro}).finally(()=>Mg=null),Mg)}async function jg(){let e=JSON.stringify({tickets:ro},null,2),t=`${Dg()}.${process.pid}.tmp`;await Nc.mkdir(uI(),{recursive:!0}),await Nc.writeFile(t,e),await Nc.rename(t,Dg())}async function oo(e=null){if(Ng=Ng.then(jg,jg),await Ng.catch(()=>{}),!e)return;let t=ro?.[e];t?yt("tickets",{id:e,updatedAt:Date.now(),...t},{trackId:e}).catch(()=>{}):Zt("tickets",e).catch(()=>{})}async function Fn(e){return(await Dc())[e]??null}async function pI(){return{...await Dc()}}async function fI(){return(await Lg()).length>0}async function Aa(e,t,{source:n="api"}={}){let r=await Lg();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 Dc())[e.id]=c,await oo(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 Pc(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 Mc(c,`**Bostrat** \u2014 Track **${c.track.name}** linked${l.length?` (${l.join(", ")})`:""}.`),await wI(e.id,c,"linked"),c}async function Ug(e){let t=await Dc();return t[e]?(delete t[e],await oo(e),!0):!1}var Bg=e=>`$${e>=100?Math.round(e):e.toFixed(2)}`;async function mI(e,t){if(!e.track?.cwd)return null;let n=Nr(await K({id:t,cwd:e.track.cwd}));return!n.totalUsd||n.totalUsd<.01?null:n}function oH(e){let t=Object.entries(e.byProvider).sort((r,o)=>o[1].usd-r[1].usd).map(([r,o])=>`${r} ${Bg(o.usd)}`).join(" \xB7 "),n=Object.keys(e.byBox).length;return`${Bg(e.totalUsd)}${t?` (${t})`:""}${n>1?` across ${n} boxes`:""}`}function sH(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(Bg(t.totalUsd)),n.join(" \xB7 ")||"linked"}async function Pc(e,t){let n=await rs(t);if(!n)return;let r=await mI(t,e).catch(()=>null);await n.api.upsertCard(n.cfg,t,{url:Hd(e),title:`Bostrat Track: ${t.track.name}`,subtitle:sH(t,r)})}function Wd(e){let t=new URL(dI());return`${t.protocol}//${e}.${t.host}/`}var aH={linked:"linked",opened:"prOpened",merged:"prMerged"};function iH(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 hI(e,t,{from:n,to:r,mode:o,phase:s=null,actor:a="user"}){t.state=r,await oo(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 wI(e,t,n){let r=await rs(t);if(!r)return;let o=r.cfg.ticketFlow?.[aH[n]]??"prompt";if(o==="off")return;let{current:s,states:a}=await r.api.issueStates(r.cfg,t),i=Fg(s,a),c=iH(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 hI(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:cI(),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 gI(e){let t=await Fn(e);if(!t)throw new Error("no ticket linked to this Track");let n=await rs(t);if(!n)throw new Error("no ticketing integration configured");let{current:r,states:o}=await n.api.issueStates(n.cfg,t),s=Fg(r,o);return s?.name&&t.state!==s.name&&(t.state=s.name,await oo(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 Hg(e,t,{mode:n="manual"}={}){if(!t)throw new Error("stateId required");let r=await Fn(e);if(!r)throw new Error("no ticket linked to this Track");let o=await rs(r);if(!o)throw new Error("no ticketing integration configured");let{current:s,states:a}=await o.api.issueStates(o.cfg,r),i=Fg(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 oo(e)),{key:r.key,from:l,to:c.name,moved:!1}):(await o.api.moveIssue(o.cfg,r,c.id),await hI(e,r,{from:l,to:c.name,mode:n}),{key:r.key,from:l,to:c.name,moved:!0})}async function yI(e,t){let n=await Fn(e);if(!n)throw new Error("no ticket linked to this Track");let r=await rs(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 bI(e,t,n){if(!t)throw new Error("offerId required");return Jr(`tkt:${e.id}:${t}`,()=>cH(e,t,n))}async function cH(e,t,n){let r=await K({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 Hg(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 rI=50;async function kI(){let e=await es();if(!e)throw new Error("no ticketing integration configured");return Ta(e)}function lH(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>rI)throw new Error(`too many issues (${n.length}); cap is ${rI} per proposal`);return{epic:r,issues:n,team:t.team?String(t.team).trim():null,linkCurrentTrack:t.linkCurrentTrack===!0}}async function uH(e,t,n,r){let o=r??await Ta(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 Fn(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 xI(e,t){let n=await es();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=lH(t),o=await Ta(n),s=await uH(n,r,e,o),a=s?{id:s.id,key:s.key,name:s.name}:null,i=cI();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 vI(e,t,n,{teamId:r=null}={}){if(!t)throw new Error("proposalId required");let o=await K({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 es();if(!a)throw new Error("no ticketing integration configured");let i=s.payload,c=i.team??null;if(!c&&r){let w=(await Ta(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 Rg(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 Og(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 Fn(e.id)&&(f=await Aa(e,p[0].key,{source:"created"}).catch(()=>null)),{proposalId:t,action:"created",created:l,failed:u,linked:f?f.key:null}}async function Mc(e,t){let n=await rs(e);n&&await n.api.createComment(n.cfg,e,t)}async function dH(e,t,n){let r=await rs(e);if(!r)return null;let o=await cr(t);if(!o)return null;let s=an(o,n);if(!s)return null;let a=await Nc.readFile(zt(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 oI=()=>Number(process.env.BOSTRAT_TICKET_COST_SYNC_MS??12e4),Pg=new Map;function pH(e,t){if(oI()<=0)return Pc(e,t);if(Pg.has(e))return;let n=setTimeout(()=>{Pg.delete(e),Fn(e).then(r=>r?Pc(e,r):null).catch(()=>{})},oI());n.unref?.(),Pg.set(e,n)}var sI=new Map;async function aI(e,t,n){let r=sI.get(e)??0;Date.now()-r<600*1e3||(sI.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 fH(e,{resolveTrack:t=null}={}){let n=await Fn(e.trackId),r=e.payload||{};if(!n){if(e.type!=="turn.user"||e.actor!=="user")return;let o=null;for(let a of await Lg())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 Aa(s,o,{source:"chat"})}catch(a){await aI(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 oo(e.trackId))}try{switch(e.type){case"handoff.done":n.track.leadAgent=r.toAgent??n.track.leadAgent,await oo(e.trackId),await Pc(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 oo(e.trackId),await Pc(e.trackId,n),r.change==="opened"||r.change==="merged"){let o=r.change==="merged"?await mI(n,e.trackId).catch(()=>null):null;await Mc(n,`**Bostrat** \u2014 PR ${r.change} for **${n.track.name}**${r.url?`: ${r.url}`:r.number?` (#${r.number})`:""}`+(o?`
723
+ }`,{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 nH(e,t){let n=await Ln(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 rH(e,t,n){if(!(await Ln(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 Ta(e){return((await Ln(e,"query { teams(first: 100) { nodes { id key name } } }")).teams?.nodes??[]).map(n=>({id:n.id,key:n.key,name:n.name}))}var rI=255;async function Og(e,{teamId:t,name:n,description:r}){let o=r||null,s=!!o&&o.length>rI,a=s?`${o.slice(0,rI-1).trimEnd()}\u2026`:o,i=await Ln(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 Cg(e,{teamId:t,title:n,description:r,projectId:o,priority:s}){let a=await Ln(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}}Ki();var uI={linear:{api:Mg,config:es},jira:{api:$g,config:Ud}};async function Fg(){let e=[];for(let[t,{api:n,config:r}]of Object.entries(uI)){let o=await r();o&&e.push({name:t,api:n,cfg:o})}return e}async function rs(e){let t=uI[e?.provider];if(!t)return null;let n=await t.config();return n?{name:e.provider,api:t.api,cfg:n}:null}function Ug(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 dI=()=>process.env.BOSTRAT_STATE_DIR||cI.join(process.env.HOME||oH.tmpdir(),".bostrat"),Bg=()=>cI.join(dI(),"tickets.json"),pI=()=>(process.env.BOSTRAT_PUBLIC_URL||"http://bostrat.globopi").replace(/\/$/,""),Wd=e=>`${pI()}/track/${e}`,ro=null,Ng=null,Pg=Promise.resolve();async function Dc(){return ro||(Ng??=Nc.readFile(Bg(),"utf8").then(e=>({tickets:JSON.parse(e)?.tickets??{},existed:!0})).catch(()=>({tickets:{},existed:!1})).then(async({tickets:e,existed:t})=>{if(ro=e,!t&&Fe()){let{records:n,source:r}=await st("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;ro[s]=i}Object.keys(ro).length&&await jg().catch(()=>{})}}return ro}).finally(()=>Ng=null),Ng)}async function jg(){let e=JSON.stringify({tickets:ro},null,2),t=`${Bg()}.${process.pid}.tmp`;await Nc.mkdir(dI(),{recursive:!0}),await Nc.writeFile(t,e),await Nc.rename(t,Bg())}async function oo(e=null){if(Pg=Pg.then(jg,jg),await Pg.catch(()=>{}),!e)return;let t=ro?.[e];t?yt("tickets",{id:e,updatedAt:Date.now(),...t},{trackId:e}).catch(()=>{}):Zt("tickets",e).catch(()=>{})}async function Fn(e){return(await Dc())[e]??null}async function fI(){return{...await Dc()}}async function mI(){return(await Fg()).length>0}async function Aa(e,t,{source:n="api"}={}){let r=await Fg();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 Dc())[e.id]=c,await oo(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 Pc(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 Mc(c,`**Bostrat** \u2014 Track **${c.track.name}** linked${l.length?` (${l.join(", ")})`:""}.`),await gI(e.id,c,"linked"),c}async function Hg(e){let t=await Dc();return t[e]?(delete t[e],await oo(e),!0):!1}var Lg=e=>`$${e>=100?Math.round(e):e.toFixed(2)}`;async function hI(e,t){if(!e.track?.cwd)return null;let n=Nr(await K({id:t,cwd:e.track.cwd}));return!n.totalUsd||n.totalUsd<.01?null:n}function sH(e){let t=Object.entries(e.byProvider).sort((r,o)=>o[1].usd-r[1].usd).map(([r,o])=>`${r} ${Lg(o.usd)}`).join(" \xB7 "),n=Object.keys(e.byBox).length;return`${Lg(e.totalUsd)}${t?` (${t})`:""}${n>1?` across ${n} boxes`:""}`}function aH(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(Lg(t.totalUsd)),n.join(" \xB7 ")||"linked"}async function Pc(e,t){let n=await rs(t);if(!n)return;let r=await hI(t,e).catch(()=>null);await n.api.upsertCard(n.cfg,t,{url:Wd(e),title:`Bostrat Track: ${t.track.name}`,subtitle:aH(t,r)})}function qd(e){let t=new URL(pI());return`${t.protocol}//${e}.${t.host}/`}var iH={linked:"linked",opened:"prOpened",merged:"prMerged"};function cH(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 wI(e,t,{from:n,to:r,mode:o,phase:s=null,actor:a="user"}){t.state=r,await oo(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 gI(e,t,n){let r=await rs(t);if(!r)return;let o=r.cfg.ticketFlow?.[iH[n]]??"prompt";if(o==="off")return;let{current:s,states:a}=await r.api.issueStates(r.cfg,t),i=Ug(s,a),c=cH(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 wI(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:lI(),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 yI(e){let t=await Fn(e);if(!t)throw new Error("no ticket linked to this Track");let n=await rs(t);if(!n)throw new Error("no ticketing integration configured");let{current:r,states:o}=await n.api.issueStates(n.cfg,t),s=Ug(r,o);return s?.name&&t.state!==s.name&&(t.state=s.name,await oo(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 Wg(e,t,{mode:n="manual"}={}){if(!t)throw new Error("stateId required");let r=await Fn(e);if(!r)throw new Error("no ticket linked to this Track");let o=await rs(r);if(!o)throw new Error("no ticketing integration configured");let{current:s,states:a}=await o.api.issueStates(o.cfg,r),i=Ug(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 oo(e)),{key:r.key,from:l,to:c.name,moved:!1}):(await o.api.moveIssue(o.cfg,r,c.id),await wI(e,r,{from:l,to:c.name,mode:n}),{key:r.key,from:l,to:c.name,moved:!0})}async function bI(e,t){let n=await Fn(e);if(!n)throw new Error("no ticket linked to this Track");let r=await rs(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 kI(e,t,n){if(!t)throw new Error("offerId required");return Jr(`tkt:${e.id}:${t}`,()=>lH(e,t,n))}async function lH(e,t,n){let r=await K({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 Wg(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 oI=50;async function xI(){let e=await es();if(!e)throw new Error("no ticketing integration configured");return Ta(e)}function uH(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>oI)throw new Error(`too many issues (${n.length}); cap is ${oI} per proposal`);return{epic:r,issues:n,team:t.team?String(t.team).trim():null,linkCurrentTrack:t.linkCurrentTrack===!0}}async function dH(e,t,n,r){let o=r??await Ta(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 Fn(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 vI(e,t){let n=await es();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=uH(t),o=await Ta(n),s=await dH(n,r,e,o),a=s?{id:s.id,key:s.key,name:s.name}:null,i=lI();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 SI(e,t,n,{teamId:r=null}={}){if(!t)throw new Error("proposalId required");let o=await K({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 es();if(!a)throw new Error("no ticketing integration configured");let i=s.payload,c=i.team??null;if(!c&&r){let w=(await Ta(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 Og(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 Cg(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 Fn(e.id)&&(f=await Aa(e,p[0].key,{source:"created"}).catch(()=>null)),{proposalId:t,action:"created",created:l,failed:u,linked:f?f.key:null}}async function Mc(e,t){let n=await rs(e);n&&await n.api.createComment(n.cfg,e,t)}async function pH(e,t,n){let r=await rs(e);if(!r)return null;let o=await cr(t);if(!o)return null;let s=an(o,n);if(!s)return null;let a=await Nc.readFile(zt(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 sI=()=>Number(process.env.BOSTRAT_TICKET_COST_SYNC_MS??12e4),Dg=new Map;function fH(e,t){if(sI()<=0)return Pc(e,t);if(Dg.has(e))return;let n=setTimeout(()=>{Dg.delete(e),Fn(e).then(r=>r?Pc(e,r):null).catch(()=>{})},sI());n.unref?.(),Dg.set(e,n)}var aI=new Map;async function iI(e,t,n){let r=aI.get(e)??0;Date.now()-r<600*1e3||(aI.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 mH(e,{resolveTrack:t=null}={}){let n=await Fn(e.trackId),r=e.payload||{};if(!n){if(e.type!=="turn.user"||e.actor!=="user")return;let o=null;for(let a of await Fg())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 Aa(s,o,{source:"chat"})}catch(a){await iI(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 oo(e.trackId))}try{switch(e.type){case"handoff.done":n.track.leadAgent=r.toAgent??n.track.leadAgent,await oo(e.trackId),await Pc(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 oo(e.trackId),await Pc(e.trackId,n),r.change==="opened"||r.change==="merged"){let o=r.change==="merged"?await hI(n,e.trackId).catch(()=>null):null;await Mc(n,`**Bostrat** \u2014 PR ${r.change} for **${n.track.name}**${r.url?`: ${r.url}`:r.number?` (#${r.number})`:""}`+(o?`
724
724
 
725
- Agent cost for this Track: ${oH(o)}.`:"")),await wI(e.trackId,n,r.change)}break}case"mock.state.changed":{if(r.change==="ready"&&r.mockId){let o=await dH(n,r.mockId,r.version??null);if(!o)break;let s=(r.version??1)>1?` revised (v${r.version})`:"";await Mc(n,`**Bostrat** \u2014 mock **${r.name}**${s}${r.group?` (group \`${r.group}\`)`:""}:
725
+ Agent cost for this Track: ${sH(o)}.`:"")),await gI(e.trackId,n,r.change)}break}case"mock.state.changed":{if(r.change==="ready"&&r.mockId){let o=await pH(n,r.mockId,r.version??null);if(!o)break;let s=(r.version??1)>1?` revised (v${r.version})`:"";await Mc(n,`**Bostrat** \u2014 mock **${r.name}**${s}${r.group?` (group \`${r.group}\`)`:""}:
726
726
 
727
- ![${r.name}](${o})`)}else if(r.change==="picked"){let o=(r.siblings??[]).map(s=>`**${s.name}**`).join(", ");await Mc(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 Mc(n,`**Bostrat** \u2014 live preview **${r.name}**: ${Wd(r.slug)}
728
- _(runs on the Track's branch; reachable on the operator's private network only)_`);break}case"cost.recorded":await pH(e.trackId,n);break;default:break}}catch(o){let s=t?await t(e.trackId).catch(()=>null):null;await aI(e.trackId,s?.cwd??null,o)}}function SI({resolveTrack:e}){ot.on("event",t=>{fH(t,{resolveTrack:e}).catch(()=>{})})}async function TI(){if(!Fe())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("tickets");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Dc(),r=0;for(let[o,s]of Object.entries(n))await yt("tickets",{id:o,updatedAt:Date.now(),...s},{trackId:o}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}Mo();ca();import mH from"ws";var AI=()=>process.env.BOSTRAT_SLACK_API_BASE||"https://slack.com/api";async function qd(e,t,n={}){let r=await fetch(`${AI()}/${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 Wg=(e,t)=>qd("chat.postMessage",e,t),os=(e,t)=>qd("chat.update",e,t);async function xt(e,t){await fetch(e,{method:"POST",headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify(t)}).catch(()=>{})}async function hH(e,t,n={}){let r=await fetch(`${AI()}/${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 EI(e,{filename:t,buffer:n,title:r,channelId:o,threadTs:s,initialComment:a}){let{upload_url:i,file_id:c}=await hH("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 qd("files.completeUploadExternal",e,{files:[{id:c,title:r}],channel_id:o,thread_ts:s,...a?{initial_comment:a}:{}})}var wH=2200;function _I({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 qd("apps.connections.open",u))}catch(u){return n(`connections.open failed: ${u?.message||u}`),c()}o=new mH(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()},wH);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 RI=()=>process.env.BOSTRAT_STATE_DIR||Gd.join(process.env.HOME||yH.tmpdir(),".bostrat"),Vg=()=>Gd.join(RI(),"slack.json"),Kd=null,qg=null,Kg=Promise.resolve();async function Yg(){return Kd||(qg??=jc.readFile(Vg(),"utf8").then(e=>JSON.parse(e)?.threads??{}).catch(()=>({})).then(e=>Kd=e).finally(()=>qg=null),qg)}async function II(){let e=JSON.stringify({threads:Kd},null,2),t=`${Vg()}.${process.pid}.tmp`;await jc.mkdir(RI(),{recursive:!0}),await jc.writeFile(t,e),await jc.rename(t,Vg())}async function fn(){Kg=Kg.then(II,II),await Kg.catch(()=>{})}async function Xg(e){return(await Yg())[e]??null}async function bH(e,t){let n=await Yg();for(let[r,o]of Object.entries(n))if(o.channel===e&&o.ts===t)return{trackId:r,rec:o};return null}var ve=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");function Bc(e,t){let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1).trimEnd()}\u2026`}function kH(e,t=500){let n=String(e??"").trim().split(/\n\s*\n/)[0]??"";return Bc(n.replace(/\n+/g," "),t)}function OI(e){let t=`*${ve(e.name)}*${e.archivedAt?" \xB7 _archived_":""}`,n=`${ve(e.repoLabel)} \xB7 \`${ve(e.branch||"?")}\` \xB7 lead *${ve(e.lead)}*`,r=e.kickoff?`> ${ve(Bc(e.kickoff,300))}`:"_no kickoff yet \u2014 reply in this thread to steer the lead_";return[{type:"section",text:{type:"mrkdwn",text:`${t}
729
- ${n}`}},{type:"section",text:{type:"mrkdwn",text:r}},{type:"context",elements:[{type:"mrkdwn",text:`<${Hd(e.trackId)}|open the Track> \xB7 reachable on the operator's private network only`}]}]}async function Jg(e,t){await os(e.botToken,{channel:t.channel,ts:t.ts,text:`Track: ${t.name}`,blocks:OI(t)})}async function ao(e,t,n,r=void 0){return Wg(e.botToken,{channel:t.channel,thread_ts:t.ts,text:n,...r?{blocks:r}:{},unfurl_links:!1})}var $I=new Set;function so(e){$I.add(e),e.catch(()=>{}).finally(()=>$I.delete(e))}var Le=e=>({response_type:"ephemeral",text:e}),xH="*/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._",vH=["claude","cursor","codex"];function Gg(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 zg=(e,t)=>Le(`No live Track matches \u201C${ve(t)}\u201D. Live: ${e.map(n=>`\`${ve(n.name)}\``).join(" \xB7 ")||"none"}`);async function CI(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 xt(o,{...Le(`At capacity \u2014 ${a.length} live Tracks (limit ${t.maxConcurrent}). Archive or stop something first.`),replace_original:!0});return}if(!t.channel){await xt(o,{...Le("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?Gd.basename(c.base):"fresh workspace"),lead:"claude"},u=await Wg(t.botToken,{channel:t.channel,text:`Track started: ${l.name}`,blocks:OI(l),unfurl_links:!1});l.ts=u.ts,(await Yg())[i.id]=l,await fn(),await xt(o,{...Le(`\u2713 *${ve(l.name)}* started \u2014 root message posted.`),replace_original:!0})}catch(a){await xt(o,{...Le(`Start failed: ${a?.message||a}`),replace_original:!0})}}async function SH(e,t,{track:n,responseUrl:r}){let o=e.deps;try{await o.archiveTrack(n.id);let s=await Xg(n.id);s&&(s.archivedAt=Date.now(),await fn(),await Jg(t,s).catch(()=>{})),await xt(r,{...Le(`\u2713 *${ve(n.name)}* archived.`),replace_original:!0})}catch(s){await xt(r,{...Le(`Archive failed: ${s?.message||s}`),replace_original:!0})}}async function TH(e,t,{track:n,agent:r,responseUrl:o}){try{await e.deps.startLeadHandoff(n.id,r),await xt(o,{...Le(`\u2713 Handing *${ve(n.name)}* to ${ve(r)} \u2014 the root message updates when the baton lands.`),replace_original:!0})}catch(s){await xt(o,{...Le(`Handoff failed: ${s?.message||s}`),replace_original:!0})}}async function AH(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 xt(r,{...Le(`\u2713 Stopped *${ve(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 xt(r,{...Le(`Stop failed: ${s?.message||s}`),replace_original:!0})}}function EH(e,t){let n=[...t.slice(0,99).map(r=>({text:{type:"plain_text",text:Bc(`${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 *${ve(e)}*:`},accessory:{type:"static_select",action_id:"bostrat-start-repo",placeholder:{type:"plain_text",text:"Choose a repo"},options:n}}]}async function _H(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?Gd.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 *${ve(s.name)}* \u2014 ${ve(i)}${a.branch?` \`${ve(a.branch)}\``:""} \xB7 lead ${ve(c)} \xB7 ${l}`}),o=t.length-n.length;return r.join(`
727
+ ![${r.name}](${o})`)}else if(r.change==="picked"){let o=(r.siblings??[]).map(s=>`**${s.name}**`).join(", ");await Mc(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 Mc(n,`**Bostrat** \u2014 live preview **${r.name}**: ${qd(r.slug)}
728
+ _(runs on the Track's branch; reachable on the operator's private network only)_`);break}case"cost.recorded":await fH(e.trackId,n);break;default:break}}catch(o){let s=t?await t(e.trackId).catch(()=>null):null;await iI(e.trackId,s?.cwd??null,o)}}function TI({resolveTrack:e}){ot.on("event",t=>{mH(t,{resolveTrack:e}).catch(()=>{})})}async function AI(){if(!Fe())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("tickets");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Dc(),r=0;for(let[o,s]of Object.entries(n))await yt("tickets",{id:o,updatedAt:Date.now(),...s},{trackId:o}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}Mo();ca();import hH from"ws";var EI=()=>process.env.BOSTRAT_SLACK_API_BASE||"https://slack.com/api";async function Kd(e,t,n={}){let r=await fetch(`${EI()}/${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 qg=(e,t)=>Kd("chat.postMessage",e,t),os=(e,t)=>Kd("chat.update",e,t);async function xt(e,t){await fetch(e,{method:"POST",headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify(t)}).catch(()=>{})}async function wH(e,t,n={}){let r=await fetch(`${EI()}/${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 _I(e,{filename:t,buffer:n,title:r,channelId:o,threadTs:s,initialComment:a}){let{upload_url:i,file_id:c}=await wH("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 Kd("files.completeUploadExternal",e,{files:[{id:c,title:r}],channel_id:o,thread_ts:s,...a?{initial_comment:a}:{}})}var gH=2200;function II({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 Kd("apps.connections.open",u))}catch(u){return n(`connections.open failed: ${u?.message||u}`),c()}o=new hH(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()},gH);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 OI=()=>process.env.BOSTRAT_STATE_DIR||zd.join(process.env.HOME||bH.tmpdir(),".bostrat"),Jg=()=>zd.join(OI(),"slack.json"),Gd=null,Kg=null,Gg=Promise.resolve();async function Xg(){return Gd||(Kg??=Bc.readFile(Jg(),"utf8").then(e=>JSON.parse(e)?.threads??{}).catch(()=>({})).then(e=>Gd=e).finally(()=>Kg=null),Kg)}async function $I(){let e=JSON.stringify({threads:Gd},null,2),t=`${Jg()}.${process.pid}.tmp`;await Bc.mkdir(OI(),{recursive:!0}),await Bc.writeFile(t,e),await Bc.rename(t,Jg())}async function fn(){Gg=Gg.then($I,$I),await Gg.catch(()=>{})}async function Zg(e){return(await Xg())[e]??null}async function kH(e,t){let n=await Xg();for(let[r,o]of Object.entries(n))if(o.channel===e&&o.ts===t)return{trackId:r,rec:o};return null}var ve=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");function jc(e,t){let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1).trimEnd()}\u2026`}function xH(e,t=500){let n=String(e??"").trim().split(/\n\s*\n/)[0]??"";return jc(n.replace(/\n+/g," "),t)}function CI(e){let t=`*${ve(e.name)}*${e.archivedAt?" \xB7 _archived_":""}`,n=`${ve(e.repoLabel)} \xB7 \`${ve(e.branch||"?")}\` \xB7 lead *${ve(e.lead)}*`,r=e.kickoff?`> ${ve(jc(e.kickoff,300))}`:"_no kickoff yet \u2014 reply in this thread to steer the lead_";return[{type:"section",text:{type:"mrkdwn",text:`${t}
729
+ ${n}`}},{type:"section",text:{type:"mrkdwn",text:r}},{type:"context",elements:[{type:"mrkdwn",text:`<${Wd(e.trackId)}|open the Track> \xB7 reachable on the operator's private network only`}]}]}async function Yg(e,t){await os(e.botToken,{channel:t.channel,ts:t.ts,text:`Track: ${t.name}`,blocks:CI(t)})}async function ao(e,t,n,r=void 0){return qg(e.botToken,{channel:t.channel,thread_ts:t.ts,text:n,...r?{blocks:r}:{},unfurl_links:!1})}var RI=new Set;function so(e){RI.add(e),e.catch(()=>{}).finally(()=>RI.delete(e))}var Le=e=>({response_type:"ephemeral",text:e}),vH="*/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._",SH=["claude","cursor","codex"];function zg(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 Vg=(e,t)=>Le(`No live Track matches \u201C${ve(t)}\u201D. Live: ${e.map(n=>`\`${ve(n.name)}\``).join(" \xB7 ")||"none"}`);async function MI(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 xt(o,{...Le(`At capacity \u2014 ${a.length} live Tracks (limit ${t.maxConcurrent}). Archive or stop something first.`),replace_original:!0});return}if(!t.channel){await xt(o,{...Le("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?zd.basename(c.base):"fresh workspace"),lead:"claude"},u=await qg(t.botToken,{channel:t.channel,text:`Track started: ${l.name}`,blocks:CI(l),unfurl_links:!1});l.ts=u.ts,(await Xg())[i.id]=l,await fn(),await xt(o,{...Le(`\u2713 *${ve(l.name)}* started \u2014 root message posted.`),replace_original:!0})}catch(a){await xt(o,{...Le(`Start failed: ${a?.message||a}`),replace_original:!0})}}async function TH(e,t,{track:n,responseUrl:r}){let o=e.deps;try{await o.archiveTrack(n.id);let s=await Zg(n.id);s&&(s.archivedAt=Date.now(),await fn(),await Yg(t,s).catch(()=>{})),await xt(r,{...Le(`\u2713 *${ve(n.name)}* archived.`),replace_original:!0})}catch(s){await xt(r,{...Le(`Archive failed: ${s?.message||s}`),replace_original:!0})}}async function AH(e,t,{track:n,agent:r,responseUrl:o}){try{await e.deps.startLeadHandoff(n.id,r),await xt(o,{...Le(`\u2713 Handing *${ve(n.name)}* to ${ve(r)} \u2014 the root message updates when the baton lands.`),replace_original:!0})}catch(s){await xt(o,{...Le(`Handoff failed: ${s?.message||s}`),replace_original:!0})}}async function EH(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 xt(r,{...Le(`\u2713 Stopped *${ve(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 xt(r,{...Le(`Stop failed: ${s?.message||s}`),replace_original:!0})}}function _H(e,t){let n=[...t.slice(0,99).map(r=>({text:{type:"plain_text",text:jc(`${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 *${ve(e)}*:`},accessory:{type:"static_select",action_id:"bostrat-start-repo",placeholder:{type:"plain_text",text:"Choose a repo"},options:n}}]}async function IH(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?zd.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 *${ve(s.name)}* \u2014 ${ve(i)}${a.branch?` \`${ve(a.branch)}\``:""} \xB7 lead ${ve(c)} \xB7 ${l}`}),o=t.length-n.length;return r.join(`
730
730
  `)+(o?`
731
- _${o} archived_`:"")}async function IH(e,t){let n=await ts();if(!n)return Le("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 Le("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?(so(CI(e,n,{name:u,repo:l.path,responseUrl:t.response_url})),Le(`Starting *${ve(u)}* on ${ve(l.name)}\u2026`)):{response_type:"ephemeral",text:`Pick a repo for \u201C${u}\u201D`,blocks:EH(u,i)}}case"archive":{if(!a.length)return Le("Usage: `/bostrat archive <track>`");let{match:i,live:c}=Gg(await r.listTracks(),a.join(" "));return i?(so(SH(e,n,{track:i,responseUrl:t.response_url})),Le(`Archiving *${ve(i.name)}*\u2026`)):zg(c,a.join(" "))}case"handoff":{let i=r.knownAgents??vH,c=a.at(-1)?.toLowerCase();if(a.length<2||!i.includes(c))return Le(`Usage: \`/bostrat handoff <track> <${i.join("|")}>\``);let l=a.slice(0,-1).join(" "),{match:u,live:d}=Gg(await r.listTracks(),l);return u?(so(TH(e,n,{track:u,agent:c,responseUrl:t.response_url})),Le(`Handing *${ve(u.name)}* to ${ve(c)}\u2026`)):zg(d,l)}case"stop":{if(!a.length)return Le("Usage: `/bostrat stop <track>`");let{match:i,live:c}=Gg(await r.listTracks(),a.join(" "));return i?(so(AH(e,n,{track:i,responseUrl:t.response_url})),Le(`Stopping *${ve(i.name)}*\u2026`)):zg(c,a.join(" "))}case"list":return Le(await _H(r));default:return Le(xH)}}async function $H(e,t,n,r){let{trackId:o,promptId:s,label:a}=r,i=await Xg(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 fn(),await os(t.botToken,{channel:i.channel,ts:c,text:`\u2713 ${a}`,blocks:[{type:"section",text:{type:"mrkdwn",text:`~${ve(l||"question")}~
732
- \u2713 *${ve(a)}*`}}]}).catch(()=>{})}}catch(c){await xt(n.response_url,Le(`Couldn't answer: ${c?.message||c}`))}}async function RH(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)?Fr.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,zs(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 xt(n.response_url,Le(`Couldn't act on the offer: ${c?.message||c}`))}}async function OH(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 xt(n.response_url,Le(`Couldn't act on the offer: ${i?.message||i}`))}}async function CH(e,t){let n=t.actions?.[0];if(!n?.action_id)return;let r=await ts();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 xt(t.response_url,{...Le(`Starting *${ve(s)}*\u2026`),replace_original:!0}),so(CI(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"?so($H(e,r,t,o)):n.action_id==="bostrat-ship"?so(RH(e,r,t,o)):n.action_id==="bostrat-pr-exists"&&so(OH(e,r,t,o))}async function MH(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 bH(t.channel,t.thread_ts);if(!n)return;let r=await ts();if(r)try{await e.deps.sayToLead(n.trackId,t.text.trim())}catch(o){await ao(r,n.rec,`Couldn't deliver that to the lead: ${o?.message||o}`).catch(()=>{})}}function NH(e){return async t=>{if(t.type==="slash_commands")return IH(e,t.payload);if(t.type==="interactive"){await CH(e,t.payload);return}if(t.type==="events_api"){await MH(e,t.payload?.event);return}}}var PH=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 DH(e,t){let n=[{type:"section",text:{type:"mrkdwn",text:`\u2753 ${ve(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:Bc(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 jH(e,t,n){let r=n.payload||{};if(!r.promptId||t.prompt?.promptId===r.promptId)return;t.prompt&&await os(e.botToken,{channel:t.channel,ts:t.prompt.ts,text:"superseded",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${ve(t.prompt.question||"question")}~ _superseded_`}}]}).catch(()=>{});let o=await ao(e,t,r.question||"The lead needs an answer",DH(n.trackId,r));t.prompt={promptId:r.promptId,ts:o.ts,question:r.question||null},await fn()}async function BH(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 fn(),await os(e.botToken,{channel:t.channel,ts:o,text:"answered",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${ve(s||"question")}~
733
- \u2713 _answered_`}}]})}async function LH(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 ao(e,t,r.excerpt||"Ship it?",[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${ve(Bc(r.excerpt||"The lead offered to ship.",300))}`}},{type:"actions",elements:s}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await fn()}async function FH(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await fn();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 os(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function UH(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 ao(e,t,`PR ${o} already open \u2014 push or new PR?`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${o}${r.branch?` (${ve(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 fn()}async function HH(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await fn();let s=r.choice==="dismiss"?"dismissed":r.choice==="new"?"\u2713 opening a new PR":"\u2713 pushing to the open PR";await os(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function WH(e,t,n,r){let o=n.payload||{};if(o.change==="ready"&&o.mockId){let s=await(r.readMockPng??qH)(o.mockId,o.version??null);if(!s)return;let a=(o.version??1)>1?` (v${o.version})`:"";await EI(e.botToken,{filename:s.filename,buffer:s.buffer,title:`${o.name}${a}`,channelId:t.channel,threadTs:t.ts,initialComment:`\u{1F3A8} mock *${ve(o.name)}*${a}${o.group?` (group \`${ve(o.group)}\`)`:""}`})}else if(o.change==="picked"){let s=(o.siblings??[]).map(a=>`*${ve(a.name)}*`).join(", ");await ao(e,t,`Design decision: ${o.name} picked`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F3A8} design decision: *${ve(o.name)}* picked${s?` over ${s}`:""}`}}])}}async function qH(e,t){let n=await cr(e);if(!n)return null;let r=an(n,t);if(!r)return null;let o=await jc.readFile(zt(n,r.v).png).catch(()=>null);return o?{filename:`${n.name.replace(/[^\w.-]+/g,"-")}.v${r.v}.png`,buffer:o}:null}async function KH(e,t){if(!PH.has(t.type))return;let n=await Xg(t.trackId);if(!n)return;let r=await ts();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 fn(),await Jg(r,n);return;case"turn.agent":{if(!o.text)return;let s=kH(o.text);if(!s)return;await ao(r,n,s,[{type:"section",text:{type:"mrkdwn",text:ve(s)}},{type:"context",elements:[{type:"mrkdwn",text:`<${Hd(t.trackId)}|full turn \u2192>`}]}]);return}case"prompt.raised":return jH(r,n,t);case"prompt.answered":return BH(r,n,t);case"pr.offered":return LH(r,n,t);case"pr.offer.answered":return FH(r,n,t);case"pr.exists.offered":return UH(r,n,t);case"pr.exists.answered":return HH(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 ao(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 fn(),await Jg(r,n);return;case"view.state.changed":{if(o.change!=="created"||o.restarted||!o.slug)return;await ao(r,n,`Live preview ${o.name}: ${Wd(o.slug)}`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F50D} live preview *${ve(o.name)}*: ${Wd(o.slug)}
734
- _runs on the Track's branch; reachable on the operator's private network only_`}}]);return}case"mock.state.changed":return WH(r,n,t,e.deps)}}function MI(e){let t={deps:e};ot.on("event",s=>{KH(t,s).catch(()=>{})});let n=null,r=null,o=async()=>{n||!await ts()||(r&&clearInterval(r),r=null,n=_I({getToken:async()=>(await ts())?.appToken,onEnvelope:NH(t),log:s=>console.log(`[slack] ${s}`)}))};return r=setInterval(()=>o().catch(()=>{}),3e4),r.unref?.(),o().catch(()=>{}),()=>{r&&clearInterval(r),n?.()}}nn();de();kn();ch();Vn();import GH from"node:fs/promises";function zH(e){let t=new Map;for(let n of String(e||"").split(`
735
- `)){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 VH(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 JH=new Set(["Write","Edit","NotebookEdit"]),YH=220,XH=160;function ZH(e,t){let n=e?.tool_name??null,r={tool:n},o=e?.tool_input;if(!o||typeof o!="object")return r;if(JH.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,YH)}else n==="Bash"&&typeof o.command=="string"&&o.command.trim()&&(r.head=go(o.command.trim().replace(/\s+/g," ")).slice(0,XH));return r}function QH(e,t){return e?.transcript_path?e.transcript_path:t?.cwd&&t?.sessionId?tn(t.cwd,t.sessionId):t?.cwd?sf(t.cwd):null}async function NI(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=qu(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:ZH(e,o)});break;case"Stop":await eW(r,o,e,i);break;default:break}return a}async function eW(e,t,n,r){let o=[],s=QH(n,t);if(s)try{o=zH(await GH.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=VH(await K(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:Tn(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}})}ds();Xp();Wu();de();de();Pr();de();Pr();Vn();function Lc(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 PI=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),DI=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},zd=e=>Math.round(e*1e4)/1e4;async function Zg(e){let t=[],n={},r={},o=0,s=0,a=0,i=0,c=0,l=new Set,u=PI(),d=0,p=[];for(let f of e||[]){let w=await K(f),m=Nr(w,{boxLabels:Lc(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);DI(u,m.totalTokens);for(let[g,b]of Object.entries(m.byModel))n[g]||={usd:0,events:0,tokens:PI()},n[g].usd=zd(n[g].usd+b.usd),n[g].events+=b.events,DI(n[g].tokens,b.tokens);for(let[g,b]of Object.entries(m.byProvider))r[g]||={usd:0,events:0},r[g].usd=zd(r[g].usd+b.usd),r[g].events+=b.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:Ps(),fleet:{totalUsd:zd(o),asRecordedUsd:zd(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 io=e=>`$${e.toFixed(4)}`,Ea=(e,t)=>String(e).padEnd(t);function jI(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 ${io(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 ${io(t.asRecordedUsd)} \xB7 current-rates total ${io(t.totalUsd)} (${t.totalUsd>=t.asRecordedUsd?"+":""}${io(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(` ${Ea(a,26)} ${Ea(io(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(` ${Ea(a.name||a.id,30)} ${io(a.usd)}`);let i=Object.values(a.rollup.byBox).sort((c,l)=>l.usd-c.usd);for(let c of i)if(r.push(` ${Ea(c.label,40)} ${Ea(io(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))}${Ea(io(u.usd),10)} ${u.models.join(",")||"?"}`)}return r.join(`
736
- `)}de();Om();import iW from"node:fs/promises";import cW from"node:path";Gl();Xl();Pr();var Vd=e=>e.payload?.ts??e.ts,tW=12e4,Jt=e=>Math.round(e*1e4)/1e4,nW=()=>({usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{},byTrack:new Map});function rW(e,{since:t}){let{track:n,events:r,brief:o}=e,s=y=>Vd(y)>=t,a=zn([xi(n?.name),xi(n?.workspace?.branch),o].filter(Boolean).join(" ")),i=new Map;for(let y of r)if(y.type==="subtask.delegated"&&y.boxId&&y.payload?.task){let $=zn(y.payload.task);$&&i.set(y.boxId,$)}let c=new Map,l=y=>{let $=y||"unattributed";return c.has($)||c.set($,{segments:[u(null)],lastTs:null,provider:null}),c.get($)},u=(y,{shape:$="initial",continuation:O=!1,text:M=null,ts:H=null}={})=>({textCat:y,shape:$,continuation:O,text:M,ts:H,tools:{},usd:0,tokens:{input:0,output:0,cacheRead:0,cacheWrite:0},models:{},provider:null,activeMs:0,turns:0,toolCalls:0}),d=[...r].sort((y,$)=>Vd(y)-Vd($)),p=0,f=0,w=0,m={turns:0};for(let y of d){let $=l(y.boxId),O=$.segments[$.segments.length-1],M=Vd(y);switch($.lastTs!=null&&M>$.lastTs&&s(y)&&(O.activeMs+=Math.min(M-$.lastTs,tW)),$.lastTs=M,y.provider&&($.provider=y.provider),y.type){case"turn.user":{let H=y.payload?.text;if(y.source==="hook"||!String(H||"").trim()||y.payload?.note||Ti(H))break;let P=zn(H),E=!!y.payload?.kind,R=E||c0(H),G=u(P,{shape:E?"injected":R?"follow-up":"novel-ask",continuation:!P&&R,text:LI(H),ts:M});$.segments.push(G),s(y)&&(G.turns+=1);break}case"peer.message":{let H=y.payload?.text;if(!String(H||"").trim())break;let P=zn(H),E=u(P,{shape:"peer",continuation:!P,text:LI(H),ts:M});$.segments.push(E),s(y)&&(E.turns+=1);break}case"tool.called":{if(y.source==="transcript")break;let H=y.payload?.tool;H&&(O.tools[H]=(O.tools[H]||0)+1),s(y)&&(O.toolCalls+=1);break}case"cost.recorded":{if(!s(y))break;let{usd:H,tokens:P,model:E,unpriced:R}=Wt(y);R&&(m.turns+=1),O.usd+=H,P&&(O.tokens.input+=P.input,O.tokens.output+=P.output,O.tokens.cacheRead+=P.cacheRead,O.tokens.cacheWrite+=P.cacheWrite),O.models[E]=(O.models[E]||0)+H,y.provider&&(O.provider=y.provider);break}case"handoff.done":s(y)&&(p+=1);break;case"subtask.merged":s(y)&&(f+=1);break;case"error":s(y)&&y.payload?.kind==="subtask-failed"&&(w+=1);break;default:break}}let g=new Map,b={usd:0,turns:0,byShape:{},samples:[]},x=!1;for(let[y,$]of c){let O=null;for(let M of $.segments){let H=null,P=null;if(M.textCat)H=M.textCat.category,P="text";else if(i.get(y))H=i.get(y).category,P="boxTask";else if(M.continuation&&O)H=O,P="inherited";else{let A=i0(M.tools);A?(H=A.category,P="toolMix"):a&&(H=a.category,P="hint")}if(H&&(O=H),!(M.usd>0||M.activeMs>0||M.turns>0||M.toolCalls>0))continue;let R=H??"uncategorized";g.has(R)||g.set(R,{usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{}});let G=g.get(R);G.usd+=M.usd,G.activeMs+=M.activeMs,G.turns+=M.turns,G.toolCalls+=M.toolCalls,P&&(G.provenance[P]=(G.provenance[P]||0)+M.usd);for(let[A,_]of Object.entries(M.models))G.models[A]=(G.models[A]||0)+_;let V=M.provider||$.provider;V&&(G.providers[V]=(G.providers[V]||0)+M.usd),V==="cursor"&&M.usd===0&&(x=!0),H||(b.usd+=M.usd,b.turns+=M.turns,b.byShape[M.shape]=(b.byShape[M.shape]||0)+M.usd,M.usd>0&&M.text&&b.samples.push({trackId:n?.id,track:n?.name||n?.id,shape:M.shape,usd:Jt(M.usd),ts:M.ts,text:M.text}))}}return{perCategory:g,uncategorized:b,handoffs:p,merged:f,failed:w,sawCursorActivity:x,unpricedTurns:m.turns}}function Qg(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 b of e||[]){let{track:x,events:y}=b;if(!y?.length){a+=1;continue}let{perCategory:$,uncategorized:O,handoffs:M,merged:H,failed:P,sawCursorActivity:E,unpricedTurns:R}=rW(b,{since:r});E&&(i=!0),c+=R,l.usd+=O.usd,l.turns+=O.turns;for(let[V,A]of Object.entries(O.byShape))l.byShape[V]=(l.byShape[V]||0)+A;l.samples.push(...O.samples);let G={trackId:x?.id,name:x?.name||x?.id,archived:!!x?.archivedAt,usd:0,activeMs:0,turns:0,categories:{},models:{},providers:{},handoffs:M,subtasksMerged:H,subtasksFailed:P};for(let[V,A]of $){G.usd+=A.usd,G.activeMs+=A.activeMs,G.turns+=A.turns,G.categories[V]={usd:Jt(A.usd),activeMs:A.activeMs};for(let[U,z]of Object.entries(A.models))G.models[U]=Jt((G.models[U]||0)+z);for(let[U,z]of Object.entries(A.providers))G.providers[U]=Jt((G.providers[U]||0)+z);o.has(V)||o.set(V,nW());let _=o.get(V);_.usd+=A.usd,_.activeMs+=A.activeMs,_.turns+=A.turns,_.toolCalls+=A.toolCalls;for(let[U,z]of Object.entries(A.models))_.models[U]=(_.models[U]||0)+z;for(let[U,z]of Object.entries(A.providers))_.providers[U]=(_.providers[U]||0)+z;for(let[U,z]of Object.entries(A.provenance))_.provenance[U]=(_.provenance[U]||0)+z;let N=_.byTrack.get(x?.id)||{usd:0,activeMs:0};N.usd+=A.usd,N.activeMs+=A.activeMs,_.byTrack.set(x?.id,N)}(G.usd>0||G.activeMs>0||G.turns>0)&&(G.usd=Jt(G.usd),G.dominantCategory=aW(G.categories),s.push(G))}let u=[...o.values()].reduce((b,x)=>b+x.usd,0),d=[...o.values()].reduce((b,x)=>b+x.activeMs,0),p=u>0?"usd":"time",f=p==="usd"?u:d,w=new Map((e||[]).map(b=>[b.track?.id,b.track?.name||b.track?.id])),m=[...o.entries()].map(([b,x])=>({category:b,sharePct:f>0?Math.round((p==="usd"?x.usd:x.activeMs)/f*100):0,shareBasis:p,usd:Jt(x.usd),activeMs:x.activeMs,turns:x.turns,toolCalls:x.toolCalls,models:Fc(x.models),providers:Fc(x.providers),provenance:Fc(x.provenance),topWorkstreams:[...x.byTrack.entries()].sort((y,$)=>$[1].usd-y[1].usd||$[1].activeMs-y[1].activeMs).slice(0,2).map(([y,$])=>({trackId:y,name:w.get(y),usd:Jt($.usd),activeMs:$.activeMs}))})).sort((b,x)=>x.usd-b.usd||x.activeMs-b.activeMs);s.sort((b,x)=>x.usd-b.usd||x.activeMs-b.activeMs);let g={};for(let b of o.values())for(let[x,y]of Object.entries(b.provenance))g[x]=(g[x]||0)+y;return{since:r,capturedAt:n,totalUsd:Jt(u),activeMs:d,turns:[...o.values()].reduce((b,x)=>b+x.turns,0),bullets:m,workstreams:s,provenance:Fc(g),gaps:{tracksWithoutEvents:a,cursorCostUnknown:i,unpricedTurns:c,uncategorized:{usd:Jt(l.usd),turns:l.turns,sharePct:u>0?Math.round(l.usd/u*100):0,byShape:Fc(l.byShape),top:l.samples.sort((b,x)=>x.usd-b.usd).slice(0,oW)}}}}var oW=25,BI=160,LI=e=>{let t=String(e||"").replace(/\s+/g," ").trim();return t.length>BI?`${t.slice(0,BI).trimEnd()}\u2026`:t},sW=10;function FI(e,{thresholdPct:t=sW}={}){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:Jt(o),totalUsd:Jt(r),turns:n.turns||0,inheritedPct:r>0?Math.round((e?.provenance?.inherited||0)/r*100):0,problems:i}}var aW=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},Fc=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Jt(n)]));var as={"24h":24*36e5,"7d":168*36e5,"30d":720*36e5,all:null};function lW(e){let t=String(e||"7d");return t in as?{key:t,ms:as[t]}:{key:"7d",ms:as["7d"]}}function uW(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=yu(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 dW(e){if(!e?.cwd)return null;try{let n=(await iW.readFile(cW.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 ey(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}:lW(t),d=[];for(let w of e||[]){let m=await K(w),g=uW(w,m);i&&c<o&&(g=g.filter(b=>(b.ts??0)<=c)),d.push({track:w,events:g,brief:await dW(w)})}let p=Qg(d,{windowMs:u,now:c}),f=l==="7d"&&c===o?p:Qg(d,{windowMs:as["7d"],now:o});return{window:l,...p,categorization:FI(f)}}var Uc=e=>`$${Number(e||0).toFixed(2)}`,UI=e=>{let t=Math.round((e||0)/6e4);return t>=60?`${Math.floor(t/60)}h${String(t%60).padStart(2,"0")}`:`${t}m`},ss=(e,t)=>String(e).padEnd(t);function HI(e){let t=[];t.push(`USAGE ROUNDUP \xB7 ${e.window} \xB7 ${Uc(e.totalUsd)} \xB7 ${UI(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(` ${ss(`${a.shareBasis==="time"?"~":""}${a.sharePct}%`,5)} ${ss(a.category,15)} ${ss(Uc(a.usd),10)} ${ss(UI(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 ${Uc(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} ${Uc(i)}`).join(" \xB7 ")||"none")),s.top?.length||t.push(" (nothing unmatched carried cost in this window)");for(let a of s.top||[])t.push(` ${ss(Uc(a.usd),8)} ${ss(a.shape,10)} ${ss(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(`
737
- `)}Vn();var co=36e5,GI=24*co,pW=400,fW=12,is=e=>Math.round(e*1e4)/1e4;function ty({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 as?String(e||"7d"):"7d",i=as[a];return{key:a,since:i==null?null:r-i,until:r}}var mW=(e,t)=>e!=null&&t-e<=48*co?co:GI;function WI(e,t){if(t===co)return Math.floor(e/co)*co;let n=new Date(e);return n.setHours(0,0,0,0),n.getTime()}function hW(e,t){if(t===co)return e+co;let n=new Date(e);return n.setDate(n.getDate()+1),n.setHours(0,0,0,0),n.getTime()}var qI=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),KI=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},wW=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,is(n)]));async function zI(e,t={}){let n=t.now??Date.now(),r=ty({...t,now:n}),o=r.since==null?GI:mW(r.since,r.until),s=E=>(r.since==null||E>=r.since)&&E<r.until,a=r.since!=null?r.until-r.since:null,i=E=>a!=null&&E>=r.since-a&&E<r.since,c={},l={},u=qI(),d=0,p=0,f=0,w=0,m=0,g=0,b=new Set,x=new Map,y=[],$=[],O=[],M=null;for(let E of e||[]){let G=(await K(E)).filter(_=>_.type==="cost.recorded");if(!G.length){E.archivedAt||O.push(E.name||E.id);continue}let V=[];for(let _ of G){let N=_.ts??0;s(N)?V.push(_):i(N)&&(g+=Wt(_).usd)}if(!V.length)continue;let A=Nr(V,{boxLabels:Lc(E)});d+=A.totalUsd,p+=A.turns,f+=A.repricedTurns||0,w+=A.asRecordedUsd||0,m+=A.unpricedTurns||0;for(let _ of A.unpricedModels||[])b.add(_);KI(u,A.totalTokens);for(let[_,N]of Object.entries(A.byModel))c[_]||={usd:0,events:0,tokens:qI()},c[_].usd=is(c[_].usd+N.usd),c[_].events+=N.events,KI(c[_].tokens,N.tokens);for(let[_,N]of Object.entries(A.byProvider))l[_]||={usd:0,events:0},l[_].usd=is(l[_].usd+N.usd),l[_].events+=N.events;for(let _ of V){let{usd:N}=Wt(_);if(!N)continue;let U=WI(_.ts??0,o),z=x.get(U)??{t:U,total:0,byProvider:{}};z.total+=N;let ue=_.provider||"unknown";z.byProvider[ue]=(z.byProvider[ue]||0)+N,x.set(U,z),(M==null||U<M)&&(M=U)}y.push({id:E.id,name:E.name||E.id,archived:!!E.archivedAt,usd:A.totalUsd,turns:A.turns,providers:Object.keys(A.byProvider)});for(let[_,N]of Object.entries(A.byBox))$.push({trackId:E.id,trackName:E.name||E.id,boxId:_,...N})}let H=r.since!=null?WI(r.since,o):M,P=[];for(let E=H,R=0;E!=null&&E<r.until&&R<pW;E=hW(E,o),R++){let G=x.get(E);P.push(G?{t:E,total:is(G.total),byProvider:wW(G.byProvider)}:{t:E,total:0,byProvider:{}})}return y.sort((E,R)=>R.usd-E.usd),$.sort((E,R)=>R.usd-E.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",pricing:Ps(),window:r.key,since:r.since,until:r.until,bucketMs:o,series:P,fleet:{totalUsd:is(d),asRecordedUsd:is(w),turns:p,repricedTurns:f,unpricedTurns:m,unpricedModels:[...b],totalTokens:u,byModel:c,byProvider:l,tracksWithCost:y.length,tracksSilentLive:O},prior:a!=null?{totalUsd:is(g),since:r.since-a,until:r.since}:null,tracks:y.slice(0,50),boxes:$.slice(0,fW)}}Uu();var gW=new Set(["cost.recorded","code.committed","code.rework","rework.cause.offered","rework.cause.answered"]),yW=20,bW=40;async function VI(e,t={}){let n=t.now??Date.now(),r=ty({...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 K(l),d=0,p=Lc(l);for(let f of u){if(!gW.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=XS(s,{boxMeta:a});return{generatedAt:new Date().toISOString(),window:r.key,since:r.since,until:r.until,reworkWindowDays:zr,decayEndDays:Zm,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,yW),fixes:c.fixes.slice(0,bW)}}import kW from"node:fs";import JI from"node:fs/promises";import Hc from"node:os";import xW from"node:path";qh();ct();var vW=1024*1024,Jd=e=>Math.round(e/vW);async function SW(e){try{let t=await JI.statfs(e),n=t.blocks*t.bsize,r=n-t.bavail*t.bsize;return{diskUsedMb:Jd(r),diskTotalMb:Jd(n)}}catch{return{diskUsedMb:null,diskTotalMb:null}}}async function TW(){try{return(await Qt()).filter(t=>t.isBostrat).length}catch{return null}}async function AW(){let e=0,t=!1;for(let n of["workspaces","worktrees"])try{let r=await JI.readdir(xW.join(_c,n),{withFileTypes:!0});e+=r.filter(o=>o.isDirectory()).length,t=!0}catch{}return t?e:null}async function YI({stateDir:e=_c,now:t=Date.now}={}){let n=Hc.totalmem(),[r,o,s,a]=await Promise.all([od().catch(()=>null),SW(kW.existsSync(e)?e:Hc.tmpdir()),TW(),AW()]),i=Hc.cpus()?.length||null,c=Hc.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?Jd(n-r):null,memTotalMb:Jd(n),...o,boxes:s,worktrees:a,procUptimeS:Math.round(process.uptime()),osUptimeS:Math.round(Hc.uptime())}}_h();de();Of();Va();Vn();de();Vn();var EW=864e5;function _W(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=Tn(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 XI(e,{days:t=14,tolerance:n=.005,now:r=Date.now()}={}){let o=r-t*EW,s={},a=0,i=0,c=[];for(let u of e||[]){let d=await K(u);for(let p of d){if(!p.ts||p.ts<o)continue;let f=_W(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}}Th();fw();hu();pt();An();import _a from"node:fs/promises";import IW from"node:fs";import mt from"node:path";import $W from"node:os";import{execFile as RW}from"node:child_process";import{promisify as OW}from"node:util";var CW=OW(RW),ZI=process.env.BOSTRAT_STATE_DIR||mt.join(process.env.HOME||$W.tmpdir(),".bostrat"),Yd=!1,ny=null;async function ry(e,t){let n=await _a.stat(e).catch(()=>null);if(!n?.isFile())return!1;let r=await _a.stat(t).catch(()=>null);return r&&r.size===n.size&&r.mtimeMs>=n.mtimeMs?!1:(await _a.mkdir(mt.dirname(t),{recursive:!0}),await _a.copyFile(e,t),!0)}var MW=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 Xd(e,t,{skip:n=null}={}){let r=0,o=await _a.readdir(e,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(MW.has(s.name)||n?.has(s.name))continue;let a=mt.join(e,s.name);s.isDirectory()?r+=await Xd(a,mt.join(t,s.name)):s.isFile()&&(r+=await ry(a,mt.join(t,s.name))?1:0)}return r}async function QI({stateDir:e=ZI,dest:t=process.env.BOSTRAT_SYNC_DIR||`${ZI}-sync`,remote:n=process.env.BOSTRAT_STATE_REMOTE||null,tracks:r=null}={}){try{await _a.mkdir(t,{recursive:!0});let o=0;o+=await ry(mt.join(e,"tracks.json"),mt.join(t,"tracks.json"))?1:0,o+=await ry(mt.join(e,"events.jsonl"),mt.join(t,"events.jsonl"))?1:0,o+=await Xd(mt.join(e,"events"),mt.join(t,"events")),o+=await Xd(mt.join(e,"memory"),mt.join(t,"memory"));let s=new Set(["mocks"]);for(let u of r||[])!u?.cwd||!u?.id||(o+=await Xd(mt.join(u.cwd,".bostrat"),mt.join(t,"workspaces",u.id,".bostrat"),{skip:s}));let a=(...u)=>CW("git",["-C",t,...u]);IW.existsSync(mt.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 Mp(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||Yd))try{await a("push","-q",n,"HEAD:refs/heads/main"),l=!0,Yd&&console.log("[state-sync] push recovered \u2014 off-box copy is current again"),Yd=!1,ny=null}catch(u){Yd=!0;let d=(u?.stderr||u?.message||String(u)).trim().split(`
738
- `).slice(-3).join(" | ").slice(0,300);d!==ny&&(ny=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)}}}lw();nn();vo();ct();Ua();import{execFile as NW}from"node:child_process";import{promisify as PW}from"node:util";import{randomUUID as DW}from"node:crypto";import jW from"node:fs";import BW from"node:os";import LW from"node:path";var uo=PW(NW),Zd=e=>new Promise(t=>setTimeout(t,e)),po=ef,oy=process.env.BOSTRAT_USAGE_PROBE_CWD||LW.join(BW.homedir(),".bostrat","usage-probe"),FW=Number(process.env.BOSTRAT_USAGE_IDLE_REAP_MS)||5*6e4,UW=Number(process.env.BOSTRAT_USAGE_PANEL_TIMEOUT_MS)||15e3,HW=Number(process.env.BOSTRAT_USAGE_READY_TIMEOUT_MS)||45e3,e$=Number(process.env.BOSTRAT_USAGE_CACHE_MS)||2e4,lo=null,Wc=null,qc=null;async function WW(){try{return await uo(X,Z("has-session","-t",po)),!0}catch{return!1}}function qW(){lo&&clearTimeout(lo),lo=setTimeout(()=>KW().catch(()=>{}),FW),lo.unref&&lo.unref()}async function KW(){lo&&(clearTimeout(lo),lo=null);try{await uo(X,Z("kill-session","-t",po))}catch{}}async function GW(){let e=Date.now()+HW;for(;;){let t=await sy().catch(()=>"");if(/for agents|for shortcuts|bypass permissions on/i.test(t)){await Zd(500);return}if(Date.now()>e)throw new Error("usage probe didn't reach the prompt (trust/onboarding may be blocking)");await Zd(500)}}async function zW(){if(await WW())return;if(!await Er())throw new Error("host tmux server not running \u2014 start globo-tmux.service");jW.mkdirSync(oy,{recursive:!0}),await yr(oy);let e=DW();await uo(X,Z("new-session","-d","-s",po,"-c",oy,"-x","200","-y","60",...ri()));let t=`${Qp} --session-id ${e}`;await uo(X,Z("send-keys","-t",po,t,"Enter")),await GW()}async function sy(){let{stdout:e}=await uo(X,Z("capture-pane","-t",po,"-p"));return e}async function VW(){await zW(),await uo(X,Z("send-keys","-t",po,"-l","/usage")),await uo(X,Z("send-keys","-t",po,"Enter"));let e=Date.now()+UW,t="";for(;await Zd(400),t=await sy(),!(/Current\s+(session|week)/i.test(t)||/\d+%\s*used/i.test(t)||Date.now()>e););return await Zd(900),t=await sy(),await uo(X,Z("send-keys","-t",po,"Escape")).catch(()=>{}),qW(),t}function JW(e){let t=String(e||"").split(`
739
- `).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 YW(e){let t=String(e||"").split(`
740
- `).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 t$({fresh:e=!1}={}){return!e&&Wc&&Date.now()-Wc.at<e$?Wc.data:qc||(qc=(async()=>{try{let t=await VW(),n=JW(t),r={...n,contributors:YW(t),subscription:!!(n.session||n.week||n.weekModels),capturedAt:Date.now()};return Wc={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 Wc={at:Date.now()-(e$-3e3),data:n},n}finally{qc=null}})(),qc)}var XW=262144;function ZW(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 QW=new Set([300]),eq=new Set([10080]);function tq(e){let t=Number(e);return!Number.isFinite(t)||t<=0?null:QW.has(t)?"session":eq.has(t)?"week":"other"}function nq(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 rq(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?ZW((o-n)/1e3):null,resetsAt:o}}var Kc=e=>({session:null,week:null,other:null,planType:null,credits:null,limitReached:null,sawTokenCount:e});function oq(e,t=Date.now()){let n=String(e||"").split(`
741
- `),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 Kc(r);if(c.primary||c.secondary){let l=Date.parse(a.timestamp)||null,u=Kc(r);[c.primary,c.secondary].forEach((f,w)=>{let m=rq(f,l,t);if(!m)return;let g=tq(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:nq(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{...Kc(r),session:l(c.primary_used_percent),week:l(c.secondary_used_percent)}}return Kc(r)}return Kc(r)}async function ay(e){let t={provider:"codex",supported:!0,contributors:null};try{let n=await ko(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 _t(n.file,XW),o=oq(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 n$(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 Qd({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 ay(i);if(c.subscription){a=c;break}(!a||a.error&&!c.error)&&(a=c)}r.push(a||await ay(null))}return n.has("cursor")&&r.push(await Qd({agent:"cursor"})),{providers:r,capturedAt:Date.now()}}async function Qd(e,{fresh:t=!1}={}){let n=e?.agent||"claude";return n==="codex"?ay(e):n==="cursor"?{provider:"cursor",supported:!1,subscription:!1,session:null,week:null,contributors:null,capturedAt:Date.now()}:{provider:"claude",supported:!0,...await t$({fresh:t})}}kr();pt();pt();function sq(e=process.env){return!!($e(e)&&e.BOSTRAT_PLANE_TOKEN)}var aq=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),ep=(e,t)=>Object.assign(new Error(e),{status:t});async function r$(e,t){if(!sq(t))throw ep("node is not plane-linked \u2014 Gmail unavailable",503);let n;try{n=await fetch(`${$e(t)}${e}`,{headers:aq(t)})}catch(o){throw ep(`plane unreachable \u2014 Gmail unavailable (${o?.message||o})`,503)}let r=await n.json().catch(()=>({}));if(!n.ok)throw ep(r?.error||`plane replied ${n.status}`,n.status);return r}async function o$(e,{max:t=10,env:n=process.env}={}){let r=new URLSearchParams({q:e||""});return t&&r.set("max",String(t)),(await r$(`/v1/gmail/messages?${r.toString()}`,n)).messages||[]}async function s$(e,{env:t=process.env}={}){if(!e)throw ep("message id required",400);return(await r$(`/v1/gmail/messages/${encodeURIComponent(e)}`,t)).message}Ni();$u();function iy(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 iq(e){let[t,n]=e.split("/"),r=iy(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 a$(e){return(e||"").split(",").map(t=>t.trim()).filter(Boolean).map(iq).filter(Boolean)}function cq(e){let t=e.headers["fly-client-ip"];return typeof t=="string"&&t.trim()?t.trim():(e.socket&&e.socket.remoteAddress||"").replace(/^::ffff:/,"")}function i$(e){let t=a$(e),n=String(e||"").trim().toLowerCase()==="open";return{open:n,clientIp:cq,allowed(r){if(n)return!0;let o=iy((r||"").replace(/^::ffff:/,""));return o==null?!1:t.some(s=>s(o))}}}function c$(e,t){let n=a$(e);return{active:n.length>0,allows(r){if(!n.length)return!1;let o=(r.socket&&r.socket.remoteAddress||"").replace(/^::ffff:/,""),s=iy(o);if(s==null||!n.some(i=>i(s)))return!1;let a=t(r);return!!(a&&a.view)}}}import l$ from"node:crypto";import tp from"node:fs";import lq from"node:path";function u$(e=process.env,{stateDir:t=_c,log:n=console}={}){let r=String(e.BOSTRAT_NODE_API_TOKEN||"").trim();if(r)return r;let o=lq.join(t,"api-token");try{let a=tp.readFileSync(o,"utf8").trim();if(a)return a}catch{}let s=l$.randomBytes(32).toString("base64url");try{tp.mkdirSync(t,{recursive:!0}),tp.writeFileSync(o,s+`
742
- `,{mode:384}),tp.chmodSync(o,384)}catch(a){n.error?.(`[bostrat-agent] could not persist the node API token: ${a?.message||a}`)}return s}function Gc(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 d$(e,t){if(!e||!t)return!1;let n=Buffer.from(String(e)),r=Buffer.from(String(t));return n.length!==r.length?!1:l$.timingSafeEqual(n,r)}function p$(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 uq=[/^\/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/],dq=e=>uq.some(t=>t.test(e));function f$({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=p$(o);return d$(c,e)?a():dq(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||Gc(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 m$(e,t,{enforce:n=!0}={}){return!n||d$(p$(e),t)?!0:Gc(e)}kn();ed();ed();import pq from"node:http";import fq from"node:net";function np(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 rp(e){let t=np(e.headers.host);return t?{slug:t,view:Fh(t)}:null}var mq=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;"),hq=e=>{let t=mq(e.name);return`<!doctype html><meta charset="utf-8">
731
+ _${o} archived_`:"")}async function $H(e,t){let n=await ts();if(!n)return Le("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 Le("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?(so(MI(e,n,{name:u,repo:l.path,responseUrl:t.response_url})),Le(`Starting *${ve(u)}* on ${ve(l.name)}\u2026`)):{response_type:"ephemeral",text:`Pick a repo for \u201C${u}\u201D`,blocks:_H(u,i)}}case"archive":{if(!a.length)return Le("Usage: `/bostrat archive <track>`");let{match:i,live:c}=zg(await r.listTracks(),a.join(" "));return i?(so(TH(e,n,{track:i,responseUrl:t.response_url})),Le(`Archiving *${ve(i.name)}*\u2026`)):Vg(c,a.join(" "))}case"handoff":{let i=r.knownAgents??SH,c=a.at(-1)?.toLowerCase();if(a.length<2||!i.includes(c))return Le(`Usage: \`/bostrat handoff <track> <${i.join("|")}>\``);let l=a.slice(0,-1).join(" "),{match:u,live:d}=zg(await r.listTracks(),l);return u?(so(AH(e,n,{track:u,agent:c,responseUrl:t.response_url})),Le(`Handing *${ve(u.name)}* to ${ve(c)}\u2026`)):Vg(d,l)}case"stop":{if(!a.length)return Le("Usage: `/bostrat stop <track>`");let{match:i,live:c}=zg(await r.listTracks(),a.join(" "));return i?(so(EH(e,n,{track:i,responseUrl:t.response_url})),Le(`Stopping *${ve(i.name)}*\u2026`)):Vg(c,a.join(" "))}case"list":return Le(await IH(r));default:return Le(vH)}}async function RH(e,t,n,r){let{trackId:o,promptId:s,label:a}=r,i=await Zg(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 fn(),await os(t.botToken,{channel:i.channel,ts:c,text:`\u2713 ${a}`,blocks:[{type:"section",text:{type:"mrkdwn",text:`~${ve(l||"question")}~
732
+ \u2713 *${ve(a)}*`}}]}).catch(()=>{})}}catch(c){await xt(n.response_url,Le(`Couldn't answer: ${c?.message||c}`))}}async function OH(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)?Fr.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,zs(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 xt(n.response_url,Le(`Couldn't act on the offer: ${c?.message||c}`))}}async function CH(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 xt(n.response_url,Le(`Couldn't act on the offer: ${i?.message||i}`))}}async function MH(e,t){let n=t.actions?.[0];if(!n?.action_id)return;let r=await ts();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 xt(t.response_url,{...Le(`Starting *${ve(s)}*\u2026`),replace_original:!0}),so(MI(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"?so(RH(e,r,t,o)):n.action_id==="bostrat-ship"?so(OH(e,r,t,o)):n.action_id==="bostrat-pr-exists"&&so(CH(e,r,t,o))}async function NH(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 kH(t.channel,t.thread_ts);if(!n)return;let r=await ts();if(r)try{await e.deps.sayToLead(n.trackId,t.text.trim())}catch(o){await ao(r,n.rec,`Couldn't deliver that to the lead: ${o?.message||o}`).catch(()=>{})}}function PH(e){return async t=>{if(t.type==="slash_commands")return $H(e,t.payload);if(t.type==="interactive"){await MH(e,t.payload);return}if(t.type==="events_api"){await NH(e,t.payload?.event);return}}}var DH=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 BH(e,t){let n=[{type:"section",text:{type:"mrkdwn",text:`\u2753 ${ve(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:jc(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 jH(e,t,n){let r=n.payload||{};if(!r.promptId||t.prompt?.promptId===r.promptId)return;t.prompt&&await os(e.botToken,{channel:t.channel,ts:t.prompt.ts,text:"superseded",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${ve(t.prompt.question||"question")}~ _superseded_`}}]}).catch(()=>{});let o=await ao(e,t,r.question||"The lead needs an answer",BH(n.trackId,r));t.prompt={promptId:r.promptId,ts:o.ts,question:r.question||null},await fn()}async function LH(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 fn(),await os(e.botToken,{channel:t.channel,ts:o,text:"answered",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${ve(s||"question")}~
733
+ \u2713 _answered_`}}]})}async function FH(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 ao(e,t,r.excerpt||"Ship it?",[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${ve(jc(r.excerpt||"The lead offered to ship.",300))}`}},{type:"actions",elements:s}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await fn()}async function UH(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await fn();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 os(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function HH(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 ao(e,t,`PR ${o} already open \u2014 push or new PR?`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${o}${r.branch?` (${ve(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 fn()}async function WH(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await fn();let s=r.choice==="dismiss"?"dismissed":r.choice==="new"?"\u2713 opening a new PR":"\u2713 pushing to the open PR";await os(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function qH(e,t,n,r){let o=n.payload||{};if(o.change==="ready"&&o.mockId){let s=await(r.readMockPng??KH)(o.mockId,o.version??null);if(!s)return;let a=(o.version??1)>1?` (v${o.version})`:"";await _I(e.botToken,{filename:s.filename,buffer:s.buffer,title:`${o.name}${a}`,channelId:t.channel,threadTs:t.ts,initialComment:`\u{1F3A8} mock *${ve(o.name)}*${a}${o.group?` (group \`${ve(o.group)}\`)`:""}`})}else if(o.change==="picked"){let s=(o.siblings??[]).map(a=>`*${ve(a.name)}*`).join(", ");await ao(e,t,`Design decision: ${o.name} picked`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F3A8} design decision: *${ve(o.name)}* picked${s?` over ${s}`:""}`}}])}}async function KH(e,t){let n=await cr(e);if(!n)return null;let r=an(n,t);if(!r)return null;let o=await Bc.readFile(zt(n,r.v).png).catch(()=>null);return o?{filename:`${n.name.replace(/[^\w.-]+/g,"-")}.v${r.v}.png`,buffer:o}:null}async function GH(e,t){if(!DH.has(t.type))return;let n=await Zg(t.trackId);if(!n)return;let r=await ts();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 fn(),await Yg(r,n);return;case"turn.agent":{if(!o.text)return;let s=xH(o.text);if(!s)return;await ao(r,n,s,[{type:"section",text:{type:"mrkdwn",text:ve(s)}},{type:"context",elements:[{type:"mrkdwn",text:`<${Wd(t.trackId)}|full turn \u2192>`}]}]);return}case"prompt.raised":return jH(r,n,t);case"prompt.answered":return LH(r,n,t);case"pr.offered":return FH(r,n,t);case"pr.offer.answered":return UH(r,n,t);case"pr.exists.offered":return HH(r,n,t);case"pr.exists.answered":return WH(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 ao(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 fn(),await Yg(r,n);return;case"view.state.changed":{if(o.change!=="created"||o.restarted||!o.slug)return;await ao(r,n,`Live preview ${o.name}: ${qd(o.slug)}`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F50D} live preview *${ve(o.name)}*: ${qd(o.slug)}
734
+ _runs on the Track's branch; reachable on the operator's private network only_`}}]);return}case"mock.state.changed":return qH(r,n,t,e.deps)}}function NI(e){let t={deps:e};ot.on("event",s=>{GH(t,s).catch(()=>{})});let n=null,r=null,o=async()=>{n||!await ts()||(r&&clearInterval(r),r=null,n=II({getToken:async()=>(await ts())?.appToken,onEnvelope:PH(t),log:s=>console.log(`[slack] ${s}`)}))};return r=setInterval(()=>o().catch(()=>{}),3e4),r.unref?.(),o().catch(()=>{}),()=>{r&&clearInterval(r),n?.()}}nn();de();kn();lh();Vn();import zH from"node:fs/promises";function VH(e){let t=new Map;for(let n of String(e||"").split(`
735
+ `)){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 JH(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 YH=new Set(["Write","Edit","NotebookEdit"]),XH=220,ZH=160;function QH(e,t){let n=e?.tool_name??null,r={tool:n},o=e?.tool_input;if(!o||typeof o!="object")return r;if(YH.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,XH)}else n==="Bash"&&typeof o.command=="string"&&o.command.trim()&&(r.head=go(o.command.trim().replace(/\s+/g," ")).slice(0,ZH));return r}function eW(e,t){return e?.transcript_path?e.transcript_path:t?.cwd&&t?.sessionId?tn(t.cwd,t.sessionId):t?.cwd?af(t.cwd):null}async function PI(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=Ku(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:QH(e,o)});break;case"Stop":await tW(r,o,e,i);break;default:break}return a}async function tW(e,t,n,r){let o=[],s=eW(n,t);if(s)try{o=VH(await zH.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=JH(await K(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:Tn(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}})}ds();Zp();qu();de();de();Pr();de();Pr();Vn();function Lc(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 DI=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),BI=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},Vd=e=>Math.round(e*1e4)/1e4;async function Qg(e){let t=[],n={},r={},o=0,s=0,a=0,i=0,c=0,l=new Set,u=DI(),d=0,p=[];for(let f of e||[]){let w=await K(f),m=Nr(w,{boxLabels:Lc(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);BI(u,m.totalTokens);for(let[g,b]of Object.entries(m.byModel))n[g]||={usd:0,events:0,tokens:DI()},n[g].usd=Vd(n[g].usd+b.usd),n[g].events+=b.events,BI(n[g].tokens,b.tokens);for(let[g,b]of Object.entries(m.byProvider))r[g]||={usd:0,events:0},r[g].usd=Vd(r[g].usd+b.usd),r[g].events+=b.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:Ps(),fleet:{totalUsd:Vd(o),asRecordedUsd:Vd(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 io=e=>`$${e.toFixed(4)}`,Ea=(e,t)=>String(e).padEnd(t);function jI(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 ${io(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 ${io(t.asRecordedUsd)} \xB7 current-rates total ${io(t.totalUsd)} (${t.totalUsd>=t.asRecordedUsd?"+":""}${io(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(` ${Ea(a,26)} ${Ea(io(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(` ${Ea(a.name||a.id,30)} ${io(a.usd)}`);let i=Object.values(a.rollup.byBox).sort((c,l)=>l.usd-c.usd);for(let c of i)if(r.push(` ${Ea(c.label,40)} ${Ea(io(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))}${Ea(io(u.usd),10)} ${u.models.join(",")||"?"}`)}return r.join(`
736
+ `)}de();Cm();import cW from"node:fs/promises";import lW from"node:path";Gl();Xl();Pr();var Jd=e=>e.payload?.ts??e.ts,nW=12e4,Jt=e=>Math.round(e*1e4)/1e4,rW=()=>({usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{},byTrack:new Map});function oW(e,{since:t}){let{track:n,events:r,brief:o}=e,s=y=>Jd(y)>=t,a=zn([xi(n?.name),xi(n?.workspace?.branch),o].filter(Boolean).join(" ")),i=new Map;for(let y of r)if(y.type==="subtask.delegated"&&y.boxId&&y.payload?.task){let $=zn(y.payload.task);$&&i.set(y.boxId,$)}let c=new Map,l=y=>{let $=y||"unattributed";return c.has($)||c.set($,{segments:[u(null)],lastTs:null,provider:null}),c.get($)},u=(y,{shape:$="initial",continuation:O=!1,text:M=null,ts:H=null}={})=>({textCat:y,shape:$,continuation:O,text:M,ts:H,tools:{},usd:0,tokens:{input:0,output:0,cacheRead:0,cacheWrite:0},models:{},provider:null,activeMs:0,turns:0,toolCalls:0}),d=[...r].sort((y,$)=>Jd(y)-Jd($)),p=0,f=0,w=0,m={turns:0};for(let y of d){let $=l(y.boxId),O=$.segments[$.segments.length-1],M=Jd(y);switch($.lastTs!=null&&M>$.lastTs&&s(y)&&(O.activeMs+=Math.min(M-$.lastTs,nW)),$.lastTs=M,y.provider&&($.provider=y.provider),y.type){case"turn.user":{let H=y.payload?.text;if(y.source==="hook"||!String(H||"").trim()||y.payload?.note||Ti(H))break;let P=zn(H),E=!!y.payload?.kind,R=E||c0(H),G=u(P,{shape:E?"injected":R?"follow-up":"novel-ask",continuation:!P&&R,text:FI(H),ts:M});$.segments.push(G),s(y)&&(G.turns+=1);break}case"peer.message":{let H=y.payload?.text;if(!String(H||"").trim())break;let P=zn(H),E=u(P,{shape:"peer",continuation:!P,text:FI(H),ts:M});$.segments.push(E),s(y)&&(E.turns+=1);break}case"tool.called":{if(y.source==="transcript")break;let H=y.payload?.tool;H&&(O.tools[H]=(O.tools[H]||0)+1),s(y)&&(O.toolCalls+=1);break}case"cost.recorded":{if(!s(y))break;let{usd:H,tokens:P,model:E,unpriced:R}=Wt(y);R&&(m.turns+=1),O.usd+=H,P&&(O.tokens.input+=P.input,O.tokens.output+=P.output,O.tokens.cacheRead+=P.cacheRead,O.tokens.cacheWrite+=P.cacheWrite),O.models[E]=(O.models[E]||0)+H,y.provider&&(O.provider=y.provider);break}case"handoff.done":s(y)&&(p+=1);break;case"subtask.merged":s(y)&&(f+=1);break;case"error":s(y)&&y.payload?.kind==="subtask-failed"&&(w+=1);break;default:break}}let g=new Map,b={usd:0,turns:0,byShape:{},samples:[]},x=!1;for(let[y,$]of c){let O=null;for(let M of $.segments){let H=null,P=null;if(M.textCat)H=M.textCat.category,P="text";else if(i.get(y))H=i.get(y).category,P="boxTask";else if(M.continuation&&O)H=O,P="inherited";else{let A=i0(M.tools);A?(H=A.category,P="toolMix"):a&&(H=a.category,P="hint")}if(H&&(O=H),!(M.usd>0||M.activeMs>0||M.turns>0||M.toolCalls>0))continue;let R=H??"uncategorized";g.has(R)||g.set(R,{usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{}});let G=g.get(R);G.usd+=M.usd,G.activeMs+=M.activeMs,G.turns+=M.turns,G.toolCalls+=M.toolCalls,P&&(G.provenance[P]=(G.provenance[P]||0)+M.usd);for(let[A,_]of Object.entries(M.models))G.models[A]=(G.models[A]||0)+_;let V=M.provider||$.provider;V&&(G.providers[V]=(G.providers[V]||0)+M.usd),V==="cursor"&&M.usd===0&&(x=!0),H||(b.usd+=M.usd,b.turns+=M.turns,b.byShape[M.shape]=(b.byShape[M.shape]||0)+M.usd,M.usd>0&&M.text&&b.samples.push({trackId:n?.id,track:n?.name||n?.id,shape:M.shape,usd:Jt(M.usd),ts:M.ts,text:M.text}))}}return{perCategory:g,uncategorized:b,handoffs:p,merged:f,failed:w,sawCursorActivity:x,unpricedTurns:m.turns}}function ey(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 b of e||[]){let{track:x,events:y}=b;if(!y?.length){a+=1;continue}let{perCategory:$,uncategorized:O,handoffs:M,merged:H,failed:P,sawCursorActivity:E,unpricedTurns:R}=oW(b,{since:r});E&&(i=!0),c+=R,l.usd+=O.usd,l.turns+=O.turns;for(let[V,A]of Object.entries(O.byShape))l.byShape[V]=(l.byShape[V]||0)+A;l.samples.push(...O.samples);let G={trackId:x?.id,name:x?.name||x?.id,archived:!!x?.archivedAt,usd:0,activeMs:0,turns:0,categories:{},models:{},providers:{},handoffs:M,subtasksMerged:H,subtasksFailed:P};for(let[V,A]of $){G.usd+=A.usd,G.activeMs+=A.activeMs,G.turns+=A.turns,G.categories[V]={usd:Jt(A.usd),activeMs:A.activeMs};for(let[U,z]of Object.entries(A.models))G.models[U]=Jt((G.models[U]||0)+z);for(let[U,z]of Object.entries(A.providers))G.providers[U]=Jt((G.providers[U]||0)+z);o.has(V)||o.set(V,rW());let _=o.get(V);_.usd+=A.usd,_.activeMs+=A.activeMs,_.turns+=A.turns,_.toolCalls+=A.toolCalls;for(let[U,z]of Object.entries(A.models))_.models[U]=(_.models[U]||0)+z;for(let[U,z]of Object.entries(A.providers))_.providers[U]=(_.providers[U]||0)+z;for(let[U,z]of Object.entries(A.provenance))_.provenance[U]=(_.provenance[U]||0)+z;let N=_.byTrack.get(x?.id)||{usd:0,activeMs:0};N.usd+=A.usd,N.activeMs+=A.activeMs,_.byTrack.set(x?.id,N)}(G.usd>0||G.activeMs>0||G.turns>0)&&(G.usd=Jt(G.usd),G.dominantCategory=iW(G.categories),s.push(G))}let u=[...o.values()].reduce((b,x)=>b+x.usd,0),d=[...o.values()].reduce((b,x)=>b+x.activeMs,0),p=u>0?"usd":"time",f=p==="usd"?u:d,w=new Map((e||[]).map(b=>[b.track?.id,b.track?.name||b.track?.id])),m=[...o.entries()].map(([b,x])=>({category:b,sharePct:f>0?Math.round((p==="usd"?x.usd:x.activeMs)/f*100):0,shareBasis:p,usd:Jt(x.usd),activeMs:x.activeMs,turns:x.turns,toolCalls:x.toolCalls,models:Fc(x.models),providers:Fc(x.providers),provenance:Fc(x.provenance),topWorkstreams:[...x.byTrack.entries()].sort((y,$)=>$[1].usd-y[1].usd||$[1].activeMs-y[1].activeMs).slice(0,2).map(([y,$])=>({trackId:y,name:w.get(y),usd:Jt($.usd),activeMs:$.activeMs}))})).sort((b,x)=>x.usd-b.usd||x.activeMs-b.activeMs);s.sort((b,x)=>x.usd-b.usd||x.activeMs-b.activeMs);let g={};for(let b of o.values())for(let[x,y]of Object.entries(b.provenance))g[x]=(g[x]||0)+y;return{since:r,capturedAt:n,totalUsd:Jt(u),activeMs:d,turns:[...o.values()].reduce((b,x)=>b+x.turns,0),bullets:m,workstreams:s,provenance:Fc(g),gaps:{tracksWithoutEvents:a,cursorCostUnknown:i,unpricedTurns:c,uncategorized:{usd:Jt(l.usd),turns:l.turns,sharePct:u>0?Math.round(l.usd/u*100):0,byShape:Fc(l.byShape),top:l.samples.sort((b,x)=>x.usd-b.usd).slice(0,sW)}}}}var sW=25,LI=160,FI=e=>{let t=String(e||"").replace(/\s+/g," ").trim();return t.length>LI?`${t.slice(0,LI).trimEnd()}\u2026`:t},aW=10;function UI(e,{thresholdPct:t=aW}={}){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:Jt(o),totalUsd:Jt(r),turns:n.turns||0,inheritedPct:r>0?Math.round((e?.provenance?.inherited||0)/r*100):0,problems:i}}var iW=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},Fc=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Jt(n)]));var as={"24h":24*36e5,"7d":168*36e5,"30d":720*36e5,all:null};function uW(e){let t=String(e||"7d");return t in as?{key:t,ms:as[t]}:{key:"7d",ms:as["7d"]}}function dW(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=yu(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 pW(e){if(!e?.cwd)return null;try{let n=(await cW.readFile(lW.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 ty(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}:uW(t),d=[];for(let w of e||[]){let m=await K(w),g=dW(w,m);i&&c<o&&(g=g.filter(b=>(b.ts??0)<=c)),d.push({track:w,events:g,brief:await pW(w)})}let p=ey(d,{windowMs:u,now:c}),f=l==="7d"&&c===o?p:ey(d,{windowMs:as["7d"],now:o});return{window:l,...p,categorization:UI(f)}}var Uc=e=>`$${Number(e||0).toFixed(2)}`,HI=e=>{let t=Math.round((e||0)/6e4);return t>=60?`${Math.floor(t/60)}h${String(t%60).padStart(2,"0")}`:`${t}m`},ss=(e,t)=>String(e).padEnd(t);function WI(e){let t=[];t.push(`USAGE ROUNDUP \xB7 ${e.window} \xB7 ${Uc(e.totalUsd)} \xB7 ${HI(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(` ${ss(`${a.shareBasis==="time"?"~":""}${a.sharePct}%`,5)} ${ss(a.category,15)} ${ss(Uc(a.usd),10)} ${ss(HI(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 ${Uc(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} ${Uc(i)}`).join(" \xB7 ")||"none")),s.top?.length||t.push(" (nothing unmatched carried cost in this window)");for(let a of s.top||[])t.push(` ${ss(Uc(a.usd),8)} ${ss(a.shape,10)} ${ss(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(`
737
+ `)}Vn();var co=36e5,zI=24*co,fW=400,mW=12,is=e=>Math.round(e*1e4)/1e4;function ny({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 as?String(e||"7d"):"7d",i=as[a];return{key:a,since:i==null?null:r-i,until:r}}var hW=(e,t)=>e!=null&&t-e<=48*co?co:zI;function qI(e,t){if(t===co)return Math.floor(e/co)*co;let n=new Date(e);return n.setHours(0,0,0,0),n.getTime()}function wW(e,t){if(t===co)return e+co;let n=new Date(e);return n.setDate(n.getDate()+1),n.setHours(0,0,0,0),n.getTime()}var KI=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),GI=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},gW=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,is(n)]));async function VI(e,t={}){let n=t.now??Date.now(),r=ny({...t,now:n}),o=r.since==null?zI:hW(r.since,r.until),s=E=>(r.since==null||E>=r.since)&&E<r.until,a=r.since!=null?r.until-r.since:null,i=E=>a!=null&&E>=r.since-a&&E<r.since,c={},l={},u=KI(),d=0,p=0,f=0,w=0,m=0,g=0,b=new Set,x=new Map,y=[],$=[],O=[],M=null;for(let E of e||[]){let G=(await K(E)).filter(_=>_.type==="cost.recorded");if(!G.length){E.archivedAt||O.push(E.name||E.id);continue}let V=[];for(let _ of G){let N=_.ts??0;s(N)?V.push(_):i(N)&&(g+=Wt(_).usd)}if(!V.length)continue;let A=Nr(V,{boxLabels:Lc(E)});d+=A.totalUsd,p+=A.turns,f+=A.repricedTurns||0,w+=A.asRecordedUsd||0,m+=A.unpricedTurns||0;for(let _ of A.unpricedModels||[])b.add(_);GI(u,A.totalTokens);for(let[_,N]of Object.entries(A.byModel))c[_]||={usd:0,events:0,tokens:KI()},c[_].usd=is(c[_].usd+N.usd),c[_].events+=N.events,GI(c[_].tokens,N.tokens);for(let[_,N]of Object.entries(A.byProvider))l[_]||={usd:0,events:0},l[_].usd=is(l[_].usd+N.usd),l[_].events+=N.events;for(let _ of V){let{usd:N}=Wt(_);if(!N)continue;let U=qI(_.ts??0,o),z=x.get(U)??{t:U,total:0,byProvider:{}};z.total+=N;let ue=_.provider||"unknown";z.byProvider[ue]=(z.byProvider[ue]||0)+N,x.set(U,z),(M==null||U<M)&&(M=U)}y.push({id:E.id,name:E.name||E.id,archived:!!E.archivedAt,usd:A.totalUsd,turns:A.turns,providers:Object.keys(A.byProvider)});for(let[_,N]of Object.entries(A.byBox))$.push({trackId:E.id,trackName:E.name||E.id,boxId:_,...N})}let H=r.since!=null?qI(r.since,o):M,P=[];for(let E=H,R=0;E!=null&&E<r.until&&R<fW;E=wW(E,o),R++){let G=x.get(E);P.push(G?{t:E,total:is(G.total),byProvider:gW(G.byProvider)}:{t:E,total:0,byProvider:{}})}return y.sort((E,R)=>R.usd-E.usd),$.sort((E,R)=>R.usd-E.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",pricing:Ps(),window:r.key,since:r.since,until:r.until,bucketMs:o,series:P,fleet:{totalUsd:is(d),asRecordedUsd:is(w),turns:p,repricedTurns:f,unpricedTurns:m,unpricedModels:[...b],totalTokens:u,byModel:c,byProvider:l,tracksWithCost:y.length,tracksSilentLive:O},prior:a!=null?{totalUsd:is(g),since:r.since-a,until:r.since}:null,tracks:y.slice(0,50),boxes:$.slice(0,mW)}}Hu();var yW=new Set(["cost.recorded","code.committed","code.rework","rework.cause.offered","rework.cause.answered"]),bW=20,kW=40;async function JI(e,t={}){let n=t.now??Date.now(),r=ny({...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 K(l),d=0,p=Lc(l);for(let f of u){if(!yW.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=ZS(s,{boxMeta:a});return{generatedAt:new Date().toISOString(),window:r.key,since:r.since,until:r.until,reworkWindowDays:zr,decayEndDays:Qm,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,bW),fixes:c.fixes.slice(0,kW)}}import xW from"node:fs";import YI from"node:fs/promises";import Hc from"node:os";import vW from"node:path";Kh();ct();var SW=1024*1024,Yd=e=>Math.round(e/SW);async function TW(e){try{let t=await YI.statfs(e),n=t.blocks*t.bsize,r=n-t.bavail*t.bsize;return{diskUsedMb:Yd(r),diskTotalMb:Yd(n)}}catch{return{diskUsedMb:null,diskTotalMb:null}}}async function AW(){try{return(await Qt()).filter(t=>t.isBostrat).length}catch{return null}}async function EW(){let e=0,t=!1;for(let n of["workspaces","worktrees"])try{let r=await YI.readdir(vW.join(_c,n),{withFileTypes:!0});e+=r.filter(o=>o.isDirectory()).length,t=!0}catch{}return t?e:null}async function XI({stateDir:e=_c,now:t=Date.now}={}){let n=Hc.totalmem(),[r,o,s,a]=await Promise.all([sd().catch(()=>null),TW(xW.existsSync(e)?e:Hc.tmpdir()),AW(),EW()]),i=Hc.cpus()?.length||null,c=Hc.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?Yd(n-r):null,memTotalMb:Yd(n),...o,boxes:s,worktrees:a,procUptimeS:Math.round(process.uptime()),osUptimeS:Math.round(Hc.uptime())}}Ih();de();Cf();Va();Vn();de();Vn();var _W=864e5;function IW(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=Tn(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 ZI(e,{days:t=14,tolerance:n=.005,now:r=Date.now()}={}){let o=r-t*_W,s={},a=0,i=0,c=[];for(let u of e||[]){let d=await K(u);for(let p of d){if(!p.ts||p.ts<o)continue;let f=IW(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}}Ah();mw();hu();pt();An();import _a from"node:fs/promises";import $W from"node:fs";import mt from"node:path";import RW from"node:os";import{execFile as OW}from"node:child_process";import{promisify as CW}from"node:util";var MW=CW(OW),QI=process.env.BOSTRAT_STATE_DIR||mt.join(process.env.HOME||RW.tmpdir(),".bostrat"),Xd=!1,ry=null;async function oy(e,t){let n=await _a.stat(e).catch(()=>null);if(!n?.isFile())return!1;let r=await _a.stat(t).catch(()=>null);return r&&r.size===n.size&&r.mtimeMs>=n.mtimeMs?!1:(await _a.mkdir(mt.dirname(t),{recursive:!0}),await _a.copyFile(e,t),!0)}var NW=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 Zd(e,t,{skip:n=null}={}){let r=0,o=await _a.readdir(e,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(NW.has(s.name)||n?.has(s.name))continue;let a=mt.join(e,s.name);s.isDirectory()?r+=await Zd(a,mt.join(t,s.name)):s.isFile()&&(r+=await oy(a,mt.join(t,s.name))?1:0)}return r}async function e$({stateDir:e=QI,dest:t=process.env.BOSTRAT_SYNC_DIR||`${QI}-sync`,remote:n=process.env.BOSTRAT_STATE_REMOTE||null,tracks:r=null}={}){try{await _a.mkdir(t,{recursive:!0});let o=0;o+=await oy(mt.join(e,"tracks.json"),mt.join(t,"tracks.json"))?1:0,o+=await oy(mt.join(e,"events.jsonl"),mt.join(t,"events.jsonl"))?1:0,o+=await Zd(mt.join(e,"events"),mt.join(t,"events")),o+=await Zd(mt.join(e,"memory"),mt.join(t,"memory"));let s=new Set(["mocks"]);for(let u of r||[])!u?.cwd||!u?.id||(o+=await Zd(mt.join(u.cwd,".bostrat"),mt.join(t,"workspaces",u.id,".bostrat"),{skip:s}));let a=(...u)=>MW("git",["-C",t,...u]);$W.existsSync(mt.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 Np(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||Xd))try{await a("push","-q",n,"HEAD:refs/heads/main"),l=!0,Xd&&console.log("[state-sync] push recovered \u2014 off-box copy is current again"),Xd=!1,ry=null}catch(u){Xd=!0;let d=(u?.stderr||u?.message||String(u)).trim().split(`
738
+ `).slice(-3).join(" | ").slice(0,300);d!==ry&&(ry=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)}}}uw();nn();vo();ct();Ua();import{execFile as PW}from"node:child_process";import{promisify as DW}from"node:util";import{randomUUID as BW}from"node:crypto";import jW from"node:fs";import LW from"node:os";import FW from"node:path";var uo=DW(PW),Qd=e=>new Promise(t=>setTimeout(t,e)),po=tf,sy=process.env.BOSTRAT_USAGE_PROBE_CWD||FW.join(LW.homedir(),".bostrat","usage-probe"),UW=Number(process.env.BOSTRAT_USAGE_IDLE_REAP_MS)||5*6e4,HW=Number(process.env.BOSTRAT_USAGE_PANEL_TIMEOUT_MS)||15e3,WW=Number(process.env.BOSTRAT_USAGE_READY_TIMEOUT_MS)||45e3,t$=Number(process.env.BOSTRAT_USAGE_CACHE_MS)||2e4,lo=null,Wc=null,qc=null;async function qW(){try{return await uo(X,Z("has-session","-t",po)),!0}catch{return!1}}function KW(){lo&&clearTimeout(lo),lo=setTimeout(()=>GW().catch(()=>{}),UW),lo.unref&&lo.unref()}async function GW(){lo&&(clearTimeout(lo),lo=null);try{await uo(X,Z("kill-session","-t",po))}catch{}}async function zW(){let e=Date.now()+WW;for(;;){let t=await ay().catch(()=>"");if(/for agents|for shortcuts|bypass permissions on/i.test(t)){await Qd(500);return}if(Date.now()>e)throw new Error("usage probe didn't reach the prompt (trust/onboarding may be blocking)");await Qd(500)}}async function VW(){if(await qW())return;if(!await Er())throw new Error("host tmux server not running \u2014 start globo-tmux.service");jW.mkdirSync(sy,{recursive:!0}),await yr(sy);let e=BW();await uo(X,Z("new-session","-d","-s",po,"-c",sy,"-x","200","-y","60",...ri()));let t=`${ef} --session-id ${e}`;await uo(X,Z("send-keys","-t",po,t,"Enter")),await zW()}async function ay(){let{stdout:e}=await uo(X,Z("capture-pane","-t",po,"-p"));return e}async function JW(){await VW(),await uo(X,Z("send-keys","-t",po,"-l","/usage")),await uo(X,Z("send-keys","-t",po,"Enter"));let e=Date.now()+HW,t="";for(;await Qd(400),t=await ay(),!(/Current\s+(session|week)/i.test(t)||/\d+%\s*used/i.test(t)||Date.now()>e););return await Qd(900),t=await ay(),await uo(X,Z("send-keys","-t",po,"Escape")).catch(()=>{}),KW(),t}function YW(e){let t=String(e||"").split(`
739
+ `).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 XW(e){let t=String(e||"").split(`
740
+ `).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 n$({fresh:e=!1}={}){return!e&&Wc&&Date.now()-Wc.at<t$?Wc.data:qc||(qc=(async()=>{try{let t=await JW(),n=YW(t),r={...n,contributors:XW(t),subscription:!!(n.session||n.week||n.weekModels),capturedAt:Date.now()};return Wc={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 Wc={at:Date.now()-(t$-3e3),data:n},n}finally{qc=null}})(),qc)}var ZW=262144;function QW(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 eq=new Set([300]),tq=new Set([10080]);function nq(e){let t=Number(e);return!Number.isFinite(t)||t<=0?null:eq.has(t)?"session":tq.has(t)?"week":"other"}function rq(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 oq(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?QW((o-n)/1e3):null,resetsAt:o}}var Kc=e=>({session:null,week:null,other:null,planType:null,credits:null,limitReached:null,sawTokenCount:e});function sq(e,t=Date.now()){let n=String(e||"").split(`
741
+ `),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 Kc(r);if(c.primary||c.secondary){let l=Date.parse(a.timestamp)||null,u=Kc(r);[c.primary,c.secondary].forEach((f,w)=>{let m=oq(f,l,t);if(!m)return;let g=nq(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:rq(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{...Kc(r),session:l(c.primary_used_percent),week:l(c.secondary_used_percent)}}return Kc(r)}return Kc(r)}async function iy(e){let t={provider:"codex",supported:!0,contributors:null};try{let n=await ko(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 _t(n.file,ZW),o=sq(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 r$(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 ep({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 iy(i);if(c.subscription){a=c;break}(!a||a.error&&!c.error)&&(a=c)}r.push(a||await iy(null))}return n.has("cursor")&&r.push(await ep({agent:"cursor"})),{providers:r,capturedAt:Date.now()}}async function ep(e,{fresh:t=!1}={}){let n=e?.agent||"claude";return n==="codex"?iy(e):n==="cursor"?{provider:"cursor",supported:!1,subscription:!1,session:null,week:null,contributors:null,capturedAt:Date.now()}:{provider:"claude",supported:!0,...await n$({fresh:t})}}kr();pt();pt();function aq(e=process.env){return!!($e(e)&&e.BOSTRAT_PLANE_TOKEN)}var iq=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),tp=(e,t)=>Object.assign(new Error(e),{status:t});async function o$(e,t){if(!aq(t))throw tp("node is not plane-linked \u2014 Gmail unavailable",503);let n;try{n=await fetch(`${$e(t)}${e}`,{headers:iq(t)})}catch(o){throw tp(`plane unreachable \u2014 Gmail unavailable (${o?.message||o})`,503)}let r=await n.json().catch(()=>({}));if(!n.ok)throw tp(r?.error||`plane replied ${n.status}`,n.status);return r}async function s$(e,{max:t=10,env:n=process.env}={}){let r=new URLSearchParams({q:e||""});return t&&r.set("max",String(t)),(await o$(`/v1/gmail/messages?${r.toString()}`,n)).messages||[]}async function a$(e,{env:t=process.env}={}){if(!e)throw tp("message id required",400);return(await o$(`/v1/gmail/messages/${encodeURIComponent(e)}`,t)).message}Ni();$u();function cy(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 cq(e){let[t,n]=e.split("/"),r=cy(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 i$(e){return(e||"").split(",").map(t=>t.trim()).filter(Boolean).map(cq).filter(Boolean)}function lq(e){let t=e.headers["fly-client-ip"];return typeof t=="string"&&t.trim()?t.trim():(e.socket&&e.socket.remoteAddress||"").replace(/^::ffff:/,"")}function c$(e){let t=i$(e),n=String(e||"").trim().toLowerCase()==="open";return{open:n,clientIp:lq,allowed(r){if(n)return!0;let o=cy((r||"").replace(/^::ffff:/,""));return o==null?!1:t.some(s=>s(o))}}}function l$(e,t){let n=i$(e);return{active:n.length>0,allows(r){if(!n.length)return!1;let o=(r.socket&&r.socket.remoteAddress||"").replace(/^::ffff:/,""),s=cy(o);if(s==null||!n.some(i=>i(s)))return!1;let a=t(r);return!!(a&&a.view)}}}import u$ from"node:crypto";import np from"node:fs";import uq from"node:path";function d$(e=process.env,{stateDir:t=_c,log:n=console}={}){let r=String(e.BOSTRAT_NODE_API_TOKEN||"").trim();if(r)return r;let o=uq.join(t,"api-token");try{let a=np.readFileSync(o,"utf8").trim();if(a)return a}catch{}let s=u$.randomBytes(32).toString("base64url");try{np.mkdirSync(t,{recursive:!0}),np.writeFileSync(o,s+`
742
+ `,{mode:384}),np.chmodSync(o,384)}catch(a){n.error?.(`[bostrat-agent] could not persist the node API token: ${a?.message||a}`)}return s}function Gc(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 p$(e,t){if(!e||!t)return!1;let n=Buffer.from(String(e)),r=Buffer.from(String(t));return n.length!==r.length?!1:u$.timingSafeEqual(n,r)}function f$(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 dq=[/^\/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/],pq=e=>dq.some(t=>t.test(e));function m$({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=f$(o);return p$(c,e)?a():pq(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||Gc(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 h$(e,t,{enforce:n=!0}={}){return!n||p$(f$(e),t)?!0:Gc(e)}kn();td();td();import fq from"node:http";import mq from"node:net";function rp(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 op(e){let t=rp(e.headers.host);return t?{slug:t,view:Uh(t)}:null}var hq=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;"),wq=e=>{let t=hq(e.name);return`<!doctype html><meta charset="utf-8">
743
743
  <meta http-equiv="refresh" content="3">
744
744
  <title>${t} \u2014 starting</title>
745
745
  <body style="font-family:system-ui;background:#0b0e14;color:#dce3f0;display:grid;place-items:center;height:100vh;margin:0">
746
746
  <div style="text-align:center"><p style="font-size:2rem;margin:0">\u23F3</p>
747
- <p><b>${t}</b> is waking up\u2026</p><p style="opacity:.6">auto-refreshing</p></div>`};function h$(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 w$(e,t,n){let r=rp(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(hq(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=pq.request({host:"127.0.0.1",port:o.port,method:e.method,path:h$(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 g$(e,t,n){let r=rp(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
747
+ <p><b>${t}</b> is waking up\u2026</p><p style="opacity:.6">auto-refreshing</p></div>`};function w$(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 g$(e,t,n){let r=op(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(wq(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=fq.request({host:"127.0.0.1",port:o.port,method:e.method,path:w$(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 y$(e,t,n){let r=op(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
748
748
  \r
749
749
  bostrat: no live view "${s}"\r
750
- `),t.destroy(),!0;let a=fq.connect(o.port,"127.0.0.1",()=>{let c=[`${e.method} ${h$(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
750
+ `),t.destroy(),!0;let a=mq.connect(o.port,"127.0.0.1",()=>{let c=[`${e.method} ${w$(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
751
751
  `)+`\r
752
752
  \r
753
- `),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 y$(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}.${wq(n.host)}/`}function wq(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 np(t)&&Fh(n[0])?n.slice(1).join("."):t}ca();Zh();ld();dh();de();import b$ from"node:os";import{randomUUID as ly}from"node:crypto";var gq=(e=process.env)=>({nodeId:e.BOSTRAT_NODE_ID||b$.hostname(),nodeName:e.BOSTRAT_NODE_NAME||b$.hostname()});var k$=32768,x$=120,v$=1e3,S$=new Set(["claude","codex","cursor"]),yq=new Set(["off","transition","nag"]),bq=[[0,59],[0,23],[1,31],[1,12],[0,6]];function kq(e){let t=String(e??"").trim().split(/\s+/);return t.length!==5?!1:t.every((n,r)=>{let[o,s]=bq[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 mn=e=>String(e??"").trim(),cs={name(e){let t=mn(e);if(!t)throw new Error("a loop needs a name");if(t.length>x$)throw new Error(`name is too long (${t.length}); cap is ${x$}`);return t},schedule(e){let t=mn(e);if(!t)throw new Error('a loop needs a schedule (5-field UTC crontab, e.g. "0 7 * * *")');if(!kq(t))throw new Error(`invalid cron schedule: "${t}" \u2014 5 UTC fields, e.g. "0 7 * * *"`);return t},prompt(e){let t=mn(e);if(!t)throw new Error("a loop needs a prompt \u2014 it is what the run does");if(t.length>k$)throw new Error(`prompt is too long (${t.length} chars); cap is ${k$}`);return t},expectation(e){let t=mn(e)||null;if(t&&t.length>v$)throw new Error(`expectation is too long (${t.length}); cap is ${v$}`);return t},notify(e){let t=mn(e)||"off";if(!yq.has(t))throw new Error(`notify must be one of off | transition | nag, got "${e}"`);return t},assignment(e){let t=e??null,n=mn(typeof t=="string"?t:t?.provider)||"claude";if(!S$.has(n))throw new Error(`unknown provider "${n}" \u2014 one of ${[...S$].join(", ")}`);let r=typeof t=="object"&&t&&mn(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 xq(e,t){let n=e&&typeof e=="object"?e:{},r=cs.name(n.name),o=cs.schedule(n.schedule),s=cs.prompt(n.prompt),a=cs.expectation(n.expectation),i=cs.notify(n.notify),c=cs.assignment(n.assignment),l=mn(t?.workspace?.repo)||mn(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}=gq();return{name:r,schedule:o,prompt:s,expectation:a,notify:i,assignment:c,repo:l,nodeId:u||null,nodeName:d||null}}async function A$(e,t){let n=xq(t,e),r=ly();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 E$(e,t,n,{loopId:r=null,nextFireAt:o=null}={}){if(!t)throw new Error("proposalId required");let s=await K({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 cy=["name","schedule","prompt","expectation","notify","assignment","enabled"],vq=(e,t)=>(e?.provider??"claude")===(t?.provider??"claude")&&(e?.model??null)===(t?.model??null);function _$(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 I$(e,t){let n=mn(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 Sq(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=>!cy.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: ${cy.join(", ")}`)}let o={};for(let a of cy){if(!(a in n))continue;let i=cs[a](n[a]);(a==="assignment"?vq(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 $$(e,t,n){let r=_$(t),{patch:o,changed:s}=Sq(n,r),a=ly(),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 T$=600;async function R$(e,t,n){let r=mn(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>T$)throw new Error(`reason is too long (${r.length}); cap is ${T$}`);let o=_$(t),s=ly(),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 O$=async(e,t,n)=>{if(!n)throw new Error("proposalId required");let r=await K({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 C$(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 O$(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 M$(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 O$(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}}de();import{randomUUID as Tq}from"node:crypto";var py=20,Aq=300,uy=120,N$=120,P$=2e3,op=new Set(["build","ops","debt","spike"]),D$=new Set(["active","done","abandoned"]),fy=new Set(["circuit.create","circuit.update","circuit.delete"]),Eq=new Set(["person.create","slot.create","slot.update","slot.delete","reservation.create","reservation.update","reservation.delete"]),zc=new Set([...fy,...Eq]),_q=["name","description","status","type"],Iq=["person","startDate","endDate","estUsd"],$q=["person","label","startDate","endDate"],Rq=/^\d{4}-\d{2}-\d{2}$/,Lt=e=>String(e??"").trim(),my=e=>typeof e=="string"&&e.startsWith("@"),L$=864e5;function F$(e){let t=Date.parse(`${e}T00:00:00Z`),n=new Date(t).getUTCDay();return new Date(t-(n+6)%7*L$).toISOString().slice(0,10)}function Oq(e){return new Date(Date.parse(`${F$(e)}T00:00:00Z`)+6*L$).toISOString().slice(0,10)}var j$=(e,t)=>{let n=Lt(e);if(!Rq.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 Cq(e,t){let n=j$(e,"startDate"),r=j$(t,"endDate");if(r<n)throw new Error(`endDate ${r} is before startDate ${n}`);let o=F$(n),s=Oq(r);return{startDate:o,endDate:s,snapped:o!==n||s!==r}}var B$=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},fo=(e,t,n)=>{let r=Lt(e);if(r.length>t)throw new Error(`${n} is too long (${r.length}); cap is ${t}`);return r};function dy(e,t){let n=Lt(t);if(!n)throw new Error("a circuit name or id is required");if(my(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 Mq(e,t){let n=Lt(t);if(!n)throw new Error('a person is required \u2014 "me", a person id, or a row label');if(n==="me"||my(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 Nq(e,t,{allow:n=zc}={}){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>py)throw new Error(`too many ops (${o.length}); cap is ${py} \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=y=>{y.id&&(l.circuits[y.id]={name:y.name,status:y.status,type:y.type??"build",updatedAt:y.updatedAt??null},u[y.id]=y.name)},m=y=>{y.id&&(u[y.id]=y.label)},g=(y,$)=>{let O=Lt(y);if(!O)return null;if(d.has(O))throw new Error(`ref "${O}" is used by two ops \u2014 each ref names one thing`);return d.add(O),u[`@${O}`]=$,O},b=o.map((y,$)=>{let O=y&&typeof y=="object"?y:{},M=Lt(O.op),H=`op ${$+1}`;if(!zc.has(M))throw new Error(`${H}: unknown op "${M}" \u2014 one of ${[...zc].join(", ")}`);if(!n.has(M))throw new Error(`${H}: "${M}" isn't a circuit op \u2014 roadmap changes go through \`bostrat-roadmap propose\` (one card, either CLI)`);let P=A=>{throw new Error(`${H} (${M}): ${A}`)},E=A=>{let _=O.set&&typeof O.set=="object"&&!Array.isArray(O.set)?O.set:null;_||P("needs a `set` object naming the fields to change");let N=Object.keys(_).filter(U=>!A.includes(U));return N.length&&P(`unknown field(s) ${N.join(", ")} \u2014 settable: ${A.join(", ")}`),Object.keys(_).length||P("`set` names no fields"),_},R=A=>{let{startDate:_,endDate:N,snapped:U}=Cq(A.startDate,A.endDate);return U&&(p=!0),{startDate:_,endDate:N,snapped:U}},G=A=>{let _=Mq(a,A);return Lt(A)==="me"&&(f=!0),m(_),{key:_.id??Lt(A),label:_.label}},V=(A,_,N,U,z)=>{let ue=Lt(A);ue||P(`needs a ${U} id`);let pe=_.find(Se=>Se[N]===ue);return pe||P(`no ${U} "${ue}" \u2014 see \`bostrat-roadmap ls\``),z[ue]={...pe},pe};switch(M){case"circuit.create":{let A=fo(O.name,N$,"name");A||P("a circuit needs a name");let _=Lt(O.type)||"build";op.has(_)||P(`bad type "${_}" (${[...op].join(" | ")})`);let N=s.find(z=>String(z.name).toLowerCase()===A.toLowerCase());N&&P(`a circuit named "${N.name}" already exists (${N.id}) \u2014 update it instead of making a twin`);let U=g(O.ref,A);return{op:M,...U?{ref:U}:{},name:A,description:fo(O.description,P$,"description"),type:_}}case"circuit.update":{let A=dy(s,O.circuit);A.id||P("can't update a circuit created in the same plan \u2014 set its fields on the create op"),w(A);let _=E(_q),N={};if(_.name!==void 0){let U=fo(_.name,N$,"name");U||P("name can't be blank"),U!==A.name&&(N.name=U)}return _.description!==void 0&&(N.description=fo(_.description,P$,"description")),_.status!==void 0&&(D$.has(_.status)||P(`bad status "${_.status}" (${[...D$].join(" | ")})`),_.status!==A.status&&(N.status=_.status)),_.type!==void 0&&(op.has(_.type)||P(`bad type "${_.type}" (${[...op].join(" | ")})`),_.type!==(A.type??"build")&&(N.type=_.type)),Object.keys(N).length||P("nothing would change \u2014 the set equals the circuit's current values"),{op:M,circuit:A.id,name:A.name,set:N}}case"circuit.delete":{let A=dy(s,O.circuit);A.id||P("can't delete a circuit created in the same plan"),w(A);let _=o.some((N,U)=>U<$&&Lt(N?.op)==="circuit.update"&&N?.set?.status&&N.set.status!=="active"&&Lt(N?.circuit)===Lt(O.circuit));return A.status==="active"&&!_&&P(`\u201C${A.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:M,circuit:A.id,name:A.name,status:A.status}}case"person.create":{let A=fo(O.label,uy,"label");A||P("a person row needs a label");let _=a.find(U=>String(U.label).toLowerCase()===A.toLowerCase());_&&P(`a roadmap row labelled "${_.label}" already exists (${_.personId})`);let N=g(O.ref,A);return{op:M,...N?{ref:N}:{},label:A}}case"slot.create":{let A=dy(s,O.circuit);w(A);let _=G(O.person),N=R(O);return{op:M,circuit:A.id??A.ref,circuitName:A.name,person:_.key,personLabel:_.label,...N,estUsd:B$(O.estUsd)}}case"slot.update":{let A=V(O.slot,i,"slotId","slot",l.slots),_=E(Iq),N={};if(_.person!==void 0){let z=G(_.person);N.person=z.key,N.personLabel=z.label}if(_.startDate!==void 0||_.endDate!==void 0){let z=R({startDate:_.startDate??A.startDate,endDate:_.endDate??A.endDate});z.startDate!==A.startDate&&(N.startDate=z.startDate),z.endDate!==A.endDate&&(N.endDate=z.endDate)}_.estUsd!==void 0&&(N.estUsd=B$(_.estUsd)),Object.keys(N).length||P("nothing would change");let U=s.find(z=>z.id===A.circuitId);return{op:M,slot:A.slotId,circuitName:U?.name??null,set:N}}case"slot.delete":{let A=V(O.slot,i,"slotId","slot",l.slots),_=s.find(N=>N.id===A.circuitId);return{op:M,slot:A.slotId,circuitName:_?.name??null,startDate:A.startDate,endDate:A.endDate}}case"reservation.create":{let A=G(O.person),_=fo(O.label,uy,"label");return _||P("a reservation needs a label (Leave, Support rotation, \u2026)"),{op:M,person:A.key,personLabel:A.label,label:_,...R(O)}}case"reservation.update":{let A=V(O.reservation,c,"reservationId","reservation",l.reservations),_=E($q),N={};if(_.person!==void 0){let U=G(_.person);N.person=U.key,N.personLabel=U.label}if(_.label!==void 0){let U=fo(_.label,uy,"label");U||P("label can't be blank"),U!==A.label&&(N.label=U)}if(_.startDate!==void 0||_.endDate!==void 0){let U=R({startDate:_.startDate??A.startDate,endDate:_.endDate??A.endDate});U.startDate!==A.startDate&&(N.startDate=U.startDate),U.endDate!==A.endDate&&(N.endDate=U.endDate)}return Object.keys(N).length||P("nothing would change"),{op:M,reservation:A.reservationId,label:A.label,set:N}}case"reservation.delete":{let A=V(O.reservation,c,"reservationId","reservation",l.reservations);return{op:M,reservation:A.reservationId,label:A.label,startDate:A.startDate,endDate:A.endDate}}default:return P("unhandled op")}});b.forEach((y,$)=>{for(let O of[y.circuit,y.person,y.set?.person])if(my(O)&&!d.has(String(O).slice(1)))throw new Error(`op ${$+1} (${y.op}): unknown ref "${O}" \u2014 no earlier op in this plan creates it`)});let x=a.some(y=>y.kind==="user"&&y.userId);return{why:fo(r.why,Aq,"why"),ops:b,base:l,resolved:u,snapped:p,createsMeRow:f&&!x}}async function U$(e,t,n,r={}){let o=Nq(t,n,r),s=Tq(),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 Pq=async(e,t)=>{if(!t)throw new Error("proposalId required");let n=await K({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 H$(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 Pq(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,py+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}}zu();de();Tr();de();Zn();ld();var W$=10,q$=200,Dq=120,jq=24,G$=/^\d{4}-\d{2}-\d{2}$/;function hy(e=process.env){return(e.CHANGELOG_REPOS||"globocodes/bostrat").split(",").map(t=>t.trim()).filter(Boolean)}var Bq=(e=Date.now())=>new Date(e).toISOString().slice(0,10),ht=(e,t="i")=>new RegExp(e,t),Lq=[{re:ht("^(business|docs|chore|ci|refactor|test|security|sec)(\\([^)]*\\))?!?:"),reason:"non-product PR prefix"},{re:ht("\\bSPC\\b",""),reason:"business (SPC)"},{re:ht("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),reason:"business"},{re:ht("competitor|cloudcli|\\bkiro\\b"),reason:"competitor research"},{re:ht("\\bReplicas\\b",""),reason:"competitor research"},{re:ht("tenanc|tenant|perimeter|ip[- ]gate|access[- ]code|vulnerab|\\bCVE\\b|audit|hardening|security|\\bsweep\\b"),reason:"security / tenancy"},{re:ht("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),reason:"internal codename"},{re:ht("^track/(business|security|spc|sec)-"),reason:"non-product branch"}],Fq=[ht("\\bSPC\\b",""),ht("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),ht("competitor|cloudcli|\\bkiro\\b"),ht("\\bReplicas\\b",""),ht("tenanc|\\btenants?\\b|cross-tenant|perimeter|ip[- ]gate|vulnerab|\\bCVE\\b|hardening|security register|audit finding"),ht("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),ht("(^|[^\\w&])#\\d+\\b"),ht("\\btrack/[\\w.-]+")];function Uq({title:e="",headRef:t=""}={}){let n=String(e||""),r=String(t||"");for(let{re:o,reason:s}of Lq)if(o.test(n)||o.test(r))return s;return null}function K$(e){let t=String(e||"");for(let n of Fq){let r=n.exec(t);if(r)return r[0].trim()}return null}function z$(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 Hq=/^\*\*([^*]+?)\*\*\s*[:.]?\s*[—–-]?\s*(.*)$/;function Wq(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=ic(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(`
754
- `)){let s=o.trim();if(!s)continue;if(s.startsWith("#")){n==null&&(n=s.replace(/^#+\s*/,"").trim().slice(0,Dq)||null);continue}let a=/^[-*]\s+(.*)$/.exec(s);if(!a)continue;let i=a[1].trim(),c=null,l=new RegExp(`^\\[([^\\]]{1,${jq}})\\]\\s+(.*)$`).exec(i);if(l&&(c=l[1].trim(),i=l[2].trim()),!i)continue;let u=Hq.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=K$(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>q$)throw new Error(`bullet ${r.length+1} is ${i.length} chars \u2014 over the ${q$}-char cap; a changelog bullet is one line`);r.push({text:i,...c?{area:c}:{}})}if(n){let o=K$(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>W$)throw new Error(`${r.length} bullets \u2014 over the ${W$}-bullet cap; group related changes into one line`);return{title:n||null,bullets:r}}async function qq(e,{repos:t=hy()}={}){let n=new Set(t);return(await Xn()).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:Uq({title:r.title,headRef:r.headRef})}))}async function V$(e,t){let n=await qq(e,t);return{prs:n.filter(r=>!r.excluded),excluded:n.filter(r=>r.excluded)}}async function J$(e,{md:t,day:n=null}){let r=Wq(t),o=n==null||n===""?Bq():String(n);if(!G$.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 Y$(e,{day:t}){let n=String(t||"");if(!G$.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}}Bo();Zn();Fo();de();Bo();pt();or();Zn();Ni();Wu();$u();Fi();An();import{execFile as n5}from"node:child_process";import{promisify as r5}from"node:util";var Kq=new Set(["pull_request","check_suite","workflow_run","push"]),Gq=/^[^/\s]+\/[^/\s]+$/,zq=500,wy=new Set,gy=[],sp=new Map,Yt={hourStart:0,byEvent:{},duplicates:0,rejected:0};function yy(e,t,n){let r=Math.floor(e/36e5)*36e5;r!==Yt.hourStart&&(Yt.hourStart=r,Yt.byEvent={},Yt.duplicates=0,Yt.rejected=0),t==="accepted"?Yt.byEvent[n]=(Yt.byEvent[n]||0)+1:Yt[t]+=1}function Vq(e){if(!e||typeof e!="object"||e.forge!=="github"||typeof e.event!="string"||!Kq.has(e.event)||typeof e.repo!="string"||!Gq.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 X$(e,{now:t=Date.now(),onAccept:n=null,log:r=console}={}){let o=Vq(e);if(!o)return yy(t,"rejected"),{ok:!1,error:"malformed github event envelope"};if(o.deliveryId){if(wy.has(o.deliveryId))return yy(t,"duplicates"),{ok:!0,duplicate:!0,envelope:o};for(wy.add(o.deliveryId),gy.push(o.deliveryId);gy.length>zq;)wy.delete(gy.shift())}let s=o.repo.toLowerCase(),a=sp.get(s)||{lastDeliveryAt:0,count:0};a.lastDeliveryAt=t,a.count+=1,sp.set(s,a),yy(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 Jq(e,t=Date.now()){let n=sp.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 Z$=1440*6e4;function by(e,t=Date.now()){let n=Jq(e,t);return n.covered&&n.ageMs<Z$}function Q$(e=Date.now()){let t={};for(let[n,r]of sp)t[n]={lastDeliveryAt:r.lastDeliveryAt,count:r.count,covered:e-r.lastDeliveryAt<Z$};return{hourStart:Yt.hourStart,byEvent:{...Yt.byEvent},duplicates:Yt.duplicates,rejected:Yt.rejected,repos:t}}de();Zn();kr();or();An();function eR(e){return(e?.checks?.failed??0)>0?"red":e?.mergeable==="CONFLICTING"?"conflict":e?.mergeStateStatus==="BEHIND"?"behind":null}function Yq(e){return!(!e?.checks||e.checks.pending>0||e.mergeabilityPending||e.mergeable==="UNKNOWN"||e.mergeStateStatus==="UNKNOWN")}var Xq=new Set(["merged","closed","lost"]);function Zq(e,t){if(!e?.blocked)return null;let n=eR(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 Qq(e,t){return e.autoMerge?!0:t==="ci-fixed"?!!(e.ciFix||e.ciFixAwait):t==="reconciled"?!!(e.reconcile||e.reconcileAwait):!1}async function e5(e,t,n,r,o){return(await K(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 t5(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 ap(e,t={}){let{now:n=Date.now(),slugOf:r=_e,lookup:o=at,note:s=aS,tracks:a=async()=>(await me()).filter(d=>!Ve(d)),asked:i=e5,emitChange:c=t5}=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(!Yq(f))continue;let w=await o(p,f.number).catch(()=>null);if(!w?.trackId||Xq.has(w.state))continue;let{prev:m}=await s(p,f.number,{blocked:eR(f),sha:f.headSha??null,at:n});if(!m)continue;let g=Zq(m,f);if(!g||Qq(w,g.change))continue;u??=new Map((await a()).map($=>[$.id,$]));let b=u.get(w.trackId);if(!b)continue;let x=f.headSha??null;if(await i(b,g.change,f.number,x,m.at||0))continue;let y={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"?y.passed=f.checks.passed:y.base=f.baseRefName||null,await c(b,g.change,y),l.push({change:g.change,number:f.number,reason:g.reason})}catch{}}return l}var vy=r5(n5),iR=3e4,o5=30*6e4,s5=iR,a5=10*6e4,i5=10080*6e4,c5=60*6e4,l5=8,cR=1440*6e4,u5=3,lR="number,url,title,headRefName,headRefOid,state,mergedAt,closedAt",xy=60*6e4,d5=15*6e4,p5=9e4,f5=1440*6e4,ip=new Map,cp=new Map,m5=/could not resolve|not found|no pull requests?/i,h5=e=>m5.test(String(e?.message||e||""));function w5(e,t){return[e.ciFix?.delegatedAt,e.reconcile?.delegatedAt,e.ciFixAwait?.since,e.reconcileAwait?.since].some(n=>n&&t-n<xy)}var tR={fast:s5,slow:a5,decay:c5};function nR(e,t,n=by){return uR(e,t,{grace:0})||!n(e.repo,t)&&(e.armedAt&&t-e.armedAt<o5||w5(e,t))?"fast":t-(e.firstSeen||0)>i5?"decay":"slow"}function Jc(e,t,n,r){let o=e.lanes?.get(se(t.repo,t.number))||{};return Iu({change:n,repo:t.repo,number:Number(t.number),githubAt:r||null,lane:o.lane||null,intervalMs:o.intervalMs||null,source:"watch"})}async function g5(e,t){er("watch");try{let{stdout:n}=await vy("gh",["pr","view",String(t),"--repo",e,"--json",lR],{timeout:3e4,maxBuffer:4194304,env:{...process.env,...await yn({slug:e})}});return JSON.parse(n||"null")}catch(n){throw qr(n)&&Kr(n),n}}async function y5(e){er("watch");try{let{stdout:t}=await vy("gh",["pr","list","--repo",e,"--state","all","--limit","100","--json",lR],{timeout:3e4,maxBuffer:8388608,env:{...process.env,...await yn({slug:e})}}),n=new Map;for(let r of JSON.parse(t||"[]"))n.set(Number(r.number),r);return n}catch(t){throw qr(t)&&Kr(t),t}}async function b5(){let e=new Map;for(let t of await me().catch(()=>[]))e.set(t.id,t);return e}async function k5(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 Hu(e,t).catch(()=>{})}async function x5(e,t){let n=await jo(e);return n?Xs(n,t):null}async function v5(e,t,n){let r=await jo(e);if(!r)throw new Error(`no local checkout for ${e}`);return Zs(r,t,{method:n})}async function S5(e,t){let n=await jo(e);if(!n)throw new Error(`no local checkout for ${e}`);return ji(n,t)}async function T5(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 Ia(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 A5=10*6e4;async function E5(e,t,n){let r=e.autoMerge?.armedAt||0;if(r&&(n.now??Date.now())-r>cR){await Ia(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 Ia(e,o,t,n,`check${o.checks.failed===1?"":"s"} failed: ${a}`);return}if(o.mergeable==="CONFLICTING"){await Ia(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<A5)return;await Ia(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 Ia(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 Ia(e,o,t,n,String(a?.message||a).trim()||"merge failed");return}await dR(e,{...o,state:"MERGED"},t,n,{change:"auto-merged",githubAt:o.checks.settledAt||null})}}async function $a(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 _5(e,t){try{return await vy("git",["-C",e.cwd,"cat-file","-e",`${t}^{commit}`],{timeout:1e4}),!0}catch{return!1}}async function Vc(e,t,n,r=()=>!0){return(await K(e).catch(()=>[])).some(s=>s.type==="pr.state.changed"&&s.payload?.change===t&&s.payload?.number===Number(n)&&r(s))}var Ra=(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 uR(e,t,{grace:n=p5}={}){if(e.announced!==!1)return!1;let r=t-(e.firstSeen||0);return r>=n&&r<=f5}async function I5(e,t,n,r){let o=r.now??Date.now();if(!uR(e,o))return!1;let s=n.get(e.trackId)||null;if(!s||Ve(s))return!1;let a=(s.boxes||[]).find(d=>d.name===s.leadBox);return await(r.midTurn??Lo)(s.leadBox,a?.agent).catch(()=>!1)?!1:(await K(s).catch(()=>[])).some(d=>d.type==="pr.state.changed"&&d.payload?.number===Number(e.number))?(await(r.claim??Yn)(e.repo,e.number).catch(()=>null),!1):await(r.claim??Yn)(e.repo,e.number).catch(()=>null)?(await $a(s,"opened",{...Ra(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 $5(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 ku(e.repo,e.number,{headSha:s}).catch(()=>{}),e.reconcile?.headSha&&s!==e.reconcile.headSha&&await vu(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<d5;await sS(e.repo,e.number,s).catch(()=>{}),e.baseFoldAt&&await oS(e.repo,e.number).catch(()=>{}),!i&&!c&&!l&&a&&!await r.localHasCommit(a,s).catch(()=>!1)&&!await Vc(a,"pushed",e.number,d=>d.payload?.sha===s)&&await $a(a,"pushed",{...Ra(e,t),sha:s}).catch(()=>{})}if(e.ciFixAwait)if(o-(e.ciFixAwait.since||0)>xy)await xu(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 xu(e.repo,e.number).catch(()=>{});else if(i.checks.total>0&&i.checks.pending===0){let c=Jc(r,e,"ci-fixed",i.checks.settledAt||null),l=e.ciFixAwait.since||0;a&&!await Vc(a,"ci-fixed",e.number,u=>(u.payload?.ts||0)>=l)&&await $a(a,"ci-fixed",{...Ra(e,t),sha:s,delegated:!0,passed:i.checks.passed,githubAt:c.githubAt,latencyMs:c.latencyMs,lane:c.lane}).catch(()=>{}),await xu(e.repo,e.number).catch(()=>{})}}}if(e.reconcileAwait)if(o-(e.reconcileAwait.since||0)>xy)await Su(e.repo,e.number).catch(()=>{});else{let i=await r.detail(e.repo,e.number).catch(()=>null);if(i){if(i.mergeable==="CONFLICTING")await Su(e.repo,e.number).catch(()=>{});else if(i.mergeable==="MERGEABLE"){Jc(r,e,"reconciled",null);let c=e.reconcileAwait.since||0;a&&!await Vc(a,"reconciled",e.number,l=>(l.payload?.ts||0)>=c)&&await $a(a,"reconciled",{...Ra(e,t),sha:s,delegated:!0,base:i.baseRefName||null}).catch(()=>{}),await Su(e.repo,e.number).catch(()=>{})}}}}async function R5(e,t,n,r){let o=Jc(r,e,"closed",Date.parse(t?.closedAt||"")||null),s=n.get(e.trackId);s&&!await Vc(s,"closed",e.number)&&await $a(s,"closed",{...Ra(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 O5(e,t,n){Jc(n,e,"lost",null);let r=t.get(e.trackId);r&&!await Vc(r,"lost",e.number)&&await $a(r,"lost",Ra(e,null)).catch(()=>{}),await n.notifyIfResolved(e.repo,e.number,"lost").catch(()=>{}),await n.mark(e.repo,e.number,"lost").catch(()=>{})}async function dR(e,t,n,r,o={}){let s=Jc(r,e,o.change||"merged",o.githubAt??(Date.parse(t.mergedAt||"")||null)),a=n.get(e.trackId);a&&((await K(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 rR(e={}){let{now:t=Date.now(),auth:n=Fm,view:r=g5,list:o=y5,links:s=lS,trackMap:a=b5,emitMerged:i=k5,mark:c=Hr,archiveIfArmed:l=nr,notifyIfArmed:u=rr,notifyIfResolved:d=Sd,followupsIfMerged:p=Xo,batchThreshold:f=u5,detail:w=x5,merge:m=v5,updateBranch:g=S5,lookup:b=at,disarm:x=Mi,emitDisarmed:y=T5,localHasCommit:$=_5,claim:O=Yn,midTurn:M=Lo,only:H=null,wantDetail:P=null,covered:E=by,verdicts:R=null}=e;if(!(await n().catch(()=>null))?.authenticated||Eu()>0)return 0;let V=await s().catch(()=>[]),A=MS(V),_=J=>{try{return!!P?.(J)}catch{return!1}},N=H?V.filter(J=>{try{return H(J)}catch{return!1}}):V.filter(J=>t-(ip.get(se(J.repo,J.number))||0)>=tR[nR(J,t,E)]);if(!N.length)return 0;let U=Date.now(),z=new Map,ue=new Map;for(let J of[...N].sort(Bi)){let ge=H?"event":nR(J,t,E);z.set(se(J.repo,J.number),{lane:ge,intervalMs:tR[ge]??null}),ip.set(se(J.repo,J.number),t),ue.has(J.repo)||ue.set(J.repo,[]),ue.get(J.repo).push(J)}let pe=await a().catch(()=>new Map),Se=new Map,Ae=(J,ge)=>{let Oe=se(J,ge);if(!Se.has(Oe)){let Me=Promise.resolve().then(()=>w(J,ge));Me.catch(()=>{}),Se.set(Oe,Me)}return Se.get(Oe)},W=R??((J,ge)=>ap([{path:J,prs:[ge]}],{now:t,slugOf:async()=>J,tracks:async()=>[...pe.values()].filter(Oe=>!Ve(Oe))}).catch(()=>{})),te={now:t,lanes:z,emitMerged:i,mark:c,archiveIfArmed:l,notifyIfArmed:u,notifyIfResolved:d,followupsIfMerged:p,detail:Ae,merge:m,updateBranch:g,lookup:b,disarm:x,emitDisarmed:y,localHasCommit:$,claim:O,midTurn:M};for(let[J,ge]of ue){let Oe,Me=new Set,I=j=>j.ciFixAwait||j.reconcileAwait||_(j)?!0:!j.autoMerge||j.trackId&&A.get(j.trackId)!==se(j.repo,j.number)?!1:t-(j.autoMerge.armedAt||0)<=cR;if(ge.length>f)Oe=await o(J).catch(()=>null);else{Oe=new Map;for(let j of ge){if(I(j)){let fe=await Ae(J,j.number).catch(()=>null);if(fe?.state){Oe.set(Number(j.number),{number:Number(j.number),url:fe.url,title:fe.title,headRefName:fe.headRefName,headRefOid:fe.headSha??null,state:fe.state,mergedAt:fe.mergedAt??null,closedAt:fe.closedAt??null});continue}}try{let fe=await r(J,j.number);fe?.number!=null&&Oe.set(Number(fe.number),fe)}catch(fe){h5(fe)&&Me.add(se(j.repo,j.number))}}}if(Oe)for(let j of ge){let fe=se(j.repo,j.number),Pe=Oe.get(Number(j.number));if(!Pe){if(Me.has(fe)){let Ce=(cp.get(fe)||0)+1;cp.set(fe,Ce),Ce>=l5&&(await O5(j,pe,te),cp.delete(fe),ip.delete(fe))}continue}if(cp.delete(fe),Pe.state==="MERGED"||Pe.state==="CLOSED")Pe.state==="MERGED"?await dR(j,Pe,pe,te):await R5(j,Pe,pe,te),ip.delete(fe);else{await I5(j,Pe,pe,te).catch(()=>{}),await $5(j,Pe,pe,te).catch(()=>{});let Ce=!j.trackId||A.get(j.trackId)===fe;j.autoMerge&&Ce&&await E5(j,pe,te).catch(()=>{});try{if(_(j)&&!Se.has(fe)&&Ae(j.repo,j.number),Se.has(fe)){let wn=await Se.get(fe).catch(()=>null);wn?.checks&&await W(j.repo,wn)}}catch{}}}}let ie={};for(let{lane:J}of z.values())ie[J]=(ie[J]||0)+1;return console.log(`[pr-watch] probed ${N.length} link(s) (${Object.entries(ie).map(([J,ge])=>`${J} ${ge}`).join(", ")}) in ${Date.now()-U}ms`),N.length}function oR(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 ky=!1,lp=!1,up=[],sR=Promise.resolve();async function C5(){for(;lp||up.length;){if(lp){lp=!1;try{await rR()}catch{}continue}let e=up;up=[];let t=e.map(r=>r.spec),n=Object.assign({},...e.map(r=>r.deps||{}));try{await rR({...n,only:r=>t.some(o=>oR(o,r)),wantDetail:r=>t.some(o=>o.detail&&oR(o,r))})}catch{}}}function dp(e,t){return e===null?lp=!0:up.push({spec:e,deps:t}),ky||(ky=!0,sR=C5().finally(()=>{ky=!1})),sR}function pR(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 dp({repo:n,numbers:r,branch:e.branch||null,event:e.event||null,detail:e.detail===!0},t)}var M5=6e4,aR=0;function fR(e=void 0){let t=e?.now??Date.now();return t-aR<M5?Promise.resolve():(aR=t,dp({all:!0},e))}function mR(){dp(null),setInterval(()=>dp(null),iR)}Bo();sh();rd();or();An();var N5=new Set(["opened","reopened","closed","synchronize","ready_for_review","converted_to_draft","edited"]);async function P5({tracks:e=me,reconcile:t=nd}={}){for(let n of(await e().catch(()=>[])).filter(r=>!Ve(r)))await t(n,{bypassThrottle:!0}).catch(()=>{})}function hR(e,t={}){let{invalidate:n=Kt,probe:r=pR,poke:o=mT,reconcileOpened:s=P5}=t;try{n()}catch{}let a={probe:null,poked:!1,reconciled:!1};if(!e?.repo)return a;if(e.event==="pull_request"&&N5.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}ct();de();or();An();import{randomUUID as D5}from"node:crypto";var j5=2e4,wR=3,Oa=new Map,Sy=new Set;async function gR(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 B5(e={}){let{sessions:t=null,tracks:n=null,append:r=C,read:o=K,now:s=Date.now()}=e;if(process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1")return;let a,i;try{a=t??await Qt(),i=n??await me()}catch{return}let c=new Map(a.map(u=>[u.name,u])),l=new Set;for(let u of i){if(Ve(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=(Oa.get(d.name)||0)+1;Oa.set(d.name,f),f===wR&&(Sy.add(d.name),await gR(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:D5(),box:d.name,agent:d.agent}}).catch(()=>{}))}else{let f=(Oa.get(d.name)||0)>=wR;if(Oa.delete(d.name),f||!Sy.has(d.name)){Sy.add(d.name);let w=await gR(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[...Oa.keys()])l.has(u)||Oa.delete(u)}var Yc=null,Ty=!1;function yR(){return Yc?()=>{}:(Yc=setInterval(()=>{Ty||(Ty=!0,B5().catch(()=>{}).finally(()=>{Ty=!1}))},j5),Yc.unref?.(),()=>{clearInterval(Yc),Yc=null})}Mo();rd();de();Bo();Fo();Mo();Ki();import{randomUUID as L5}from"node:crypto";async function F5(){let e=await Promise.resolve().then(()=>(or(),w_));return{sayToLead:e.sayToLead,queueShipCompleteNotify:e.queueShipCompleteNotify}}var Ay={listRepoPrs:En,readEvents:K,appendEvent:C,sayDeps:F5,currentBranch:Gr};async function U5(e,t=Ay,{branch:n=null}={}){if(!e?.cwd)return null;let r=n||await(t.currentBranch??Gr)(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 Ey(e,t,{actions:n,notify:r=!1}={},o=Ay){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 U5(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=L5();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 _y(e,{offerId:t,choice:n}={},r=Ay){if(!t)throw new Error("offerId required");if(!["push","new","dismiss"].includes(n))throw new Error('choice "push" | "new" | "dismiss" required');return Jr(`prx:${e.id}:${t}`,()=>H5(e,{offerId:t,choice:n},r))}async function H5(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=Fr.filter(d=>d!=="pr"&&(i.includes(d)||d==="push")),c=await u(e.id,zs(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,zv(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}}Ki();import wr from"node:fs/promises";import Ca from"node:path";import AR from"node:os";import bR from"node:fs/promises";import pp from"node:path";import{execFile as W5}from"node:child_process";import{promisify as q5}from"node:util";import{fileURLToPath as K5}from"node:url";var G5=q5(W5),xR=pp.dirname(K5(import.meta.url)),z5=pp.resolve(xR,"..","..","client","dist"),V5="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",J5=new Map([...V5].map((e,t)=>[e,t]));function Y5(e){let t=[],n=0,r=0;for(let o of e){let s=J5.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 X5(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=Y5(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 Z5(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 kR=new Map;async function Q5(e){let t;try{t=await bR.stat(e)}catch{return null}let n=kR.get(e);if(n&&n.mtimeMs===t.mtimeMs)return n;try{let r=JSON.parse(await bR.readFile(e,"utf8")),o={mtimeMs:t.mtimeMs,sources:r.sources||[],lines:X5(r.mappings||"")};return kR.set(e,o),o}catch{return null}}var Iy=null;function eK(){return Iy||(Iy=process.env.BOSTRAT_RELEASE?Promise.resolve(process.env.BOSTRAT_RELEASE):G5("git",["rev-parse","--short","HEAD"],{cwd:pp.resolve(xR,"..","..")}).then(e=>e.stdout.trim()).catch(()=>null)),Iy}var tK=/(?:https?:\/\/[^\s()]*)?\/assets\/([^\s()/]+\.js):(\d+):(\d+)/g;async function nK(e,{distDir:t=z5}={}){let n=[],r=0,o=!1;for(let s of e.matchAll(tK)){let[a,i,c,l]=s,u=await Q5(pp.join(t,"assets",`${i}.map`)),d=u?Z5(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 vR(e,t={}){try{if(!e?.error?.stack||!e.release||e.release==="unknown")return e;let n=t.release??await eK();if(!n||e.release!==n)return e;let{stack:r,symbolicated:o}=await nK(e.error.stack,t);o&&(e.error.stack=r,e.error.symbolicated=!0)}catch{}return e}var rK=()=>process.env.BOSTRAT_STATE_DIR||Ca.join(process.env.HOME||AR.tmpdir(),".bostrat"),mo=()=>Ca.join(rK(),"telemetry"),ER=()=>Ca.join(mo(),".relay-offsets.json"),oK=50,sK=14,aK=3e4,SR=500,Ft=(e,t)=>typeof e=="string"?e.slice(0,t):"";function iK(e,t){if(!e||typeof e!="object")return null;let n=Ft(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:Ft(e.anonId,64),sessionId:Ft(e.sessionId,64),userId:Ft(e.userId,64),release:Ft(e.release,64),appVersion:Ft(e.appVersion,32),route:Ft(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:Ft(e.error.kind,256),message:Ft(e.error.message,8192),stack:Ft(e.error.stack,32768),fingerprint:Ft(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:Ft(s?.n,64),r:Ft(s?.r,128)}))),o}var _R=e=>new Date(e).toISOString().slice(0,10),TR=0;async function IR(e,t=Date.now()){let r=(Array.isArray(e?.events)?e.events.slice(0,oK):[]).map(s=>iK(s,t)).filter(Boolean);if(!r.length)return 0;for(let s of r)s.error?.stack&&await vR(s);await wr.mkdir(mo(),{recursive:!0});let o=Ca.join(mo(),`${_R(t)}.ndjson`);return await wr.appendFile(o,r.map(s=>JSON.stringify(s)+`
755
- `).join(""),"utf8"),t-TR>6*3600*1e3&&(TR=t,cK(t).catch(()=>{})),r.length}async function cK(e=Date.now()){let t=_R(e-sK*24*3600*1e3),n=[];try{n=await wr.readdir(mo())}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 wr.rm(Ca.join(mo(),s),{force:!0});let o=await RR();for(let s of r)delete o[s];await OR(o)}var fp=new Map;function $R(e,t=Date.now()){let n=e||"unknown",r=fp.get(n);return r||(fp.size>512&&fp.clear(),r={tokens:40,at:t},fp.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 RR(){try{return JSON.parse(await wr.readFile(ER(),"utf8"))||{}}catch{return{}}}async function OR(e){await wr.mkdir(mo(),{recursive:!0}),await wr.writeFile(ER(),JSON.stringify(e),"utf8")}function lK(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||AR.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 uK({fetchImpl:e=fetch}={}){let t=await Z_();if(!t)return{sent:0,disabled:!0};let n;try{n=(await wr.readdir(mo())).filter(s=>s.endsWith(".ndjson")).sort()}catch{return{sent:0,disabled:!1}}let r=await RR(),o=0;for(let s of n){let a=Ca.join(mo(),s),i=r[s]||0,c;try{let p=await wr.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(`
756
- `).filter(Boolean),d=[];for(let p of u)try{d.push(JSON.parse(p))}catch{}for(let p=0;p<d.length;p+=SR){let f=d.slice(p,p+SR).map(m=>lK(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 OR(r)}return{sent:o,disabled:!1}}var $y=null,Ry=!1;function CR(){$y||($y=setInterval(async()=>{if(!Ry){Ry=!0;try{await uK()}catch(e){console.error("[telemetry] relay failed:",e?.message||e)}finally{Ry=!1}}},aK),$y.unref?.())}import hp from"node:fs/promises";import jR from"node:path";import dK from"node:os";var BR=()=>process.env.BOSTRAT_STATE_DIR||jR.join(process.env.HOME||dK.tmpdir(),".bostrat"),LR=()=>jR.join(BR(),"dictation-glossary.json"),pK=100,fK=500,mK=["bostrat","globopi","codex","tmux","worktree","Deepgram","Linear","Firecracker","Tigris","WireGuard","misous","postyx","cedar","gerbil","Anthropic","Opus","Haiku","Sonnet","keyterm","monorepo","dogfood"],wp=null,Oy=null,Cy=Promise.resolve();function MR(){let e={},t=Date.now();for(let n of mK)e[n.toLowerCase()]={term:n,count:1,lastUsed:t,source:"seed"};return e}async function FR(){return wp||(Oy??=hp.readFile(LR(),"utf8").then(e=>JSON.parse(e)?.terms??MR()).catch(()=>MR()).then(e=>wp=e).finally(()=>Oy=null),Oy)}async function NR(){let e=JSON.stringify({terms:wp},null,2),t=LR(),n=`${t}.${process.pid}.tmp`;await hp.mkdir(BR(),{recursive:!0}),await hp.writeFile(n,e),await hp.rename(n,t)}function hK(){return Cy=Cy.then(NR,NR),Cy.catch(()=>{})}async function My(){return Object.values(await FR()).sort((t,n)=>n.count-t.count||n.lastUsed-t.lastUsed)}var wK=e=>Math.max(1,Math.ceil(e.length/4));async function gK(){let e=[],t=0;for(let{term:n}of await My()){let r=wK(n);if(!(t+r>fK)&&(e.push(n),t+=r,e.length>=pK))break}return e}async function yK(e,t){let n=await FR(),r=e.toLowerCase(),o=n[r];n[r]={term:e,count:(o?.count??0)+1,lastUsed:Date.now(),source:o?.source??t}}var PR=e=>(e||"").split(/\s+/).map(t=>t.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"")).filter(Boolean),mp=e=>e.toLowerCase();function DR(e){return!new RegExp("\\p{L}","u").test(e)||e.length<3?!1:/^[a-z]+$/.test(e)?e.length>=4:!0}async function UR(e,t){let n=PR(e),r=PR(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]=mp(n[u])===mp(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;)mp(n[c])===mp(r[l])?(c++,l++):a[c+1][l]>=a[c][l+1]?c++:(DR(r[l])&&i.add(r[l]),l++);for(;l<s;l++)DR(r[l])&&i.add(r[l]);if(!i.size)return[];for(let u of i)await yK(u,"learned");return await hK(),[...i]}var Xc=null;function bK(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 HR(){if(!Xc)return null;let e=await Cc();if(!e||e.apiKey.slice(-6)!==Xc.keyTail)return null;let{keyTail:t,...n}=Xc;return n}async function WR(e,t){let n=await Cc();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 gK())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=bK(o.status,i);c.persistent&&(Xc={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 Xc=null,{transcript:(await o.json())?.results?.channels?.[0]?.alternatives?.[0]?.transcript??""}}de();var Ny={"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 kK(e){if(!e)return null;let t=String(e).trim();if(Ny[t])return t;let n=null;for(let r of Object.keys(Ny))t.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function xK(e,t={}){let n=Ny[kK(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 vK(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 Zc=null;async function SK(){if(!Zc)return null;let e=await Ud();if(!e||e.apiKey.slice(-6)!==Zc.keyTail)return null;let{keyTail:t,...n}=Zc;return n}async function TK(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=vK(t.status,o);s.persistent&&(Zc={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}Zc=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 AK={openai:TK};async function qR(){let e=await Ud();return e?{configured:!0,provider:e.provider,model:e.model,voice:e.voice,problem:await SK()}:{configured:!1}}async function KR(){let e=await Ud();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 AK[e.provider](e);return{provider:e.provider,model:e.model,voice:e.voice,...t}}async function GR(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=xK(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}}An();var eO=Te.dirname(_K(import.meta.url)),zR=Number(process.env.PORT)||3362,yp=gg(process.env),tO=Number(process.env.BOSTRAT_AUTO_TRIGGER_PCT)||80,Ma=i$(process.env.BOSTRAT_ALLOW_IPS),Ly=c$(process.env.BOSTRAT_VIEW_FRONT_CIDRS,rp),Fy=u$(),nO=process.env.BOSTRAT_ALLOW_LAN_TOKENLESS!=="1",S=Ut();S.disable("x-powered-by");S.use((e,t,n)=>{t.setHeader("x-content-type-options","nosniff"),np(e.headers.host)||(t.setHeader("x-frame-options","DENY"),t.setHeader("referrer-policy","strict-origin-when-cross-origin")),n()});S.use((e,t,n)=>{if(Gc(e)||Ma.allowed(Ma.clientIp(e))||Ly.allows(e))return n();t.status(403).type("text/plain").send("bostrat: access restricted to the allowlist")});S.use(w$);S.use(f$({token:Fy,enforce:nO}));S.use("/api/mocks",Ut.json({limit:"1mb"}));S.use("/api/mocks",Ut.raw({type:"image/png",limit:"24mb"}));S.use("/api/mocks",Ut.raw({type:["video/mp4","video/webm"],limit:"105mb"}));S.use("/api/runbooks",Ut.json({limit:"1mb"}));S.use("/api/tracks/adopt",Ut.json({limit:"1mb"}));S.use("/api/telemetry",Ut.json({limit:"256kb"}));S.use("/api/hook",Ut.json({limit:"2mb"}));S.use("/api/dictation",Ut.raw({type:["audio/*","video/mp4","application/octet-stream"],limit:"32mb"}));S.use("/api/tracks/:id/upload",Ut.raw({type:()=>!0,limit:"25mb"}));S.use(Ut.json({limit:"64kb"}));S.get("/api/health",async(e,t)=>{t.json({ok:!0,tmuxSocket:Rt,hostTmuxAlive:await Er(),autoTriggerPct:tO,plane:Na?Na.status():null})});S.get("/api/sessions",async(e,t)=>{t.json({sessions:await Qt()})});S.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 _r(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})}});S.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 ke(n))return t.status(404).json({error:"session not found"});try{await en(n),t.json({ok:!0})}catch(r){t.status(500).json({error:`failed to kill: ${r?.message||r}`})}});S.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 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})});S.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 ax(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)})}});S.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 VR=10;async function rO(){let e=await me(),t=await S_(e);return{tracks:e,views:await Lh(),queuedOf:n=>Vo(n),jobsOf:n=>t.get(n)??[]}}S.get("/api/idle-guard",async(e,t)=>{try{t.json(fg(await rO()))}catch{t.status(500).json({busy:!0,reasons:["error"]})}});var Xt=Qo(),MK=B_({kind:Xt}),Qc=null,vt=()=>Qc&&["auto","prompt","off"].includes(Qc)?Qc:MK,By=null,NK=Rc.has(Xt),oO=async({to:e,from:t})=>!NK||Nd(await Oc())?!1:(tl.arm({to:e,from:t,kind:Xt}),!0);async function PK(e){let t=vt();Qc=e??null;let n=vt();if(t!==n){if(console.log(`[self-update] policy ${t} \u2192 ${n} (${e?"plane row":"node default"})`),n!=="auto"){tl.cancel();return}By&&await oO(By)}}var sO=(()=>{try{return CK(import.meta.url)("../package.json").version||null}catch{return null}})(),tl=F_({isBusy:async()=>fg(await rO()).busy,onStuck:({to:e,from:t})=>Bn({current:t,latest:e,installKind:Xt,policy:vt(),status:"stuck"}).catch(()=>{}),onStarted:({to:e,from:t,result:n})=>(n?.ok?Bn({current:t,latest:e,installKind:Xt,policy:vt(),status:"updating",reason:"auto"}):Bn({current:t,latest:e,installKind:Xt,policy:vt(),status:"failed",error:n?.reason})).catch(()=>{})});S.get("/api/node/self-update",async(e,t)=>{t.json({installKind:Xt,policy:vt(),policySource:Qc?"plane":"node",current:sO,status:await Oc(),armed:tl.armed})});S.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 Pd({to:n,kind:Xt,reason:"manual"});if(r.ok)return tl.cancel(),Bn({current:r.from,latest:n,installKind:Xt,policy:vt(),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 aO(){try{let e=await L_();e&&await Bn({current:e.from,latest:e.to,installKind:e.kind||Xt,policy:vt(),status:e.status,error:e.error,reason:e.reason}),await Ow({current:sO,installKind:Xt,policy:vt()})}catch{}}aO();setInterval(aO,3e4).unref();S.get("/api/tracks",async(e,t)=>{let n=(await me()).filter(s=>!s.transferredTo),r=n.filter(s=>s.archivedAt&&!s.archiving),o=n;if(e.query.archived!=="all"&&r.length>VR){let s=new Set([...r].sort((a,i)=>(i.archivedAt||0)-(a.archivedAt||0)).slice(0,VR).map(a=>a.id));o=n.filter(a=>!a.archivedAt||a.archiving||s.has(a.id))}t.json({tracks:o,archivedTotal:r.length,agents:bc,agentAvailability:await gd(),tickets:await pI()})});S.get("/api/cost",async(e,t)=>{try{let n=await me();e.query.track&&(n=n.filter(o=>o.id===e.query.track));let r=await Zg(n);if(r.cursorUsage=Sh(),e.query.format==="text")return t.type("text/plain").send(jI(r));t.json(r)}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/usage/roundup",async(e,t)=>{try{let n=await ey(await me(),{window:e.query.window,from:e.query.from,to:e.query.to});if(e.query.format==="text")return t.type("text/plain").send(HI(n));t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/usage/spend",async(e,t)=>{try{let n=await zI(await me(),{window:e.query.window,from:e.query.from,to:e.query.to});n.cursorUsage=Sh(),n.subscriptionMonthlyUsd=Number(process.env.BOSTRAT_SUBSCRIPTION_MONTHLY_USD)||null,n.caps=Ri(),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/usage/caps",(e,t)=>{t.json(Ri())});S.post("/api/usage/caps",async(e,t)=>{try{t.json(await mu(e.body?.caps??{},{source:"local"}))}catch(n){t.status(400).json({error:n?.message||String(n)})}});S.get("/api/usage/limits",async(e,t)=>{try{let n=e.query.fresh==="1"||e.query.fresh==="true";t.json(await n$(await me(),{fresh:n}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.post("/api/hook",async(e,t)=>{try{let{mode:n,target:r}=await eb(e.get(Hn),{byToken:xc,legacy:()=>Vi(e.body?.session_id,e.body?.cwd)});if(n==="refused")return Fa("refused",{reason:"unknown-token",hook:e.body?.hook_event_name}),t.json({ok:!1,error:"unknown hook token"});if(n==="legacy-denied")return Fa("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&&Fa("mismatch",{track:r.track.id,box:r.box.name}),Fa(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 NI(e.body||{},()=>r);e.body?.hook_event_name==="Stop"&&r?.box?.cwd&&kl(r.box.cwd),t.json({ok:!0,events:o.length})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});S.get("/api/git/trailers",async(e,t)=>{t.type("text/plain");try{let n=await xc(e.get(Hn));if(!n?.track||!n?.box)return t.status(204).end();t.send((await QS(n.track,n.box)).join(`
753
+ `),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 b$(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}.${gq(n.host)}/`}function gq(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 rp(t)&&Uh(n[0])?n.slice(1).join("."):t}ca();Qh();ud();ph();de();import k$ from"node:os";import{randomUUID as uy}from"node:crypto";var yq=(e=process.env)=>({nodeId:e.BOSTRAT_NODE_ID||k$.hostname(),nodeName:e.BOSTRAT_NODE_NAME||k$.hostname()});var x$=32768,v$=120,S$=1e3,T$=new Set(["claude","codex","cursor"]),bq=new Set(["off","transition","nag"]),kq=[[0,59],[0,23],[1,31],[1,12],[0,6]];function xq(e){let t=String(e??"").trim().split(/\s+/);return t.length!==5?!1:t.every((n,r)=>{let[o,s]=kq[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 mn=e=>String(e??"").trim(),cs={name(e){let t=mn(e);if(!t)throw new Error("a loop needs a name");if(t.length>v$)throw new Error(`name is too long (${t.length}); cap is ${v$}`);return t},schedule(e){let t=mn(e);if(!t)throw new Error('a loop needs a schedule (5-field UTC crontab, e.g. "0 7 * * *")');if(!xq(t))throw new Error(`invalid cron schedule: "${t}" \u2014 5 UTC fields, e.g. "0 7 * * *"`);return t},prompt(e){let t=mn(e);if(!t)throw new Error("a loop needs a prompt \u2014 it is what the run does");if(t.length>x$)throw new Error(`prompt is too long (${t.length} chars); cap is ${x$}`);return t},expectation(e){let t=mn(e)||null;if(t&&t.length>S$)throw new Error(`expectation is too long (${t.length}); cap is ${S$}`);return t},notify(e){let t=mn(e)||"off";if(!bq.has(t))throw new Error(`notify must be one of off | transition | nag, got "${e}"`);return t},assignment(e){let t=e??null,n=mn(typeof t=="string"?t:t?.provider)||"claude";if(!T$.has(n))throw new Error(`unknown provider "${n}" \u2014 one of ${[...T$].join(", ")}`);let r=typeof t=="object"&&t&&mn(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 vq(e,t){let n=e&&typeof e=="object"?e:{},r=cs.name(n.name),o=cs.schedule(n.schedule),s=cs.prompt(n.prompt),a=cs.expectation(n.expectation),i=cs.notify(n.notify),c=cs.assignment(n.assignment),l=mn(t?.workspace?.repo)||mn(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}=yq();return{name:r,schedule:o,prompt:s,expectation:a,notify:i,assignment:c,repo:l,nodeId:u||null,nodeName:d||null}}async function E$(e,t){let n=vq(t,e),r=uy();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 _$(e,t,n,{loopId:r=null,nextFireAt:o=null}={}){if(!t)throw new Error("proposalId required");let s=await K({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 ly=["name","schedule","prompt","expectation","notify","assignment","enabled"],Sq=(e,t)=>(e?.provider??"claude")===(t?.provider??"claude")&&(e?.model??null)===(t?.model??null);function I$(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 $$(e,t){let n=mn(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 Tq(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=>!ly.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: ${ly.join(", ")}`)}let o={};for(let a of ly){if(!(a in n))continue;let i=cs[a](n[a]);(a==="assignment"?Sq(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 R$(e,t,n){let r=I$(t),{patch:o,changed:s}=Tq(n,r),a=uy(),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 A$=600;async function O$(e,t,n){let r=mn(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>A$)throw new Error(`reason is too long (${r.length}); cap is ${A$}`);let o=I$(t),s=uy(),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 C$=async(e,t,n)=>{if(!n)throw new Error("proposalId required");let r=await K({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 M$(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 C$(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 N$(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 C$(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}}de();import{randomUUID as Aq}from"node:crypto";var fy=20,Eq=300,dy=120,P$=120,D$=2e3,sp=new Set(["build","ops","debt","spike"]),B$=new Set(["active","done","abandoned"]),my=new Set(["circuit.create","circuit.update","circuit.delete"]),_q=new Set(["person.create","slot.create","slot.update","slot.delete","reservation.create","reservation.update","reservation.delete"]),zc=new Set([...my,..._q]),Iq=["name","description","status","type"],$q=["person","startDate","endDate","estUsd"],Rq=["person","label","startDate","endDate"],Oq=/^\d{4}-\d{2}-\d{2}$/,Lt=e=>String(e??"").trim(),hy=e=>typeof e=="string"&&e.startsWith("@"),F$=864e5;function U$(e){let t=Date.parse(`${e}T00:00:00Z`),n=new Date(t).getUTCDay();return new Date(t-(n+6)%7*F$).toISOString().slice(0,10)}function Cq(e){return new Date(Date.parse(`${U$(e)}T00:00:00Z`)+6*F$).toISOString().slice(0,10)}var j$=(e,t)=>{let n=Lt(e);if(!Oq.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 Mq(e,t){let n=j$(e,"startDate"),r=j$(t,"endDate");if(r<n)throw new Error(`endDate ${r} is before startDate ${n}`);let o=U$(n),s=Cq(r);return{startDate:o,endDate:s,snapped:o!==n||s!==r}}var L$=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},fo=(e,t,n)=>{let r=Lt(e);if(r.length>t)throw new Error(`${n} is too long (${r.length}); cap is ${t}`);return r};function py(e,t){let n=Lt(t);if(!n)throw new Error("a circuit name or id is required");if(hy(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 Nq(e,t){let n=Lt(t);if(!n)throw new Error('a person is required \u2014 "me", a person id, or a row label');if(n==="me"||hy(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 Pq(e,t,{allow:n=zc}={}){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>fy)throw new Error(`too many ops (${o.length}); cap is ${fy} \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=y=>{y.id&&(l.circuits[y.id]={name:y.name,status:y.status,type:y.type??"build",updatedAt:y.updatedAt??null},u[y.id]=y.name)},m=y=>{y.id&&(u[y.id]=y.label)},g=(y,$)=>{let O=Lt(y);if(!O)return null;if(d.has(O))throw new Error(`ref "${O}" is used by two ops \u2014 each ref names one thing`);return d.add(O),u[`@${O}`]=$,O},b=o.map((y,$)=>{let O=y&&typeof y=="object"?y:{},M=Lt(O.op),H=`op ${$+1}`;if(!zc.has(M))throw new Error(`${H}: unknown op "${M}" \u2014 one of ${[...zc].join(", ")}`);if(!n.has(M))throw new Error(`${H}: "${M}" isn't a circuit op \u2014 roadmap changes go through \`bostrat-roadmap propose\` (one card, either CLI)`);let P=A=>{throw new Error(`${H} (${M}): ${A}`)},E=A=>{let _=O.set&&typeof O.set=="object"&&!Array.isArray(O.set)?O.set:null;_||P("needs a `set` object naming the fields to change");let N=Object.keys(_).filter(U=>!A.includes(U));return N.length&&P(`unknown field(s) ${N.join(", ")} \u2014 settable: ${A.join(", ")}`),Object.keys(_).length||P("`set` names no fields"),_},R=A=>{let{startDate:_,endDate:N,snapped:U}=Mq(A.startDate,A.endDate);return U&&(p=!0),{startDate:_,endDate:N,snapped:U}},G=A=>{let _=Nq(a,A);return Lt(A)==="me"&&(f=!0),m(_),{key:_.id??Lt(A),label:_.label}},V=(A,_,N,U,z)=>{let ue=Lt(A);ue||P(`needs a ${U} id`);let pe=_.find(Se=>Se[N]===ue);return pe||P(`no ${U} "${ue}" \u2014 see \`bostrat-roadmap ls\``),z[ue]={...pe},pe};switch(M){case"circuit.create":{let A=fo(O.name,P$,"name");A||P("a circuit needs a name");let _=Lt(O.type)||"build";sp.has(_)||P(`bad type "${_}" (${[...sp].join(" | ")})`);let N=s.find(z=>String(z.name).toLowerCase()===A.toLowerCase());N&&P(`a circuit named "${N.name}" already exists (${N.id}) \u2014 update it instead of making a twin`);let U=g(O.ref,A);return{op:M,...U?{ref:U}:{},name:A,description:fo(O.description,D$,"description"),type:_}}case"circuit.update":{let A=py(s,O.circuit);A.id||P("can't update a circuit created in the same plan \u2014 set its fields on the create op"),w(A);let _=E(Iq),N={};if(_.name!==void 0){let U=fo(_.name,P$,"name");U||P("name can't be blank"),U!==A.name&&(N.name=U)}return _.description!==void 0&&(N.description=fo(_.description,D$,"description")),_.status!==void 0&&(B$.has(_.status)||P(`bad status "${_.status}" (${[...B$].join(" | ")})`),_.status!==A.status&&(N.status=_.status)),_.type!==void 0&&(sp.has(_.type)||P(`bad type "${_.type}" (${[...sp].join(" | ")})`),_.type!==(A.type??"build")&&(N.type=_.type)),Object.keys(N).length||P("nothing would change \u2014 the set equals the circuit's current values"),{op:M,circuit:A.id,name:A.name,set:N}}case"circuit.delete":{let A=py(s,O.circuit);A.id||P("can't delete a circuit created in the same plan"),w(A);let _=o.some((N,U)=>U<$&&Lt(N?.op)==="circuit.update"&&N?.set?.status&&N.set.status!=="active"&&Lt(N?.circuit)===Lt(O.circuit));return A.status==="active"&&!_&&P(`\u201C${A.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:M,circuit:A.id,name:A.name,status:A.status}}case"person.create":{let A=fo(O.label,dy,"label");A||P("a person row needs a label");let _=a.find(U=>String(U.label).toLowerCase()===A.toLowerCase());_&&P(`a roadmap row labelled "${_.label}" already exists (${_.personId})`);let N=g(O.ref,A);return{op:M,...N?{ref:N}:{},label:A}}case"slot.create":{let A=py(s,O.circuit);w(A);let _=G(O.person),N=R(O);return{op:M,circuit:A.id??A.ref,circuitName:A.name,person:_.key,personLabel:_.label,...N,estUsd:L$(O.estUsd)}}case"slot.update":{let A=V(O.slot,i,"slotId","slot",l.slots),_=E($q),N={};if(_.person!==void 0){let z=G(_.person);N.person=z.key,N.personLabel=z.label}if(_.startDate!==void 0||_.endDate!==void 0){let z=R({startDate:_.startDate??A.startDate,endDate:_.endDate??A.endDate});z.startDate!==A.startDate&&(N.startDate=z.startDate),z.endDate!==A.endDate&&(N.endDate=z.endDate)}_.estUsd!==void 0&&(N.estUsd=L$(_.estUsd)),Object.keys(N).length||P("nothing would change");let U=s.find(z=>z.id===A.circuitId);return{op:M,slot:A.slotId,circuitName:U?.name??null,set:N}}case"slot.delete":{let A=V(O.slot,i,"slotId","slot",l.slots),_=s.find(N=>N.id===A.circuitId);return{op:M,slot:A.slotId,circuitName:_?.name??null,startDate:A.startDate,endDate:A.endDate}}case"reservation.create":{let A=G(O.person),_=fo(O.label,dy,"label");return _||P("a reservation needs a label (Leave, Support rotation, \u2026)"),{op:M,person:A.key,personLabel:A.label,label:_,...R(O)}}case"reservation.update":{let A=V(O.reservation,c,"reservationId","reservation",l.reservations),_=E(Rq),N={};if(_.person!==void 0){let U=G(_.person);N.person=U.key,N.personLabel=U.label}if(_.label!==void 0){let U=fo(_.label,dy,"label");U||P("label can't be blank"),U!==A.label&&(N.label=U)}if(_.startDate!==void 0||_.endDate!==void 0){let U=R({startDate:_.startDate??A.startDate,endDate:_.endDate??A.endDate});U.startDate!==A.startDate&&(N.startDate=U.startDate),U.endDate!==A.endDate&&(N.endDate=U.endDate)}return Object.keys(N).length||P("nothing would change"),{op:M,reservation:A.reservationId,label:A.label,set:N}}case"reservation.delete":{let A=V(O.reservation,c,"reservationId","reservation",l.reservations);return{op:M,reservation:A.reservationId,label:A.label,startDate:A.startDate,endDate:A.endDate}}default:return P("unhandled op")}});b.forEach((y,$)=>{for(let O of[y.circuit,y.person,y.set?.person])if(hy(O)&&!d.has(String(O).slice(1)))throw new Error(`op ${$+1} (${y.op}): unknown ref "${O}" \u2014 no earlier op in this plan creates it`)});let x=a.some(y=>y.kind==="user"&&y.userId);return{why:fo(r.why,Eq,"why"),ops:b,base:l,resolved:u,snapped:p,createsMeRow:f&&!x}}async function H$(e,t,n,r={}){let o=Pq(t,n,r),s=Aq(),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 Dq=async(e,t)=>{if(!t)throw new Error("proposalId required");let n=await K({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 W$(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 Dq(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,fy+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}}Vu();de();Tr();de();Zn();ud();var q$=10,K$=200,Bq=120,jq=24,z$=/^\d{4}-\d{2}-\d{2}$/;function wy(e=process.env){return(e.CHANGELOG_REPOS||"globocodes/bostrat").split(",").map(t=>t.trim()).filter(Boolean)}var Lq=(e=Date.now())=>new Date(e).toISOString().slice(0,10),ht=(e,t="i")=>new RegExp(e,t),Fq=[{re:ht("^(business|docs|chore|ci|refactor|test|security|sec)(\\([^)]*\\))?!?:"),reason:"non-product PR prefix"},{re:ht("\\bSPC\\b",""),reason:"business (SPC)"},{re:ht("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),reason:"business"},{re:ht("competitor|cloudcli|\\bkiro\\b"),reason:"competitor research"},{re:ht("\\bReplicas\\b",""),reason:"competitor research"},{re:ht("tenanc|tenant|perimeter|ip[- ]gate|access[- ]code|vulnerab|\\bCVE\\b|audit|hardening|security|\\bsweep\\b"),reason:"security / tenancy"},{re:ht("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),reason:"internal codename"},{re:ht("^track/(business|security|spc|sec)-"),reason:"non-product branch"}],Uq=[ht("\\bSPC\\b",""),ht("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),ht("competitor|cloudcli|\\bkiro\\b"),ht("\\bReplicas\\b",""),ht("tenanc|\\btenants?\\b|cross-tenant|perimeter|ip[- ]gate|vulnerab|\\bCVE\\b|hardening|security register|audit finding"),ht("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),ht("(^|[^\\w&])#\\d+\\b"),ht("\\btrack/[\\w.-]+")];function Hq({title:e="",headRef:t=""}={}){let n=String(e||""),r=String(t||"");for(let{re:o,reason:s}of Fq)if(o.test(n)||o.test(r))return s;return null}function G$(e){let t=String(e||"");for(let n of Uq){let r=n.exec(t);if(r)return r[0].trim()}return null}function V$(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 Wq=/^\*\*([^*]+?)\*\*\s*[:.]?\s*[—–-]?\s*(.*)$/;function qq(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=ic(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(`
754
+ `)){let s=o.trim();if(!s)continue;if(s.startsWith("#")){n==null&&(n=s.replace(/^#+\s*/,"").trim().slice(0,Bq)||null);continue}let a=/^[-*]\s+(.*)$/.exec(s);if(!a)continue;let i=a[1].trim(),c=null,l=new RegExp(`^\\[([^\\]]{1,${jq}})\\]\\s+(.*)$`).exec(i);if(l&&(c=l[1].trim(),i=l[2].trim()),!i)continue;let u=Wq.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=G$(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>K$)throw new Error(`bullet ${r.length+1} is ${i.length} chars \u2014 over the ${K$}-char cap; a changelog bullet is one line`);r.push({text:i,...c?{area:c}:{}})}if(n){let o=G$(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>q$)throw new Error(`${r.length} bullets \u2014 over the ${q$}-bullet cap; group related changes into one line`);return{title:n||null,bullets:r}}async function Kq(e,{repos:t=wy()}={}){let n=new Set(t);return(await Xn()).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:Hq({title:r.title,headRef:r.headRef})}))}async function J$(e,t){let n=await Kq(e,t);return{prs:n.filter(r=>!r.excluded),excluded:n.filter(r=>r.excluded)}}async function Y$(e,{md:t,day:n=null}){let r=qq(t),o=n==null||n===""?Lq():String(n);if(!z$.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 X$(e,{day:t}){let n=String(t||"");if(!z$.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}}jo();Zn();Fo();de();jo();pt();or();Zn();Ni();qu();$u();Fi();An();import{execFile as r5}from"node:child_process";import{promisify as o5}from"node:util";var Gq=new Set(["pull_request","check_suite","workflow_run","push"]),zq=/^[^/\s]+\/[^/\s]+$/,Vq=500,gy=new Set,yy=[],ap=new Map,Yt={hourStart:0,byEvent:{},duplicates:0,rejected:0};function by(e,t,n){let r=Math.floor(e/36e5)*36e5;r!==Yt.hourStart&&(Yt.hourStart=r,Yt.byEvent={},Yt.duplicates=0,Yt.rejected=0),t==="accepted"?Yt.byEvent[n]=(Yt.byEvent[n]||0)+1:Yt[t]+=1}function Jq(e){if(!e||typeof e!="object"||e.forge!=="github"||typeof e.event!="string"||!Gq.has(e.event)||typeof e.repo!="string"||!zq.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 Z$(e,{now:t=Date.now(),onAccept:n=null,log:r=console}={}){let o=Jq(e);if(!o)return by(t,"rejected"),{ok:!1,error:"malformed github event envelope"};if(o.deliveryId){if(gy.has(o.deliveryId))return by(t,"duplicates"),{ok:!0,duplicate:!0,envelope:o};for(gy.add(o.deliveryId),yy.push(o.deliveryId);yy.length>Vq;)gy.delete(yy.shift())}let s=o.repo.toLowerCase(),a=ap.get(s)||{lastDeliveryAt:0,count:0};a.lastDeliveryAt=t,a.count+=1,ap.set(s,a),by(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 Yq(e,t=Date.now()){let n=ap.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 Q$=1440*6e4;function ky(e,t=Date.now()){let n=Yq(e,t);return n.covered&&n.ageMs<Q$}function eR(e=Date.now()){let t={};for(let[n,r]of ap)t[n]={lastDeliveryAt:r.lastDeliveryAt,count:r.count,covered:e-r.lastDeliveryAt<Q$};return{hourStart:Yt.hourStart,byEvent:{...Yt.byEvent},duplicates:Yt.duplicates,rejected:Yt.rejected,repos:t}}de();Zn();kr();or();An();function tR(e){return(e?.checks?.failed??0)>0?"red":e?.mergeable==="CONFLICTING"?"conflict":e?.mergeStateStatus==="BEHIND"?"behind":null}function Xq(e){return!(!e?.checks||e.checks.pending>0||e.mergeabilityPending||e.mergeable==="UNKNOWN"||e.mergeStateStatus==="UNKNOWN")}var Zq=new Set(["merged","closed","lost"]);function Qq(e,t){if(!e?.blocked)return null;let n=tR(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 e5(e,t){return e.autoMerge?!0:t==="ci-fixed"?!!(e.ciFix||e.ciFixAwait):t==="reconciled"?!!(e.reconcile||e.reconcileAwait):!1}async function t5(e,t,n,r,o){return(await K(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 n5(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 ip(e,t={}){let{now:n=Date.now(),slugOf:r=_e,lookup:o=at,note:s=aS,tracks:a=async()=>(await me()).filter(d=>!Ve(d)),asked:i=t5,emitChange:c=n5}=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(!Xq(f))continue;let w=await o(p,f.number).catch(()=>null);if(!w?.trackId||Zq.has(w.state))continue;let{prev:m}=await s(p,f.number,{blocked:tR(f),sha:f.headSha??null,at:n});if(!m)continue;let g=Qq(m,f);if(!g||e5(w,g.change))continue;u??=new Map((await a()).map($=>[$.id,$]));let b=u.get(w.trackId);if(!b)continue;let x=f.headSha??null;if(await i(b,g.change,f.number,x,m.at||0))continue;let y={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"?y.passed=f.checks.passed:y.base=f.baseRefName||null,await c(b,g.change,y),l.push({change:g.change,number:f.number,reason:g.reason})}catch{}}return l}var Sy=o5(r5),cR=3e4,s5=30*6e4,a5=cR,i5=10*6e4,c5=10080*6e4,l5=60*6e4,u5=8,lR=1440*6e4,d5=3,uR="number,url,title,headRefName,headRefOid,state,mergedAt,closedAt",vy=60*6e4,p5=15*6e4,f5=9e4,m5=1440*6e4,cp=new Map,lp=new Map,h5=/could not resolve|not found|no pull requests?/i,w5=e=>h5.test(String(e?.message||e||""));function g5(e,t){return[e.ciFix?.delegatedAt,e.reconcile?.delegatedAt,e.ciFixAwait?.since,e.reconcileAwait?.since].some(n=>n&&t-n<vy)}var nR={fast:a5,slow:i5,decay:l5};function rR(e,t,n=ky){return dR(e,t,{grace:0})||!n(e.repo,t)&&(e.armedAt&&t-e.armedAt<s5||g5(e,t))?"fast":t-(e.firstSeen||0)>c5?"decay":"slow"}function Jc(e,t,n,r){let o=e.lanes?.get(se(t.repo,t.number))||{};return Iu({change:n,repo:t.repo,number:Number(t.number),githubAt:r||null,lane:o.lane||null,intervalMs:o.intervalMs||null,source:"watch"})}async function y5(e,t){er("watch");try{let{stdout:n}=await Sy("gh",["pr","view",String(t),"--repo",e,"--json",uR],{timeout:3e4,maxBuffer:4194304,env:{...process.env,...await yn({slug:e})}});return JSON.parse(n||"null")}catch(n){throw qr(n)&&Kr(n),n}}async function b5(e){er("watch");try{let{stdout:t}=await Sy("gh",["pr","list","--repo",e,"--state","all","--limit","100","--json",uR],{timeout:3e4,maxBuffer:8388608,env:{...process.env,...await yn({slug:e})}}),n=new Map;for(let r of JSON.parse(t||"[]"))n.set(Number(r.number),r);return n}catch(t){throw qr(t)&&Kr(t),t}}async function k5(){let e=new Map;for(let t of await me().catch(()=>[]))e.set(t.id,t);return e}async function x5(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 Wu(e,t).catch(()=>{})}async function v5(e,t){let n=await Bo(e);return n?Xs(n,t):null}async function S5(e,t,n){let r=await Bo(e);if(!r)throw new Error(`no local checkout for ${e}`);return Zs(r,t,{method:n})}async function T5(e,t){let n=await Bo(e);if(!n)throw new Error(`no local checkout for ${e}`);return Bi(n,t)}async function A5(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 Ia(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 E5=10*6e4;async function _5(e,t,n){let r=e.autoMerge?.armedAt||0;if(r&&(n.now??Date.now())-r>lR){await Ia(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 Ia(e,o,t,n,`check${o.checks.failed===1?"":"s"} failed: ${a}`);return}if(o.mergeable==="CONFLICTING"){await Ia(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<E5)return;await Ia(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 Ia(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 Ia(e,o,t,n,String(a?.message||a).trim()||"merge failed");return}await pR(e,{...o,state:"MERGED"},t,n,{change:"auto-merged",githubAt:o.checks.settledAt||null})}}async function $a(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 I5(e,t){try{return await Sy("git",["-C",e.cwd,"cat-file","-e",`${t}^{commit}`],{timeout:1e4}),!0}catch{return!1}}async function Vc(e,t,n,r=()=>!0){return(await K(e).catch(()=>[])).some(s=>s.type==="pr.state.changed"&&s.payload?.change===t&&s.payload?.number===Number(n)&&r(s))}var Ra=(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 dR(e,t,{grace:n=f5}={}){if(e.announced!==!1)return!1;let r=t-(e.firstSeen||0);return r>=n&&r<=m5}async function $5(e,t,n,r){let o=r.now??Date.now();if(!dR(e,o))return!1;let s=n.get(e.trackId)||null;if(!s||Ve(s))return!1;let a=(s.boxes||[]).find(d=>d.name===s.leadBox);return await(r.midTurn??Lo)(s.leadBox,a?.agent).catch(()=>!1)?!1:(await K(s).catch(()=>[])).some(d=>d.type==="pr.state.changed"&&d.payload?.number===Number(e.number))?(await(r.claim??Yn)(e.repo,e.number).catch(()=>null),!1):await(r.claim??Yn)(e.repo,e.number).catch(()=>null)?(await $a(s,"opened",{...Ra(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 R5(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 ku(e.repo,e.number,{headSha:s}).catch(()=>{}),e.reconcile?.headSha&&s!==e.reconcile.headSha&&await vu(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<p5;await sS(e.repo,e.number,s).catch(()=>{}),e.baseFoldAt&&await oS(e.repo,e.number).catch(()=>{}),!i&&!c&&!l&&a&&!await r.localHasCommit(a,s).catch(()=>!1)&&!await Vc(a,"pushed",e.number,d=>d.payload?.sha===s)&&await $a(a,"pushed",{...Ra(e,t),sha:s}).catch(()=>{})}if(e.ciFixAwait)if(o-(e.ciFixAwait.since||0)>vy)await xu(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 xu(e.repo,e.number).catch(()=>{});else if(i.checks.total>0&&i.checks.pending===0){let c=Jc(r,e,"ci-fixed",i.checks.settledAt||null),l=e.ciFixAwait.since||0;a&&!await Vc(a,"ci-fixed",e.number,u=>(u.payload?.ts||0)>=l)&&await $a(a,"ci-fixed",{...Ra(e,t),sha:s,delegated:!0,passed:i.checks.passed,githubAt:c.githubAt,latencyMs:c.latencyMs,lane:c.lane}).catch(()=>{}),await xu(e.repo,e.number).catch(()=>{})}}}if(e.reconcileAwait)if(o-(e.reconcileAwait.since||0)>vy)await Su(e.repo,e.number).catch(()=>{});else{let i=await r.detail(e.repo,e.number).catch(()=>null);if(i){if(i.mergeable==="CONFLICTING")await Su(e.repo,e.number).catch(()=>{});else if(i.mergeable==="MERGEABLE"){Jc(r,e,"reconciled",null);let c=e.reconcileAwait.since||0;a&&!await Vc(a,"reconciled",e.number,l=>(l.payload?.ts||0)>=c)&&await $a(a,"reconciled",{...Ra(e,t),sha:s,delegated:!0,base:i.baseRefName||null}).catch(()=>{}),await Su(e.repo,e.number).catch(()=>{})}}}}async function O5(e,t,n,r){let o=Jc(r,e,"closed",Date.parse(t?.closedAt||"")||null),s=n.get(e.trackId);s&&!await Vc(s,"closed",e.number)&&await $a(s,"closed",{...Ra(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 C5(e,t,n){Jc(n,e,"lost",null);let r=t.get(e.trackId);r&&!await Vc(r,"lost",e.number)&&await $a(r,"lost",Ra(e,null)).catch(()=>{}),await n.notifyIfResolved(e.repo,e.number,"lost").catch(()=>{}),await n.mark(e.repo,e.number,"lost").catch(()=>{})}async function pR(e,t,n,r,o={}){let s=Jc(r,e,o.change||"merged",o.githubAt??(Date.parse(t.mergedAt||"")||null)),a=n.get(e.trackId);a&&((await K(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 oR(e={}){let{now:t=Date.now(),auth:n=Um,view:r=y5,list:o=b5,links:s=lS,trackMap:a=k5,emitMerged:i=x5,mark:c=Hr,archiveIfArmed:l=nr,notifyIfArmed:u=rr,notifyIfResolved:d=Td,followupsIfMerged:p=Xo,batchThreshold:f=d5,detail:w=v5,merge:m=S5,updateBranch:g=T5,lookup:b=at,disarm:x=Mi,emitDisarmed:y=A5,localHasCommit:$=I5,claim:O=Yn,midTurn:M=Lo,only:H=null,wantDetail:P=null,covered:E=ky,verdicts:R=null}=e;if(!(await n().catch(()=>null))?.authenticated||Eu()>0)return 0;let V=await s().catch(()=>[]),A=MS(V),_=J=>{try{return!!P?.(J)}catch{return!1}},N=H?V.filter(J=>{try{return H(J)}catch{return!1}}):V.filter(J=>t-(cp.get(se(J.repo,J.number))||0)>=nR[rR(J,t,E)]);if(!N.length)return 0;let U=Date.now(),z=new Map,ue=new Map;for(let J of[...N].sort(ji)){let ge=H?"event":rR(J,t,E);z.set(se(J.repo,J.number),{lane:ge,intervalMs:nR[ge]??null}),cp.set(se(J.repo,J.number),t),ue.has(J.repo)||ue.set(J.repo,[]),ue.get(J.repo).push(J)}let pe=await a().catch(()=>new Map),Se=new Map,Ae=(J,ge)=>{let Oe=se(J,ge);if(!Se.has(Oe)){let Me=Promise.resolve().then(()=>w(J,ge));Me.catch(()=>{}),Se.set(Oe,Me)}return Se.get(Oe)},W=R??((J,ge)=>ip([{path:J,prs:[ge]}],{now:t,slugOf:async()=>J,tracks:async()=>[...pe.values()].filter(Oe=>!Ve(Oe))}).catch(()=>{})),te={now:t,lanes:z,emitMerged:i,mark:c,archiveIfArmed:l,notifyIfArmed:u,notifyIfResolved:d,followupsIfMerged:p,detail:Ae,merge:m,updateBranch:g,lookup:b,disarm:x,emitDisarmed:y,localHasCommit:$,claim:O,midTurn:M};for(let[J,ge]of ue){let Oe,Me=new Set,I=B=>B.ciFixAwait||B.reconcileAwait||_(B)?!0:!B.autoMerge||B.trackId&&A.get(B.trackId)!==se(B.repo,B.number)?!1:t-(B.autoMerge.armedAt||0)<=lR;if(ge.length>f)Oe=await o(J).catch(()=>null);else{Oe=new Map;for(let B of ge){if(I(B)){let fe=await Ae(J,B.number).catch(()=>null);if(fe?.state){Oe.set(Number(B.number),{number:Number(B.number),url:fe.url,title:fe.title,headRefName:fe.headRefName,headRefOid:fe.headSha??null,state:fe.state,mergedAt:fe.mergedAt??null,closedAt:fe.closedAt??null});continue}}try{let fe=await r(J,B.number);fe?.number!=null&&Oe.set(Number(fe.number),fe)}catch(fe){w5(fe)&&Me.add(se(B.repo,B.number))}}}if(Oe)for(let B of ge){let fe=se(B.repo,B.number),Pe=Oe.get(Number(B.number));if(!Pe){if(Me.has(fe)){let Ce=(lp.get(fe)||0)+1;lp.set(fe,Ce),Ce>=u5&&(await C5(B,pe,te),lp.delete(fe),cp.delete(fe))}continue}if(lp.delete(fe),Pe.state==="MERGED"||Pe.state==="CLOSED")Pe.state==="MERGED"?await pR(B,Pe,pe,te):await O5(B,Pe,pe,te),cp.delete(fe);else{await $5(B,Pe,pe,te).catch(()=>{}),await R5(B,Pe,pe,te).catch(()=>{});let Ce=!B.trackId||A.get(B.trackId)===fe;B.autoMerge&&Ce&&await _5(B,pe,te).catch(()=>{});try{if(_(B)&&!Se.has(fe)&&Ae(B.repo,B.number),Se.has(fe)){let wn=await Se.get(fe).catch(()=>null);wn?.checks&&await W(B.repo,wn)}}catch{}}}}let ie={};for(let{lane:J}of z.values())ie[J]=(ie[J]||0)+1;return console.log(`[pr-watch] probed ${N.length} link(s) (${Object.entries(ie).map(([J,ge])=>`${J} ${ge}`).join(", ")}) in ${Date.now()-U}ms`),N.length}function sR(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 xy=!1,up=!1,dp=[],aR=Promise.resolve();async function M5(){for(;up||dp.length;){if(up){up=!1;try{await oR()}catch{}continue}let e=dp;dp=[];let t=e.map(r=>r.spec),n=Object.assign({},...e.map(r=>r.deps||{}));try{await oR({...n,only:r=>t.some(o=>sR(o,r)),wantDetail:r=>t.some(o=>o.detail&&sR(o,r))})}catch{}}}function pp(e,t){return e===null?up=!0:dp.push({spec:e,deps:t}),xy||(xy=!0,aR=M5().finally(()=>{xy=!1})),aR}function fR(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 pp({repo:n,numbers:r,branch:e.branch||null,event:e.event||null,detail:e.detail===!0},t)}var N5=6e4,iR=0;function mR(e=void 0){let t=e?.now??Date.now();return t-iR<N5?Promise.resolve():(iR=t,pp({all:!0},e))}function hR(){pp(null),setInterval(()=>pp(null),cR)}jo();ah();od();or();An();var P5=new Set(["opened","reopened","closed","synchronize","ready_for_review","converted_to_draft","edited"]);async function D5({tracks:e=me,reconcile:t=rd}={}){for(let n of(await e().catch(()=>[])).filter(r=>!Ve(r)))await t(n,{bypassThrottle:!0}).catch(()=>{})}function wR(e,t={}){let{invalidate:n=Kt,probe:r=fR,poke:o=hT,reconcileOpened:s=D5}=t;try{n()}catch{}let a={probe:null,poked:!1,reconciled:!1};if(!e?.repo)return a;if(e.event==="pull_request"&&P5.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}ct();de();or();An();import{randomUUID as B5}from"node:crypto";var j5=2e4,gR=3,Oa=new Map,Ty=new Set;async function yR(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 L5(e={}){let{sessions:t=null,tracks:n=null,append:r=C,read:o=K,now:s=Date.now()}=e;if(process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1")return;let a,i;try{a=t??await Qt(),i=n??await me()}catch{return}let c=new Map(a.map(u=>[u.name,u])),l=new Set;for(let u of i){if(Ve(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=(Oa.get(d.name)||0)+1;Oa.set(d.name,f),f===gR&&(Ty.add(d.name),await yR(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:B5(),box:d.name,agent:d.agent}}).catch(()=>{}))}else{let f=(Oa.get(d.name)||0)>=gR;if(Oa.delete(d.name),f||!Ty.has(d.name)){Ty.add(d.name);let w=await yR(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[...Oa.keys()])l.has(u)||Oa.delete(u)}var Yc=null,Ay=!1;function bR(){return Yc?()=>{}:(Yc=setInterval(()=>{Ay||(Ay=!0,L5().catch(()=>{}).finally(()=>{Ay=!1}))},j5),Yc.unref?.(),()=>{clearInterval(Yc),Yc=null})}Mo();od();de();jo();Fo();Mo();Ki();import{randomUUID as F5}from"node:crypto";async function U5(){let e=await Promise.resolve().then(()=>(or(),g_));return{sayToLead:e.sayToLead,queueShipCompleteNotify:e.queueShipCompleteNotify}}var Ey={listRepoPrs:En,readEvents:K,appendEvent:C,sayDeps:U5,currentBranch:Gr};async function H5(e,t=Ey,{branch:n=null}={}){if(!e?.cwd)return null;let r=n||await(t.currentBranch??Gr)(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 _y(e,t,{actions:n,notify:r=!1}={},o=Ey){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 H5(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=F5();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 Iy(e,{offerId:t,choice:n}={},r=Ey){if(!t)throw new Error("offerId required");if(!["push","new","dismiss"].includes(n))throw new Error('choice "push" | "new" | "dismiss" required');return Jr(`prx:${e.id}:${t}`,()=>W5(e,{offerId:t,choice:n},r))}async function W5(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=Fr.filter(d=>d!=="pr"&&(i.includes(d)||d==="push")),c=await u(e.id,zs(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,zv(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}}Ki();import wr from"node:fs/promises";import Ca from"node:path";import ER from"node:os";import kR from"node:fs/promises";import fp from"node:path";import{execFile as q5}from"node:child_process";import{promisify as K5}from"node:util";import{fileURLToPath as G5}from"node:url";var z5=K5(q5),vR=fp.dirname(G5(import.meta.url)),V5=fp.resolve(vR,"..","..","client","dist"),J5="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",Y5=new Map([...J5].map((e,t)=>[e,t]));function X5(e){let t=[],n=0,r=0;for(let o of e){let s=Y5.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 Z5(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=X5(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 Q5(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 xR=new Map;async function eK(e){let t;try{t=await kR.stat(e)}catch{return null}let n=xR.get(e);if(n&&n.mtimeMs===t.mtimeMs)return n;try{let r=JSON.parse(await kR.readFile(e,"utf8")),o={mtimeMs:t.mtimeMs,sources:r.sources||[],lines:Z5(r.mappings||"")};return xR.set(e,o),o}catch{return null}}var $y=null;function tK(){return $y||($y=process.env.BOSTRAT_RELEASE?Promise.resolve(process.env.BOSTRAT_RELEASE):z5("git",["rev-parse","--short","HEAD"],{cwd:fp.resolve(vR,"..","..")}).then(e=>e.stdout.trim()).catch(()=>null)),$y}var nK=/(?:https?:\/\/[^\s()]*)?\/assets\/([^\s()/]+\.js):(\d+):(\d+)/g;async function rK(e,{distDir:t=V5}={}){let n=[],r=0,o=!1;for(let s of e.matchAll(nK)){let[a,i,c,l]=s,u=await eK(fp.join(t,"assets",`${i}.map`)),d=u?Q5(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 SR(e,t={}){try{if(!e?.error?.stack||!e.release||e.release==="unknown")return e;let n=t.release??await tK();if(!n||e.release!==n)return e;let{stack:r,symbolicated:o}=await rK(e.error.stack,t);o&&(e.error.stack=r,e.error.symbolicated=!0)}catch{}return e}var oK=()=>process.env.BOSTRAT_STATE_DIR||Ca.join(process.env.HOME||ER.tmpdir(),".bostrat"),mo=()=>Ca.join(oK(),"telemetry"),_R=()=>Ca.join(mo(),".relay-offsets.json"),sK=50,aK=14,iK=3e4,TR=500,Ft=(e,t)=>typeof e=="string"?e.slice(0,t):"";function cK(e,t){if(!e||typeof e!="object")return null;let n=Ft(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:Ft(e.anonId,64),sessionId:Ft(e.sessionId,64),userId:Ft(e.userId,64),release:Ft(e.release,64),appVersion:Ft(e.appVersion,32),route:Ft(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:Ft(e.error.kind,256),message:Ft(e.error.message,8192),stack:Ft(e.error.stack,32768),fingerprint:Ft(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:Ft(s?.n,64),r:Ft(s?.r,128)}))),o}var IR=e=>new Date(e).toISOString().slice(0,10),AR=0;async function $R(e,t=Date.now()){let r=(Array.isArray(e?.events)?e.events.slice(0,sK):[]).map(s=>cK(s,t)).filter(Boolean);if(!r.length)return 0;for(let s of r)s.error?.stack&&await SR(s);await wr.mkdir(mo(),{recursive:!0});let o=Ca.join(mo(),`${IR(t)}.ndjson`);return await wr.appendFile(o,r.map(s=>JSON.stringify(s)+`
755
+ `).join(""),"utf8"),t-AR>6*3600*1e3&&(AR=t,lK(t).catch(()=>{})),r.length}async function lK(e=Date.now()){let t=IR(e-aK*24*3600*1e3),n=[];try{n=await wr.readdir(mo())}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 wr.rm(Ca.join(mo(),s),{force:!0});let o=await OR();for(let s of r)delete o[s];await CR(o)}var mp=new Map;function RR(e,t=Date.now()){let n=e||"unknown",r=mp.get(n);return r||(mp.size>512&&mp.clear(),r={tokens:40,at:t},mp.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 OR(){try{return JSON.parse(await wr.readFile(_R(),"utf8"))||{}}catch{return{}}}async function CR(e){await wr.mkdir(mo(),{recursive:!0}),await wr.writeFile(_R(),JSON.stringify(e),"utf8")}function uK(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||ER.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 dK({fetchImpl:e=fetch}={}){let t=await Q_();if(!t)return{sent:0,disabled:!0};let n;try{n=(await wr.readdir(mo())).filter(s=>s.endsWith(".ndjson")).sort()}catch{return{sent:0,disabled:!1}}let r=await OR(),o=0;for(let s of n){let a=Ca.join(mo(),s),i=r[s]||0,c;try{let p=await wr.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(`
756
+ `).filter(Boolean),d=[];for(let p of u)try{d.push(JSON.parse(p))}catch{}for(let p=0;p<d.length;p+=TR){let f=d.slice(p,p+TR).map(m=>uK(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 CR(r)}return{sent:o,disabled:!1}}var Ry=null,Oy=!1;function MR(){Ry||(Ry=setInterval(async()=>{if(!Oy){Oy=!0;try{await dK()}catch(e){console.error("[telemetry] relay failed:",e?.message||e)}finally{Oy=!1}}},iK),Ry.unref?.())}import wp from"node:fs/promises";import jR from"node:path";import pK from"node:os";var LR=()=>process.env.BOSTRAT_STATE_DIR||jR.join(process.env.HOME||pK.tmpdir(),".bostrat"),FR=()=>jR.join(LR(),"dictation-glossary.json"),fK=100,mK=500,hK=["bostrat","globopi","codex","tmux","worktree","Deepgram","Linear","Firecracker","Tigris","WireGuard","misous","postyx","cedar","gerbil","Anthropic","Opus","Haiku","Sonnet","keyterm","monorepo","dogfood"],gp=null,Cy=null,My=Promise.resolve();function NR(){let e={},t=Date.now();for(let n of hK)e[n.toLowerCase()]={term:n,count:1,lastUsed:t,source:"seed"};return e}async function UR(){return gp||(Cy??=wp.readFile(FR(),"utf8").then(e=>JSON.parse(e)?.terms??NR()).catch(()=>NR()).then(e=>gp=e).finally(()=>Cy=null),Cy)}async function PR(){let e=JSON.stringify({terms:gp},null,2),t=FR(),n=`${t}.${process.pid}.tmp`;await wp.mkdir(LR(),{recursive:!0}),await wp.writeFile(n,e),await wp.rename(n,t)}function wK(){return My=My.then(PR,PR),My.catch(()=>{})}async function Ny(){return Object.values(await UR()).sort((t,n)=>n.count-t.count||n.lastUsed-t.lastUsed)}var gK=e=>Math.max(1,Math.ceil(e.length/4));async function yK(){let e=[],t=0;for(let{term:n}of await Ny()){let r=gK(n);if(!(t+r>mK)&&(e.push(n),t+=r,e.length>=fK))break}return e}async function bK(e,t){let n=await UR(),r=e.toLowerCase(),o=n[r];n[r]={term:e,count:(o?.count??0)+1,lastUsed:Date.now(),source:o?.source??t}}var DR=e=>(e||"").split(/\s+/).map(t=>t.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"")).filter(Boolean),hp=e=>e.toLowerCase();function BR(e){return!new RegExp("\\p{L}","u").test(e)||e.length<3?!1:/^[a-z]+$/.test(e)?e.length>=4:!0}async function HR(e,t){let n=DR(e),r=DR(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]=hp(n[u])===hp(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;)hp(n[c])===hp(r[l])?(c++,l++):a[c+1][l]>=a[c][l+1]?c++:(BR(r[l])&&i.add(r[l]),l++);for(;l<s;l++)BR(r[l])&&i.add(r[l]);if(!i.size)return[];for(let u of i)await bK(u,"learned");return await wK(),[...i]}var Xc=null;function kK(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 WR(){if(!Xc)return null;let e=await Cc();if(!e||e.apiKey.slice(-6)!==Xc.keyTail)return null;let{keyTail:t,...n}=Xc;return n}async function qR(e,t){let n=await Cc();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 yK())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=kK(o.status,i);c.persistent&&(Xc={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 Xc=null,{transcript:(await o.json())?.results?.channels?.[0]?.alternatives?.[0]?.transcript??""}}de();var Py={"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 xK(e){if(!e)return null;let t=String(e).trim();if(Py[t])return t;let n=null;for(let r of Object.keys(Py))t.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function vK(e,t={}){let n=Py[xK(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 SK(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 Zc=null;async function TK(){if(!Zc)return null;let e=await Hd();if(!e||e.apiKey.slice(-6)!==Zc.keyTail)return null;let{keyTail:t,...n}=Zc;return n}async function AK(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=SK(t.status,o);s.persistent&&(Zc={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}Zc=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 EK={openai:AK};async function KR(){let e=await Hd();return e?{configured:!0,provider:e.provider,model:e.model,voice:e.voice,problem:await TK()}:{configured:!1}}async function GR(){let e=await Hd();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 EK[e.provider](e);return{provider:e.provider,model:e.model,voice:e.voice,...t}}async function zR(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=vK(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}}An();var tO=Te.dirname(IK(import.meta.url)),VR=Number(process.env.PORT)||3362,bp=yg(process.env),nO=Number(process.env.BOSTRAT_AUTO_TRIGGER_PCT)||80,Ma=c$(process.env.BOSTRAT_ALLOW_IPS),Fy=l$(process.env.BOSTRAT_VIEW_FRONT_CIDRS,op),Uy=d$(),rO=process.env.BOSTRAT_ALLOW_LAN_TOKENLESS!=="1",S=Ut();S.disable("x-powered-by");S.use((e,t,n)=>{t.setHeader("x-content-type-options","nosniff"),rp(e.headers.host)||(t.setHeader("x-frame-options","DENY"),t.setHeader("referrer-policy","strict-origin-when-cross-origin")),n()});S.use((e,t,n)=>{if(Gc(e)||Ma.allowed(Ma.clientIp(e))||Fy.allows(e))return n();t.status(403).type("text/plain").send("bostrat: access restricted to the allowlist")});S.use(g$);S.use(m$({token:Uy,enforce:rO}));S.use("/api/mocks",Ut.json({limit:"1mb"}));S.use("/api/mocks",Ut.raw({type:"image/png",limit:"24mb"}));S.use("/api/mocks",Ut.raw({type:["video/mp4","video/webm"],limit:"105mb"}));S.use("/api/runbooks",Ut.json({limit:"1mb"}));S.use("/api/tracks/adopt",Ut.json({limit:"1mb"}));S.use("/api/telemetry",Ut.json({limit:"256kb"}));S.use("/api/hook",Ut.json({limit:"2mb"}));S.use("/api/dictation",Ut.raw({type:["audio/*","video/mp4","application/octet-stream"],limit:"32mb"}));S.use("/api/tracks/:id/upload",Ut.raw({type:()=>!0,limit:"25mb"}));S.use(Ut.json({limit:"64kb"}));S.get("/api/health",async(e,t)=>{t.json({ok:!0,tmuxSocket:Rt,hostTmuxAlive:await Er(),autoTriggerPct:nO,plane:Na?Na.status():null})});S.get("/api/sessions",async(e,t)=>{t.json({sessions:await Qt()})});S.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 _r(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})}});S.delete("/api/sessions/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!je(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 en(n),t.json({ok:!0})}catch(r){t.status(500).json({error:`failed to kill: ${r?.message||r}`})}});S.get("/api/context/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!je(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})});S.post("/api/handoff/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!je(n))return t.status(400).json({error:"invalid session name"});try{let r=await ax(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)})}});S.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 JR=10;async function oO(){let e=await me(),t=await T_(e);return{tracks:e,views:await Fh(),queuedOf:n=>Vo(n),jobsOf:n=>t.get(n)??[]}}S.get("/api/idle-guard",async(e,t)=>{try{t.json(mg(await oO()))}catch{t.status(500).json({busy:!0,reasons:["error"]})}});var Xt=Qo(),NK=L_({kind:Xt}),Qc=null,vt=()=>Qc&&["auto","prompt","off"].includes(Qc)?Qc:NK,Ly=null,PK=Rc.has(Xt),sO=async({to:e,from:t})=>!PK||Pd(await Oc())?!1:(tl.arm({to:e,from:t,kind:Xt}),!0);async function DK(e){let t=vt();Qc=e??null;let n=vt();if(t!==n){if(console.log(`[self-update] policy ${t} \u2192 ${n} (${e?"plane row":"node default"})`),n!=="auto"){tl.cancel();return}Ly&&await sO(Ly)}}var aO=(()=>{try{return MK(import.meta.url)("../package.json").version||null}catch{return null}})(),tl=U_({isBusy:async()=>mg(await oO()).busy,onStuck:({to:e,from:t})=>jn({current:t,latest:e,installKind:Xt,policy:vt(),status:"stuck"}).catch(()=>{}),onStarted:({to:e,from:t,result:n})=>(n?.ok?jn({current:t,latest:e,installKind:Xt,policy:vt(),status:"updating",reason:"auto"}):jn({current:t,latest:e,installKind:Xt,policy:vt(),status:"failed",error:n?.reason})).catch(()=>{})});S.get("/api/node/self-update",async(e,t)=>{t.json({installKind:Xt,policy:vt(),policySource:Qc?"plane":"node",current:aO,status:await Oc(),armed:tl.armed})});S.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 Dd({to:n,kind:Xt,reason:"manual"});if(r.ok)return tl.cancel(),jn({current:r.from,latest:n,installKind:Xt,policy:vt(),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 iO(){try{let e=await F_();e&&await jn({current:e.from,latest:e.to,installKind:e.kind||Xt,policy:vt(),status:e.status,error:e.error,reason:e.reason}),await Cw({current:aO,installKind:Xt,policy:vt()})}catch{}}iO();setInterval(iO,3e4).unref();S.get("/api/tracks",async(e,t)=>{let n=(await me()).filter(s=>!s.transferredTo),r=n.filter(s=>s.archivedAt&&!s.archiving),o=n;if(e.query.archived!=="all"&&r.length>JR){let s=new Set([...r].sort((a,i)=>(i.archivedAt||0)-(a.archivedAt||0)).slice(0,JR).map(a=>a.id));o=n.filter(a=>!a.archivedAt||a.archiving||s.has(a.id))}t.json({tracks:o,archivedTotal:r.length,agents:bc,agentAvailability:await yd(),tickets:await fI()})});S.get("/api/cost",async(e,t)=>{try{let n=await me();e.query.track&&(n=n.filter(o=>o.id===e.query.track));let r=await Qg(n);if(r.cursorUsage=Th(),e.query.format==="text")return t.type("text/plain").send(jI(r));t.json(r)}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/usage/roundup",async(e,t)=>{try{let n=await ty(await me(),{window:e.query.window,from:e.query.from,to:e.query.to});if(e.query.format==="text")return t.type("text/plain").send(WI(n));t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/usage/spend",async(e,t)=>{try{let n=await VI(await me(),{window:e.query.window,from:e.query.from,to:e.query.to});n.cursorUsage=Th(),n.subscriptionMonthlyUsd=Number(process.env.BOSTRAT_SUBSCRIPTION_MONTHLY_USD)||null,n.caps=Ri(),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/usage/caps",(e,t)=>{t.json(Ri())});S.post("/api/usage/caps",async(e,t)=>{try{t.json(await mu(e.body?.caps??{},{source:"local"}))}catch(n){t.status(400).json({error:n?.message||String(n)})}});S.get("/api/usage/limits",async(e,t)=>{try{let n=e.query.fresh==="1"||e.query.fresh==="true";t.json(await r$(await me(),{fresh:n}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.post("/api/hook",async(e,t)=>{try{let{mode:n,target:r}=await eb(e.get(Hn),{byToken:xc,legacy:()=>Vi(e.body?.session_id,e.body?.cwd)});if(n==="refused")return Fa("refused",{reason:"unknown-token",hook:e.body?.hook_event_name}),t.json({ok:!1,error:"unknown hook token"});if(n==="legacy-denied")return Fa("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&&Fa("mismatch",{track:r.track.id,box:r.box.name}),Fa(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 PI(e.body||{},()=>r);e.body?.hook_event_name==="Stop"&&r?.box?.cwd&&kl(r.box.cwd),t.json({ok:!0,events:o.length})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});S.get("/api/git/trailers",async(e,t)=>{t.type("text/plain");try{let n=await xc(e.get(Hn));if(!n?.track||!n?.box)return t.status(204).end();t.send((await eT(n.track,n.box)).join(`
757
757
  `)+`
758
- `)}catch{t.status(204).end()}});S.post("/api/git/committed",async(e,t)=>{try{let n=await xc(e.get(Hn));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?Te.resolve(n.box.cwd):null,s=typeof e.body?.cwd=="string"&&e.body.cwd?Te.resolve(e.body.cwd):null,a=o&&s&&(s===o||s.startsWith(o+Te.sep))?s:o;eT(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)})}});S.post("/api/tracks/:id/rework-cause",async(e,t)=>{try{let n=await oe(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 nT(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})}});S.post("/api/tracks/:id/rework-cause/retract",async(e,t)=>{try{let n=await oe(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,event:await rT(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})}});S.get("/api/usage/rework",async(e,t)=>{try{t.json(await VI(await me(),{window:e.query.window,from:e.query.from,to:e.query.to}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.post("/api/telemetry",async(e,t)=>{try{if(!$R(Ma.clientIp(e)))return t.json({ok:!0,dropped:!0});let n=await IR(e.body||{});t.json({ok:!0,events:n})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});S.get("/api/repos",async(e,t)=>{try{let n=await Wn(),r=new Set((await Promise.all(n.map(a=>_e(a.path)))).filter(Boolean).map(a=>a.toLowerCase())),s=((await qa()).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)})}});S.get("/api/github/token",async(e,t)=>{try{t.json(await dl(String(e.query.repo||"")))}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});S.get("/api/github/status",(e,t)=>{t.json({configured:ul(),calls:bS(),latency:SS(),webhook:Q$()})});S.post("/api/github/event",Ut.json({limit:"64kb"}),(e,t)=>{let n=X$(e.body,{onAccept:r=>hR(r)});if(!n.ok)return t.status(400).json({error:n.error});t.json({ok:!0,duplicate:n.duplicate})});S.post("/api/github/refresh",(e,t)=>{ub(),t.json({ok:!0})});S.get("/api/gmail/search",async(e,t)=>{try{let n=await o$(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)})}});S.get("/api/gmail/messages/:id",async(e,t)=>{try{t.json({message:await s$(String(e.params.id))})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});function Uy(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}async function el({repo:e=null,number:t=null,branch:n=null}){let r=e?await _e(e):null;if(r&&t!=null){let s=await at(r,t),a=s&&await oe(s.trackId);if(a)return a}if(!n)return null;let o=await me();return Pu(o,n,s=>Uy(s,e,r))}async function iO({repo:e=null,number:t=null,branch:n=null}){let r=await el({repo:e,number:t,branch:n}).catch(()=>null);if(r&&!Ve(r))return r;if(!n)return null;let o=e?await _e(e).catch(()=>null):null,s=await me();return Pu(s,n,a=>!Ve(a)&&Uy(a,e,o))}async function hn(e,{number:t,url:n=null,title:r=null,branch:o=null,repo:s=null,track:a=null,extra:i={}}){let c=a||await el({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 DK(e){let t=(await me()).filter(n=>!Ve(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 at(r,o.number))continue;let s=await Pu(t,o.headRefName,a=>Uy(a,n.path,r));s&&await Ct({repo:r,number:o.number,trackId:s.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"})}}}S.get("/api/git/prs",async(e,t)=>{try{let n=await RS();await DK(n.repos).catch(()=>{}),await ap(n.repos).catch(()=>{}),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.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(!Di.has(x))throw new Error(`invalid merge method: ${x}`);let y=Number(r);if(!Number.isInteger(y)||y<=0)throw new Error("invalid PR number");let $=await _e((await tr(n)).path);if(!$)throw new Error("repo has no GitHub remote");let O=await el({repo:n,number:y,branch:l}).catch(()=>null);if(!O)throw new Error("auto-merge needs a Track to watch this PR \u2014 none owns it");if(a&&await ji(n,y),await Ct({repo:$,number:y,trackId:O.id,url:d,headRef:l,title:u,source:"matched"}).catch(()=>{}),!await Ci($,y,{merge:{method:x}}))throw new Error("couldn't record the auto-merge arm");return await No($,y,i===!0),await Po($,y,c===!0&&i!==!0),Kt(),await hn("auto-armed",{number:y,url:d,title:u,branch:l,repo:n,track:O,...a?{extra:{updated:!0}}:{}}),t.json({ok:!0,number:y,auto:!0})}p=await el({repo:n,number:r,branch:l}).catch(()=>null),p&&(f=await dw(p,"merge",{count:1,summary:`merging PR #${r}`}));let m=await Zs(n,r,{method:o||"squash"});await hn("merged",{number:m.number,url:d,title:u,branch:l,repo:n});let g=await _e(n).catch(()=>null),b=!1;if(g&&(i===!0&&await No(g,m.number,!0).catch(()=>{}),c===!0&&i!==!0&&await Po(g,m.number,!0).catch(()=>{}),await rr(g,m.number).catch(()=>{}),await Xo(g,m.number).catch(()=>{}),b=await nr(g,m.number).catch(()=>!1),await Hr(g,m.number,"merged").catch(()=>{})),i===!0&&!b){let x=await el({repo:n,number:m.number,branch:l}).catch(()=>null);x&&!x.archivedAt&&await Yo(x.id).catch(()=>{})}t.json(m)}catch(m){w=m;let g=m?.message||String(m),b=/invalid|unknown repo|required|needs a Track|no GitHub remote/i.test(g)?400:502;t.status(b).json({error:g})}finally{p&&f&&await pw(p,f,w?"failed":"completed",w).catch(()=>{})}});S.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 tr(n)).path).catch(()=>null),l=c?await Mi(c,i).catch(()=>null):null;try{await Wm(n,i)}catch(u){if(!l)throw u}Kt(),await hn("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})}});S.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 PS(n,{method:r||"merge",onMerged:a=>{hn("merged",{number:a.number,url:a.url,title:a.title,branch:a.headRefName,repo:n}),o&&rr(o,a.number).catch(()=>{}).then(()=>Xo(o,a.number)).catch(()=>{}).then(()=>nr(o,a.number)).catch(()=>{}).then(()=>Hr(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})}});S.get("/api/git/prs/merge-all",(e,t)=>{t.json({jobs:NS()})});S.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(!Di.has(u))throw new Error(`invalid merge method: ${u}`);if(!n)return t.status(400).json({error:"trackId required"});let d=await oe(n);if(!d)return t.status(404).json({error:`Track ${n} isn't on this node`});i=d;let p=(await Xn()).filter(m=>m.trackId===d.id&&m.state!=="merged"&&m.state!=="closed").sort(Bi);if(!p.length)return t.status(409).json({error:"no open PRs on this Track"});c=await dw(d,"merge",{count:p.length,summary:p.length===1?"merging 1 PR":`merging ${p.length} PRs`});for(let m of p)await No(m.repo,m.number,o===!0).catch(()=>{}),await Po(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 b=await jo(m.repo);if(!b)throw new Error(`no local checkout for ${m.repo}`);let x=await Xs(b,m.number);w.push({r:g,l:m,repoPath:b,pr:x,plan:OS(x,{update:r!==!1})})}catch(b){g.ok=!1,g.action="failed",g.reason=b?.message||String(b)}}for(let{r:m,l:g,repoPath:b,pr:x,plan:y}of CS(w))try{if(y.action==="skip")m.action="skipped",m.reason=y.reason;else if(y.action==="merge")await Zs(b,g.number,{method:u}),await hn("merged",{number:g.number,url:x.url,title:x.title,branch:x.headRefName,repo:b,track:d}),await rr(g.repo,g.number).catch(()=>{}),await Xo(g.repo,g.number).catch(()=>{}),await nr(g.repo,g.number).catch(()=>{}),await Hr(g.repo,g.number,"merged").catch(()=>{}),m.action="merged";else{if(y.action==="update-arm"&&(await ji(b,g.number).catch(()=>{}),m.action="updated-armed"),!await Ci(g.repo,g.number,{merge:{method:u}}))throw new Error("couldn't record the auto-merge arm");await hn("auto-armed",{number:g.number,url:x.url,title:x.title,branch:x.headRefName,repo:b,track:d,...m.action==="updated-armed"?{extra:{updated:!0}}:{}})}}catch($){m.ok=!1,m.action="failed",m.reason=$?.message||String($)}if(Kt(),!f.some(m=>m.ok)){if(o===!0)for(let m of p)await No(m.repo,m.number,!1).catch(()=>{});if(s===!0&&o!==!0)for(let m of p)await Po(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 pw(i,c,l?"failed":"completed",l).catch(()=>{})}});S.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 oe(n);if(!r)return t.status(404).json({error:`Track ${n} isn't on this node`});let o=(await Xn()).filter(a=>a.trackId===r.id&&a.state!=="merged"&&a.state!=="closed"),s=[];for(let a of o){let i=await Mi(a.repo,a.number).catch(()=>null),c=await jo(a.repo).catch(()=>null);c&&await Wm(c,a.number).catch(()=>{}),i&&(await hn("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}))}Kt(),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})}});S.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 oe(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(b=>b.name===m||b.repo===m||b.base===m||b.dir===m);if(!g)throw new Error(`invalid repo "${m}" \u2014 not tagged on this Track`);return g});else if(d=await Ho(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 Km(m.dir,{title:r,body:o,base:s}),b=m.repo||await _e(m.dir).catch(()=>null);b&&g.number&&await Ct({repo:b,number:g.number,trackId:i.id,url:g.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await hn("opened",{number:g.number,url:g.url,title:r,track:i,branch:i.workspace?.branch,extra:{repo:b??m.name}}),f.push({repo:m.name,slug:b??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 Km(i.cwd,{title:r,body:o,base:s}),l=await _e(i.cwd).catch(()=>null);l&&c.number&&await Ct({repo:l,number:c.number,trackId:i.id,url:c.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await hn("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})}});S.get("/api/tracks/:id/repos",async(e,t)=>{try{let n=await oe(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await Ho(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)})}});S.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 Ww(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})}});S.delete("/api/tracks/:id/repos/:name",async(e,t)=>{try{let n=await qw(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})}});S.post("/api/git/prs/fix",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await Xs(n,r),s=await _e(n).catch(()=>null),a=await iO({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(b=>b.base===n||s&&b.repo===s)??null,c=a.workspace?.kind==="multi",l=await DS(n,o.number);if(!l.length)return t.status(409).json({error:"no failing checks on this PR"});let u=c&&i?Te.join("ci",i.name):"ci",d=Te.join(a.cwd,".bostrat",u),p=Te.join(".bostrat",u,`pr-${o.number}-fail.log`);await wt.promises.mkdir(d,{recursive:!0}),await wt.promises.writeFile(Te.join(a.cwd,p),l.map(b=>`\u2550\u2550\u2550\u2550 ${b.name}${b.link?` \xB7 ${b.link}`:""} \u2550\u2550\u2550\u2550
758
+ `)}catch{t.status(204).end()}});S.post("/api/git/committed",async(e,t)=>{try{let n=await xc(e.get(Hn));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?Te.resolve(n.box.cwd):null,s=typeof e.body?.cwd=="string"&&e.body.cwd?Te.resolve(e.body.cwd):null,a=o&&s&&(s===o||s.startsWith(o+Te.sep))?s:o;tT(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)})}});S.post("/api/tracks/:id/rework-cause",async(e,t)=>{try{let n=await oe(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 rT(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})}});S.post("/api/tracks/:id/rework-cause/retract",async(e,t)=>{try{let n=await oe(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,event:await oT(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})}});S.get("/api/usage/rework",async(e,t)=>{try{t.json(await JI(await me(),{window:e.query.window,from:e.query.from,to:e.query.to}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.post("/api/telemetry",async(e,t)=>{try{if(!RR(Ma.clientIp(e)))return t.json({ok:!0,dropped:!0});let n=await $R(e.body||{});t.json({ok:!0,events:n})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});S.get("/api/repos",async(e,t)=>{try{let n=await Wn(),r=new Set((await Promise.all(n.map(a=>_e(a.path)))).filter(Boolean).map(a=>a.toLowerCase())),s=((await qa()).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)})}});S.get("/api/github/token",async(e,t)=>{try{t.json(await dl(String(e.query.repo||"")))}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});S.get("/api/github/status",(e,t)=>{t.json({configured:ul(),calls:bS(),latency:SS(),webhook:eR()})});S.post("/api/github/event",Ut.json({limit:"64kb"}),(e,t)=>{let n=Z$(e.body,{onAccept:r=>wR(r)});if(!n.ok)return t.status(400).json({error:n.error});t.json({ok:!0,duplicate:n.duplicate})});S.post("/api/github/refresh",(e,t)=>{ub(),t.json({ok:!0})});S.get("/api/gmail/search",async(e,t)=>{try{let n=await s$(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)})}});S.get("/api/gmail/messages/:id",async(e,t)=>{try{t.json({message:await a$(String(e.params.id))})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});async function el({repo:e=null,number:t=null,branch:n=null}){let r=e?await _e(e):null;if(r&&t!=null){let s=await at(r,t),a=s&&await oe(s.trackId);if(a)return a}if(!n)return null;let o=await me();return Pu(o,n,s=>Du(s,{branch:n,repo:e,slug:r}))}async function cO({repo:e=null,number:t=null,branch:n=null}){let r=await el({repo:e,number:t,branch:n}).catch(()=>null);if(r&&!Ve(r))return r;if(!n)return null;let o=e?await _e(e).catch(()=>null):null,s=await me();return Pu(s,n,a=>!Ve(a)&&Du(a,{branch:n,repo:e,slug:o}))}async function hn(e,{number:t,url:n=null,title:r=null,branch:o=null,repo:s=null,track:a=null,extra:i={}}){let c=a||await el({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 BK(e){let t=(await me()).filter(n=>!Ve(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 at(r,o.number))continue;let s=await Pu(t,o.headRefName,a=>Du(a,{branch:o.headRefName,repo:n.path,slug:r}));s&&await Ct({repo:r,number:o.number,trackId:s.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"})}}}S.get("/api/git/prs",async(e,t)=>{try{let n=await RS();await BK(n.repos).catch(()=>{}),await ip(n.repos).catch(()=>{}),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.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(!Di.has(x))throw new Error(`invalid merge method: ${x}`);let y=Number(r);if(!Number.isInteger(y)||y<=0)throw new Error("invalid PR number");let $=await _e((await tr(n)).path);if(!$)throw new Error("repo has no GitHub remote");let O=await el({repo:n,number:y,branch:l}).catch(()=>null);if(!O)throw new Error("auto-merge needs a Track to watch this PR \u2014 none owns it");if(a&&await Bi(n,y),await Ct({repo:$,number:y,trackId:O.id,url:d,headRef:l,title:u,source:"matched"}).catch(()=>{}),!await Ci($,y,{merge:{method:x}}))throw new Error("couldn't record the auto-merge arm");return await No($,y,i===!0),await Po($,y,c===!0&&i!==!0),Kt(),await hn("auto-armed",{number:y,url:d,title:u,branch:l,repo:n,track:O,...a?{extra:{updated:!0}}:{}}),t.json({ok:!0,number:y,auto:!0})}p=await el({repo:n,number:r,branch:l}).catch(()=>null),p&&(f=await pw(p,"merge",{count:1,summary:`merging PR #${r}`}));let m=await Zs(n,r,{method:o||"squash"});await hn("merged",{number:m.number,url:d,title:u,branch:l,repo:n});let g=await _e(n).catch(()=>null),b=!1;if(g&&(i===!0&&await No(g,m.number,!0).catch(()=>{}),c===!0&&i!==!0&&await Po(g,m.number,!0).catch(()=>{}),await rr(g,m.number).catch(()=>{}),await Xo(g,m.number).catch(()=>{}),b=await nr(g,m.number).catch(()=>!1),await Hr(g,m.number,"merged").catch(()=>{})),i===!0&&!b){let x=await el({repo:n,number:m.number,branch:l}).catch(()=>null);x&&!x.archivedAt&&await Yo(x.id).catch(()=>{})}t.json(m)}catch(m){w=m;let g=m?.message||String(m),b=/invalid|unknown repo|required|needs a Track|no GitHub remote/i.test(g)?400:502;t.status(b).json({error:g})}finally{p&&f&&await fw(p,f,w?"failed":"completed",w).catch(()=>{})}});S.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 tr(n)).path).catch(()=>null),l=c?await Mi(c,i).catch(()=>null):null;try{await qm(n,i)}catch(u){if(!l)throw u}Kt(),await hn("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})}});S.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 PS(n,{method:r||"merge",onMerged:a=>{hn("merged",{number:a.number,url:a.url,title:a.title,branch:a.headRefName,repo:n}),o&&rr(o,a.number).catch(()=>{}).then(()=>Xo(o,a.number)).catch(()=>{}).then(()=>nr(o,a.number)).catch(()=>{}).then(()=>Hr(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})}});S.get("/api/git/prs/merge-all",(e,t)=>{t.json({jobs:NS()})});S.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(!Di.has(u))throw new Error(`invalid merge method: ${u}`);if(!n)return t.status(400).json({error:"trackId required"});let d=await oe(n);if(!d)return t.status(404).json({error:`Track ${n} isn't on this node`});i=d;let p=(await Xn()).filter(m=>m.trackId===d.id&&m.state!=="merged"&&m.state!=="closed").sort(ji);if(!p.length)return t.status(409).json({error:"no open PRs on this Track"});c=await pw(d,"merge",{count:p.length,summary:p.length===1?"merging 1 PR":`merging ${p.length} PRs`});for(let m of p)await No(m.repo,m.number,o===!0).catch(()=>{}),await Po(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 b=await Bo(m.repo);if(!b)throw new Error(`no local checkout for ${m.repo}`);let x=await Xs(b,m.number);w.push({r:g,l:m,repoPath:b,pr:x,plan:OS(x,{update:r!==!1})})}catch(b){g.ok=!1,g.action="failed",g.reason=b?.message||String(b)}}for(let{r:m,l:g,repoPath:b,pr:x,plan:y}of CS(w))try{if(y.action==="skip")m.action="skipped",m.reason=y.reason;else if(y.action==="merge")await Zs(b,g.number,{method:u}),await hn("merged",{number:g.number,url:x.url,title:x.title,branch:x.headRefName,repo:b,track:d}),await rr(g.repo,g.number).catch(()=>{}),await Xo(g.repo,g.number).catch(()=>{}),await nr(g.repo,g.number).catch(()=>{}),await Hr(g.repo,g.number,"merged").catch(()=>{}),m.action="merged";else{if(y.action==="update-arm"&&(await Bi(b,g.number).catch(()=>{}),m.action="updated-armed"),!await Ci(g.repo,g.number,{merge:{method:u}}))throw new Error("couldn't record the auto-merge arm");await hn("auto-armed",{number:g.number,url:x.url,title:x.title,branch:x.headRefName,repo:b,track:d,...m.action==="updated-armed"?{extra:{updated:!0}}:{}})}}catch($){m.ok=!1,m.action="failed",m.reason=$?.message||String($)}if(Kt(),!f.some(m=>m.ok)){if(o===!0)for(let m of p)await No(m.repo,m.number,!1).catch(()=>{});if(s===!0&&o!==!0)for(let m of p)await Po(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 fw(i,c,l?"failed":"completed",l).catch(()=>{})}});S.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 oe(n);if(!r)return t.status(404).json({error:`Track ${n} isn't on this node`});let o=(await Xn()).filter(a=>a.trackId===r.id&&a.state!=="merged"&&a.state!=="closed"),s=[];for(let a of o){let i=await Mi(a.repo,a.number).catch(()=>null),c=await Bo(a.repo).catch(()=>null);c&&await qm(c,a.number).catch(()=>{}),i&&(await hn("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}))}Kt(),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})}});S.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 oe(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(m=>{let g=u.find(b=>b.name===m||b.repo===m||b.base===m||b.dir===m);if(!g)throw new Error(`invalid repo "${m}" \u2014 not tagged on this Track`);return g});else if(d=await Ho(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 Gm(m.dir,{title:r,body:o,base:s}),b=m.repo||await _e(m.dir).catch(()=>null);b&&g.number&&await Ct({repo:b,number:g.number,trackId:i.id,url:g.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await hn("opened",{number:g.number,url:g.url,title:r,track:i,branch:i.workspace?.branch,extra:{repo:b??m.name}}),f.push({repo:m.name,slug:b??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 Gm(i.cwd,{title:r,body:o,base:s}),l=await _e(i.cwd).catch(()=>null);l&&c.number&&await Ct({repo:l,number:c.number,trackId:i.id,url:c.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await hn("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})}});S.get("/api/tracks/:id/repos",async(e,t)=>{try{let n=await oe(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await Ho(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)})}});S.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 qw(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})}});S.delete("/api/tracks/:id/repos/:name",async(e,t)=>{try{let n=await Kw(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})}});S.post("/api/git/prs/fix",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await Xs(n,r),s=await _e(n).catch(()=>null),a=await cO({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(b=>b.base===n||s&&b.repo===s)??null,c=a.workspace?.kind==="multi",l=await DS(n,o.number);if(!l.length)return t.status(409).json({error:"no failing checks on this PR"});let u=c&&i?Te.join("ci",i.name):"ci",d=Te.join(a.cwd,".bostrat",u),p=Te.join(".bostrat",u,`pr-${o.number}-fail.log`);await wt.promises.mkdir(d,{recursive:!0}),await wt.promises.writeFile(Te.join(a.cwd,p),l.map(b=>`\u2550\u2550\u2550\u2550 ${b.name}${b.link?` \xB7 ${b.link}`:""} \u2550\u2550\u2550\u2550
759
759
  ${b.log??"(no fetchable log \u2014 see link)"}
760
760
  `).join(`
761
- `));let f=l.map(b=>b.name).join(", "),w=c&&i?` in the ${i.name}/ checkout`:"",m=await Dt(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 Ct({repo:g,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await tS(g,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await hn("fix-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{checks:l.map(b=>b.name)}}),t.json({ok:!0,leadBox:m.leadBox,queued:!!m.queued,checks:l.map(b=>b.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})}});S.post("/api/git/prs/reconcile",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await Xs(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 iO({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 Dt(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 Ct({repo:u,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await nS(u,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await hn("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})}});S.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=Fr.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 Jr(`pr:${e.params.id}:${n}`,async()=>{let a=await oe(e.params.id);if(!a)return t.status(404).json({error:"track not found"});let i=await K(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 Ey(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 Dt(a.id,zs(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&&Bw(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})}});S.post("/api/tracks/:id/pr-exists",async(e,t)=>{let{offerId:n,choice:r}=e.body||{};try{let o=await oe(e.params.id);if(!o)return t.status(404).json({error:"track not found"});let{say:s}=await _y(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 nl=e=>t=>({...t,url:y$(t,e.headers)});S.get("/api/views",async(e,t)=>{try{let n=await Lh({trackId:e.query.track||void 0});t.json({views:n.map(nl(e)),maxLive:Xr})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/views/:id",async(e,t)=>{let n=await gA(e.params.id);if(!n)return t.status(404).json({error:"view not found"});t.json({view:nl(e)(n),session:sa(n.slug)})});S.post("/api/views",async(e,t)=>{let{trackId:n,name:r,cmd:o,cwd:s,port:a}=e.body||{};try{let i=n?await oe(n):null;if(!i&&s&&(i=(await me()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Te.sep)))||null),!i)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let c=await Uh({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:nl(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})}});S.post("/api/views/:id/stop",async(e,t)=>{try{t.json({ok:!0,view:nl(e)(await yA(e.params.id))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});S.post("/api/views/:id/restart",async(e,t)=>{try{t.json({ok:!0,view:nl(e)(await bA(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})}});S.delete("/api/views/:id",async(e,t)=>{try{t.json(await kA(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});var jK=[["linear",es,$g],["jira",Fd,_g]],Py=new Map;S.get("/api/integrations/ticketing",async(e,t)=>{try{let n=await Eg(),r={};for(let[o,s,a]of jK){let i=await s();if(!i){Py.delete(o),r[o]={configured:!1};continue}let c=Py.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},Py.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)})}});S.get("/api/tickets/flow",async(e,t)=>{try{t.json({flow:await Eg()})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.post("/api/tickets/flow",async(e,t)=>{let{trackId:n,cwd:r,set:o,actor:s}=e.body||{};try{let a=await X_(o),i=n?await oe(n):null;!i&&r&&(i=(await me()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+Te.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 ls=async(e,t)=>{let n=e?await oe(e):null;return!n&&t&&(n=(await me()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+Te.sep)))||null),n};S.get("/api/circuits",async(e,t)=>{try{t.json({circuits:await kg()})}catch(n){t.status(502).json({error:n?.message||String(n)})}});S.get("/api/roadmap",async(e,t)=>{try{t.json(await xg())}catch(n){t.status(502).json({error:n?.message||String(n)})}});S.post("/api/circuits/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=await ls(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 va(o);await Dd(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})}});S.post("/api/circuits/unlink",async(e,t)=>{let{trackId:n,cwd:r}=e.body||{};try{let o=await ls(n,r);if(!o)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});await Dd(o,null,{source:"chat"}),t.json({ok:!0,trackId:o.id})}catch(o){t.status(502).json({error:o?.message||String(o)})}});var cO=async(e,t,n)=>{if(e)return{ref:e,track:await ls(t,n)};let r=await ls(t,n),o=r?await Sg(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}};S.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 cO(o,n,r),l=await W_({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})}});S.get("/api/blueprints/show",async(e,t)=>{try{let{ref:n}=await cO(e.query.circuit,e.query.track,e.query.cwd);t.json(await vg(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})}});S.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 ls(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})}});S.get("/api/decisions",async(e,t)=>{try{let n=await ls(e.query.track,e.query.cwd);if(!n)return t.status(400).json({error:"run from inside a Track workspace"});t.json(await z_(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})}});S.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 ls(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=await Sg(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 q_(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})}});S.post("/api/tickets/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=n?await oe(n):null;if(!s&&r&&(s=(await me()).find(c=>c.cwd&&(r===c.cwd||r.startsWith(c.cwd+Te.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 Aa(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})}});S.get("/api/tickets/status",async(e,t)=>{let{cwd:n,track:r}=e.query;try{let o=r?await oe(r):null;if(!o&&n&&(o=(await me()).find(a=>a.cwd&&(n===a.cwd||String(n).startsWith(a.cwd+Te.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 fI(),ticket:await Fn(o.id)})}catch(o){t.status(500).json({error:o?.message||String(o)})}});S.get("/api/tracks/:id/ticket",async(e,t)=>{t.json({ticket:await Fn(e.params.id)})});S.post("/api/tracks/:id/ticket",async(e,t)=>{try{let n=await oe(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await Aa(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})}});S.delete("/api/tracks/:id/ticket",async(e,t)=>{t.json({ok:!0,removed:await Ug(e.params.id)})});var bp=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;S.get("/api/tracks/:id/ticket/states",async(e,t)=>{try{t.json(await gI(e.params.id))}catch(n){let r=n?.message||String(n);t.status(bp(r)).json({error:r})}});S.post("/api/tracks/:id/ticket/state",async(e,t)=>{try{t.json({ok:!0,...await Hg(e.params.id,(e.body||{}).stateId)})}catch(n){let r=n?.message||String(n);t.status(bp(r)).json({error:r})}});S.post("/api/tracks/:id/ticket/comment",async(e,t)=>{try{t.json({ok:!0,...await yI(e.params.id,(e.body||{}).body)})}catch(n){let r=n?.message||String(n);t.status(bp(r)).json({error:r})}});S.post("/api/tracks/:id/ticket-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{let o=await oe(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await bI(o,n,r===!0)})}catch(o){let s=o?.message||String(o);t.status(bp(s)).json({error:s})}});S.post("/api/tracks/:id/fullscreen-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{t.json(await eg(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})}});S.post("/api/tickets/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await oe(n):null;if(!s&&r&&(s=(await me()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+Te.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 xI(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})}});S.get("/api/tickets/teams",async(e,t)=>{try{t.json({teams:await kI()})}catch(n){let r=n?.message||String(n);t.status(/no ticketing/i.test(r)?400:502).json({error:r})}});S.post("/api/tracks/:id/ticket-create-offer",async(e,t)=>{let{proposalId:n,accept:r,teamId:o}=e.body||{};try{let s=await oe(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await vI(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})}});S.get("/api/mocks",async(e,t)=>{try{t.json({mocks:await ac({trackId:e.query.track||void 0,group:e.query.group||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/mocks/:id",async(e,t)=>{let n=await cr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});t.json({mock:n})});var rl={dotfiles:"allow"};S.get("/api/mocks/:id/png",async(e,t)=>{let n=await cr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=an(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,rl,s=>{s&&!t.headersSent&&t.status(404).json({error:"rendered artifact missing"})})});S.get("/api/mocks/:id/media",async(e,t)=>{let n=await cr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=an(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,rl,s=>{s&&!t.headersSent&&t.status(404).json({error:"video artifact missing"})})});S.get("/api/mocks/:id/html",async(e,t)=>{let n=await cr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=an(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(zt(n,r.v).html,rl,o=>{o&&!t.headersSent&&t.status(404).json({error:"source artifact missing"})})});S.post("/api/mocks",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&sd(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 oe(a):null;if(!d&&c&&(d=(await me()).find(m=>m.cwd&&(c===m.cwd||c.startsWith(m.cwd+Te.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 DA({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})}});S.post("/api/mocks/:id/update",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&sd(n)?n:null;try{let o=await jA(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})}});S.post("/api/mocks/:id/pick",async(e,t)=>{try{let{mock:n,siblings:r}=await FA(e.params.id),o=r.length?` over ${r.map(s=>`"${s.name}"`).join(", ")}`:"";await Dt(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})}});S.delete("/api/mocks/:id",async(e,t)=>{try{let n=(await oE(e.params.id)).map(r=>({id:r.id,name:r.name}));t.json({...await UA(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})}});S.get("/api/flows",async(e,t)=>{try{t.json({flows:await QA({trackId:e.query.track||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/flows/:id",async(e,t)=>{let n=await eE(e.params.id);if(!n)return t.status(404).json({error:"flow not found"});t.json({flow:n})});S.post("/api/flows",async(e,t)=>{let{trackId:n,name:r,steps:o,cwd:s}=e.body||{};try{let a=n?await oe(n):null;if(!a&&s&&(a=(await me()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Te.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 tE({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})}});S.post("/api/flows/:id/update",async(e,t)=>{try{let{steps:n,note:r}=e.body||{};t.json({ok:!0,flow:await nE(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})}});S.delete("/api/flows/:id",async(e,t)=>{try{t.json(await rE(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});S.get("/api/runbooks",async(e,t)=>{try{let n=e.query.track||void 0;if(!n&&e.query.cwd){let s=await me(),a=String(e.query.cwd);if(n=s.find(i=>i.cwd&&(a===i.cwd||a.startsWith(i.cwd+Te.sep)))?.id,!n)return t.json({runbooks:[]})}let{runbooks:r,fleetDegraded:o}=await pE({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)})}});S.get("/api/runbooks/:id",async(e,t)=>{let n=await ew(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});t.json({runbook:n})});S.get("/api/runbooks/:id/md",async(e,t)=>{let n=await ew(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});let r=uE(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 fE(n,r.v);return typeof o!="string"?t.status(404).json({error:"runbook artifact missing"}):t.send(o)}t.sendFile(pr(n,r.v),rl,o=>{o&&!t.headersSent&&t.status(404).json({error:"runbook artifact missing"})})});S.get("/api/loops",async(e,t)=>{t.json(await Wi())});S.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 me()).find(u=>u.cwd&&(o===u.cwd||o.startsWith(u.cwd+Te.sep)))||null;if(!a)return t.status(400).json({error:"cwd is not inside a Track workspace"});let i=await Wi();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 uh({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})});S.post("/api/loops/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await oe(n):null;if(!s&&r&&(s=(await me()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+Te.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 A$(s,o)})}catch(s){t.status(400).json({error:s?.message||String(s)})}});var Pa=async(e,t)=>{let n=e?await oe(e):null;return!n&&t&&(n=(await me()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+Te.sep)))||null),n};S.post("/api/followups/offer",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await Pa(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 OT(s,o,{ship:{changedRepos:Ho}})})}catch(s){t.status(400).json({error:s?.message||String(s)})}});S.post("/api/followups/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await Pa(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 MT(s,o)})}catch(s){let a=s?.message||String(s);t.status(/unreachable/i.test(a)?503:400).json({error:a})}});S.get("/api/followups",async(e,t)=>{let n=typeof e.query?.cwd=="string"?e.query.cwd:null,r=await Pa(null,n).catch(()=>null);t.json({ok:!0,trackId:r?.id??null,triggers:wh,...await BT(r)})});var JR=new Set(["reconcile","fixing-ci","rebase","merge"]);S.get("/api/status",async(e,t)=>{let n=await Pa(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})});S.post("/api/status",async(e,t)=>{try{let{trackId:n,cwd:r,phase:o,summary:s,scope:a,reason:i}=e.body||{},c=await Pa(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&&!JR.has(l))throw new Error(`phase must be one of ${[...JR].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=RK();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)})}});S.post("/api/tracks/:id/followup-offer",async(e,t)=>{let{offerId:n,followupId:r,armId:o,promoted:s}=e.body||{};try{let a=await oe(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await PT(a,{offerId:n,followupId:r||null,armId:o||null,promoted:s||null},{sayToLead:Dt,unarchiveTrack:Td})})}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})}});S.post("/api/tracks/:id/followup-arm-cancel",async(e,t)=>{try{let n=await oe(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await CT(n,e.body?.armId)})}catch(n){let r=n?.message||String(n);t.status(/unknown/i.test(r)?404:400).json({error:r})}});S.post("/api/tracks/:id/followup-create-offer",async(e,t)=>{let{proposalId:n,accept:r,followupId:o}=e.body||{};try{let s=await oe(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await NT(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})}});ot.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"||oe(e.trackId).then(async s=>{if(s&&(n&&await Gi(s,n,o),t==="opened"||t==="pushed")){let a=jT(await K(s).catch(()=>[]));a&&await Gi(s,"ship.done",{...o,shipOfferId:a})}}).catch(()=>{})});var lO=async(e,t,{trackId:n,cwd:r,loop:o})=>{let s=n?await oe(n):null;if(!s&&r&&(s=(await me()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+Te.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"}),null;let a=await Wi();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=I$(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}};S.post("/api/loops/propose-update",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await lO(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await $$(s.track,s.loop,e.body?.patch)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});S.post("/api/loops/propose-delete",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await lO(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await R$(s.track,s.loop,e.body?.reason)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});S.post("/api/planning/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o,scope:s}=e.body||{},a=await Pa(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i;try{i=await xg()}catch(c){return t.status(503).json({error:c?.message||String(c)})}try{let c=s==="circuit"?fy:zc;t.json({ok:!0,trackId:a.id,proposal:await U$(a,o,i,{allow:c})})}catch(c){t.status(400).json({error:c?.message||String(c)})}});var Hy=e=>/unknown proposal/i.test(e)?404:/already answered/i.test(e)?409:400;S.post("/api/tracks/:id/planning-offer",async(e,t)=>{let{proposalId:n,action:r,results:o}=e.body||{};try{let s=await oe(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await H$(s,n,r,{results:o||[]})})}catch(s){let a=s?.message||String(s);t.status(Hy(a)).json({error:a})}});S.post("/api/tracks/:id/loop-update-offer",async(e,t)=>{let{proposalId:n,action:r,nextFireAt:o}=e.body||{};try{let s=await oe(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await C$(s,n,r,{nextFireAt:o??null})})}catch(s){let a=s?.message||String(s);t.status(Hy(a)).json({error:a})}});S.post("/api/tracks/:id/loop-delete-offer",async(e,t)=>{let{proposalId:n,action:r}=e.body||{};try{let o=await oe(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await M$(o,n,r)})}catch(o){let s=o?.message||String(o);t.status(Hy(s)).json({error:s})}});S.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 oe(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await E$(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})}});S.post("/api/runbooks",async(e,t)=>{let{trackId:n,name:r,md:o,cwd:s}=e.body||{};try{let a=n?await oe(n):null;if(!a&&s&&(a=(await me()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Te.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 mE({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})}});S.post("/api/runbooks/:id/update",async(e,t)=>{try{let{md:n,note:r}=e.body||{};t.json({ok:!0,runbook:await hE(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})}});S.post("/api/runbooks/:id/status",async(e,t)=>{try{t.json({ok:!0,runbook:await wE(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})}});S.delete("/api/runbooks/:id",async(e,t)=>{try{t.json(await gE(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});S.get("/api/changelog/draft",async(e,t)=>{try{let n=z$(e.query.since||null);t.json({since:n,repos:hy(),...await V$(n)})}catch(n){let r=n?.message||String(n);t.status(/unparseable/i.test(r)?400:500).json({error:r})}});var uO=async({trackId:e,cwd:t})=>{let n=e?await oe(e):null;return!n&&t&&(n=(await me()).find(o=>o.cwd&&(t===o.cwd||String(t).startsWith(o.cwd+Te.sep)))||null),n};S.post("/api/changelog/publish",async(e,t)=>{let{md:n,day:r,trackId:o,cwd:s}=e.body||{};try{let a=await uO({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 J$(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})}});S.post("/api/changelog/retract",async(e,t)=>{let{day:n,trackId:r,cwd:o}=e.body||{};try{let s=await uO({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 Y$(s,{day:n})})}catch(s){let a=s?.message||String(s);t.status(/required|invalid/i.test(a)?400:500).json({error:a})}});var BK=120,Dy=400,Na=null,YR=null;S.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>Dy)return t.status(400).json({error:`message is ${i.length} chars \u2014 over the ${Dy} cap; a notification is a nudge, put the detail in chat`});let c=ic(`${n||""}
762
- ${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 oe(a):null;if(!l&&s&&(l=(await me()).find(w=>w.cwd&&(s===w.cwd||s.startsWith(w.cwd+Te.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,BK):l.name,body:d(i,Dy),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:Na?Na.status().connected:null})}catch(i){t.status(500).json({error:i?.message||String(i)})}});S.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 WR(e.body,e.headers["content-type"]))}catch(n){t.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});S.get("/api/dictation/glossary",async(e,t)=>{t.json({configured:!!await Cc(),terms:await My(),problem:await HR()})});S.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 UR(n,r)})});S.get("/api/tracks/:id/voice-chat",async(e,t)=>{if(!await oe(e.params.id))return t.status(404).json({error:"track not found"});t.json(await qR())});S.post("/api/tracks/:id/voice-chat/session",async(e,t)=>{try{let n=await oe(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 KR())}catch(n){t.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});S.post("/api/tracks/:id/voice-chat/usage",async(e,t)=>{try{let n=await oe(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 GR(n,{model:r,usage:o,seconds:s})})}catch(n){t.status(n?.status||500).json({error:n?.message||String(n)})}});S.post("/api/tracks",async(e,t)=>{let{name:n,cwd:r,repo:o,repos:s,agent:a,skipPermissions:i,ticket:c,circuit:l}=e.body||{};try{let u=await vd({name:n,cwd:r,repo:o,repos:s,agent:a,skipPermissions:i!==!1}),d=null;if(c)try{await Aa(u,c,{source:"create"})}catch(f){d=f?.message||String(f)}let p=null;if(l)try{await Dd(u,await va(l),{source:"picker"})}catch(f){p=f?.message||String(f)}t.json({ok:!0,track:u,...d?{ticketWarning:d}:{},...p?{circuitWarning:p}:{}})}catch(u){let d=u?.message||String(u);t.status(/required|unknown agent|invalid|must be/i.test(d)?400:500).json({error:d})}});S.get("/api/tracks/:id",async(e,t)=>{let n=await oe(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({track:n,handoff:dO(xa(e.params.id)),subtasks:Zo(e.params.id).map(ol),pendingOffers:await Cw(n)})});S.delete("/api/tracks/:id",async(e,t)=>{try{let n=await Vw(e.params.id,{cascadeMocks:e.query.mocks!=="0",cascadeRunbooks:e.query.runbooks==="1"});await Ug(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})}});S.post("/api/tracks/:id/archive",async(e,t)=>{try{t.json({ok:!0,track:await Yo(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})}});S.post("/api/tracks/:id/rename",async(e,t)=>{try{t.json({ok:!0,track:await Xw(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})}});S.post("/api/tracks/:id/unarchive",async(e,t)=>{try{t.json({ok:!0,track:await Td(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})}});S.get("/api/tracks/:id/messages",async(e,t)=>{let n=await yd(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json(n)});S.get("/api/tracks/:id/events",async(e,t)=>{let n=await oe(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}
761
+ `));let f=l.map(b=>b.name).join(", "),w=c&&i?` in the ${i.name}/ checkout`:"",m=await Dt(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 Ct({repo:g,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await tS(g,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await hn("fix-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{checks:l.map(b=>b.name)}}),t.json({ok:!0,leadBox:m.leadBox,queued:!!m.queued,checks:l.map(b=>b.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})}});S.post("/api/git/prs/reconcile",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await Xs(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 cO({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 Dt(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 Ct({repo:u,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await nS(u,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await hn("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})}});S.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=Fr.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 Jr(`pr:${e.params.id}:${n}`,async()=>{let a=await oe(e.params.id);if(!a)return t.status(404).json({error:"track not found"});let i=await K(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 _y(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 Dt(a.id,zs(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&&Lw(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})}});S.post("/api/tracks/:id/pr-exists",async(e,t)=>{let{offerId:n,choice:r}=e.body||{};try{let o=await oe(e.params.id);if(!o)return t.status(404).json({error:"track not found"});let{say:s}=await Iy(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 nl=e=>t=>({...t,url:b$(t,e.headers)});S.get("/api/views",async(e,t)=>{try{let n=await Fh({trackId:e.query.track||void 0});t.json({views:n.map(nl(e)),maxLive:Xr})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/views/:id",async(e,t)=>{let n=await yA(e.params.id);if(!n)return t.status(404).json({error:"view not found"});t.json({view:nl(e)(n),session:sa(n.slug)})});S.post("/api/views",async(e,t)=>{let{trackId:n,name:r,cmd:o,cwd:s,port:a}=e.body||{};try{let i=n?await oe(n):null;if(!i&&s&&(i=(await me()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Te.sep)))||null),!i)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let c=await Hh({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:nl(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})}});S.post("/api/views/:id/stop",async(e,t)=>{try{t.json({ok:!0,view:nl(e)(await bA(e.params.id))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});S.post("/api/views/:id/restart",async(e,t)=>{try{t.json({ok:!0,view:nl(e)(await kA(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})}});S.delete("/api/views/:id",async(e,t)=>{try{t.json(await xA(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});var jK=[["linear",es,Rg],["jira",Ud,Ig]],Dy=new Map;S.get("/api/integrations/ticketing",async(e,t)=>{try{let n=await _g(),r={};for(let[o,s,a]of jK){let i=await s();if(!i){Dy.delete(o),r[o]={configured:!1};continue}let c=Dy.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},Dy.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)})}});S.get("/api/tickets/flow",async(e,t)=>{try{t.json({flow:await _g()})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.post("/api/tickets/flow",async(e,t)=>{let{trackId:n,cwd:r,set:o,actor:s}=e.body||{};try{let a=await Z_(o),i=n?await oe(n):null;!i&&r&&(i=(await me()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+Te.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 ls=async(e,t)=>{let n=e?await oe(e):null;return!n&&t&&(n=(await me()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+Te.sep)))||null),n};S.get("/api/circuits",async(e,t)=>{try{t.json({circuits:await xg()})}catch(n){t.status(502).json({error:n?.message||String(n)})}});S.get("/api/roadmap",async(e,t)=>{try{t.json(await vg())}catch(n){t.status(502).json({error:n?.message||String(n)})}});S.post("/api/circuits/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=await ls(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 va(o);await Bd(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})}});S.post("/api/circuits/unlink",async(e,t)=>{let{trackId:n,cwd:r}=e.body||{};try{let o=await ls(n,r);if(!o)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});await Bd(o,null,{source:"chat"}),t.json({ok:!0,trackId:o.id})}catch(o){t.status(502).json({error:o?.message||String(o)})}});var lO=async(e,t,n)=>{if(e)return{ref:e,track:await ls(t,n)};let r=await ls(t,n),o=r?await Tg(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}};S.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 lO(o,n,r),l=await q_({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})}});S.get("/api/blueprints/show",async(e,t)=>{try{let{ref:n}=await lO(e.query.circuit,e.query.track,e.query.cwd);t.json(await Sg(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})}});S.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 ls(n,r);if(!u)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let d=await z_(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})}});S.get("/api/decisions",async(e,t)=>{try{let n=await ls(e.query.track,e.query.cwd);if(!n)return t.status(400).json({error:"run from inside a Track workspace"});t.json(await V_(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})}});S.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 ls(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=await Tg(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 K_(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})}});S.post("/api/tickets/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=n?await oe(n):null;if(!s&&r&&(s=(await me()).find(c=>c.cwd&&(r===c.cwd||r.startsWith(c.cwd+Te.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 Aa(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})}});S.get("/api/tickets/status",async(e,t)=>{let{cwd:n,track:r}=e.query;try{let o=r?await oe(r):null;if(!o&&n&&(o=(await me()).find(a=>a.cwd&&(n===a.cwd||String(n).startsWith(a.cwd+Te.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 mI(),ticket:await Fn(o.id)})}catch(o){t.status(500).json({error:o?.message||String(o)})}});S.get("/api/tracks/:id/ticket",async(e,t)=>{t.json({ticket:await Fn(e.params.id)})});S.post("/api/tracks/:id/ticket",async(e,t)=>{try{let n=await oe(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await Aa(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})}});S.delete("/api/tracks/:id/ticket",async(e,t)=>{t.json({ok:!0,removed:await Hg(e.params.id)})});var kp=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;S.get("/api/tracks/:id/ticket/states",async(e,t)=>{try{t.json(await yI(e.params.id))}catch(n){let r=n?.message||String(n);t.status(kp(r)).json({error:r})}});S.post("/api/tracks/:id/ticket/state",async(e,t)=>{try{t.json({ok:!0,...await Wg(e.params.id,(e.body||{}).stateId)})}catch(n){let r=n?.message||String(n);t.status(kp(r)).json({error:r})}});S.post("/api/tracks/:id/ticket/comment",async(e,t)=>{try{t.json({ok:!0,...await bI(e.params.id,(e.body||{}).body)})}catch(n){let r=n?.message||String(n);t.status(kp(r)).json({error:r})}});S.post("/api/tracks/:id/ticket-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{let o=await oe(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await kI(o,n,r===!0)})}catch(o){let s=o?.message||String(o);t.status(kp(s)).json({error:s})}});S.post("/api/tracks/:id/fullscreen-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{t.json(await tg(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})}});S.post("/api/tickets/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await oe(n):null;if(!s&&r&&(s=(await me()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+Te.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 vI(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})}});S.get("/api/tickets/teams",async(e,t)=>{try{t.json({teams:await xI()})}catch(n){let r=n?.message||String(n);t.status(/no ticketing/i.test(r)?400:502).json({error:r})}});S.post("/api/tracks/:id/ticket-create-offer",async(e,t)=>{let{proposalId:n,accept:r,teamId:o}=e.body||{};try{let s=await oe(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await SI(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})}});S.get("/api/mocks",async(e,t)=>{try{t.json({mocks:await ac({trackId:e.query.track||void 0,group:e.query.group||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/mocks/:id",async(e,t)=>{let n=await cr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});t.json({mock:n})});var rl={dotfiles:"allow"};S.get("/api/mocks/:id/png",async(e,t)=>{let n=await cr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=an(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,rl,s=>{s&&!t.headersSent&&t.status(404).json({error:"rendered artifact missing"})})});S.get("/api/mocks/:id/media",async(e,t)=>{let n=await cr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=an(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,rl,s=>{s&&!t.headersSent&&t.status(404).json({error:"video artifact missing"})})});S.get("/api/mocks/:id/html",async(e,t)=>{let n=await cr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=an(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(zt(n,r.v).html,rl,o=>{o&&!t.headersSent&&t.status(404).json({error:"source artifact missing"})})});S.post("/api/mocks",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&ad(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 oe(a):null;if(!d&&c&&(d=(await me()).find(m=>m.cwd&&(c===m.cwd||c.startsWith(m.cwd+Te.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 BA({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})}});S.post("/api/mocks/:id/update",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&ad(n)?n:null;try{let o=await jA(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})}});S.post("/api/mocks/:id/pick",async(e,t)=>{try{let{mock:n,siblings:r}=await UA(e.params.id),o=r.length?` over ${r.map(s=>`"${s.name}"`).join(", ")}`:"";await Dt(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})}});S.delete("/api/mocks/:id",async(e,t)=>{try{let n=(await sE(e.params.id)).map(r=>({id:r.id,name:r.name}));t.json({...await HA(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})}});S.get("/api/flows",async(e,t)=>{try{t.json({flows:await eE({trackId:e.query.track||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/flows/:id",async(e,t)=>{let n=await tE(e.params.id);if(!n)return t.status(404).json({error:"flow not found"});t.json({flow:n})});S.post("/api/flows",async(e,t)=>{let{trackId:n,name:r,steps:o,cwd:s}=e.body||{};try{let a=n?await oe(n):null;if(!a&&s&&(a=(await me()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Te.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 nE({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})}});S.post("/api/flows/:id/update",async(e,t)=>{try{let{steps:n,note:r}=e.body||{};t.json({ok:!0,flow:await rE(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})}});S.delete("/api/flows/:id",async(e,t)=>{try{t.json(await oE(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});S.get("/api/runbooks",async(e,t)=>{try{let n=e.query.track||void 0;if(!n&&e.query.cwd){let s=await me(),a=String(e.query.cwd);if(n=s.find(i=>i.cwd&&(a===i.cwd||a.startsWith(i.cwd+Te.sep)))?.id,!n)return t.json({runbooks:[]})}let{runbooks:r,fleetDegraded:o}=await fE({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)})}});S.get("/api/runbooks/:id",async(e,t)=>{let n=await tw(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});t.json({runbook:n})});S.get("/api/runbooks/:id/md",async(e,t)=>{let n=await tw(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});let r=dE(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 mE(n,r.v);return typeof o!="string"?t.status(404).json({error:"runbook artifact missing"}):t.send(o)}t.sendFile(pr(n,r.v),rl,o=>{o&&!t.headersSent&&t.status(404).json({error:"runbook artifact missing"})})});S.get("/api/loops",async(e,t)=>{t.json(await Wi())});S.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 me()).find(u=>u.cwd&&(o===u.cwd||o.startsWith(u.cwd+Te.sep)))||null;if(!a)return t.status(400).json({error:"cwd is not inside a Track workspace"});let i=await Wi();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 dh({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})});S.post("/api/loops/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await oe(n):null;if(!s&&r&&(s=(await me()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+Te.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 E$(s,o)})}catch(s){t.status(400).json({error:s?.message||String(s)})}});var Pa=async(e,t)=>{let n=e?await oe(e):null;return!n&&t&&(n=(await me()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+Te.sep)))||null),n};S.post("/api/followups/offer",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await Pa(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 CT(s,o,{ship:{changedRepos:Ho}})})}catch(s){t.status(400).json({error:s?.message||String(s)})}});S.post("/api/followups/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await Pa(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 NT(s,o)})}catch(s){let a=s?.message||String(s);t.status(/unreachable/i.test(a)?503:400).json({error:a})}});S.get("/api/followups",async(e,t)=>{let n=typeof e.query?.cwd=="string"?e.query.cwd:null,r=await Pa(null,n).catch(()=>null);t.json({ok:!0,trackId:r?.id??null,triggers:gh,...await LT(r)})});var YR=new Set(["reconcile","fixing-ci","rebase","merge"]);S.get("/api/status",async(e,t)=>{let n=await Pa(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})});S.post("/api/status",async(e,t)=>{try{let{trackId:n,cwd:r,phase:o,summary:s,scope:a,reason:i}=e.body||{},c=await Pa(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&&!YR.has(l))throw new Error(`phase must be one of ${[...YR].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=OK();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)})}});S.post("/api/tracks/:id/followup-offer",async(e,t)=>{let{offerId:n,followupId:r,armId:o,promoted:s}=e.body||{};try{let a=await oe(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await DT(a,{offerId:n,followupId:r||null,armId:o||null,promoted:s||null},{sayToLead:Dt,unarchiveTrack:Ad})})}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})}});S.post("/api/tracks/:id/followup-arm-cancel",async(e,t)=>{try{let n=await oe(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await MT(n,e.body?.armId)})}catch(n){let r=n?.message||String(n);t.status(/unknown/i.test(r)?404:400).json({error:r})}});S.post("/api/tracks/:id/followup-create-offer",async(e,t)=>{let{proposalId:n,accept:r,followupId:o}=e.body||{};try{let s=await oe(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await PT(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})}});ot.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"||oe(e.trackId).then(async s=>{if(s&&(n&&await Gi(s,n,o),t==="opened"||t==="pushed")){let a=jT(await K(s).catch(()=>[]));a&&await Gi(s,"ship.done",{...o,shipOfferId:a})}}).catch(()=>{})});var uO=async(e,t,{trackId:n,cwd:r,loop:o})=>{let s=n?await oe(n):null;if(!s&&r&&(s=(await me()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+Te.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"}),null;let a=await Wi();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=$$(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}};S.post("/api/loops/propose-update",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await uO(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await R$(s.track,s.loop,e.body?.patch)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});S.post("/api/loops/propose-delete",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await uO(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await O$(s.track,s.loop,e.body?.reason)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});S.post("/api/planning/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o,scope:s}=e.body||{},a=await Pa(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i;try{i=await vg()}catch(c){return t.status(503).json({error:c?.message||String(c)})}try{let c=s==="circuit"?my:zc;t.json({ok:!0,trackId:a.id,proposal:await H$(a,o,i,{allow:c})})}catch(c){t.status(400).json({error:c?.message||String(c)})}});var Hy=e=>/unknown proposal/i.test(e)?404:/already answered/i.test(e)?409:400;S.post("/api/tracks/:id/planning-offer",async(e,t)=>{let{proposalId:n,action:r,results:o}=e.body||{};try{let s=await oe(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await W$(s,n,r,{results:o||[]})})}catch(s){let a=s?.message||String(s);t.status(Hy(a)).json({error:a})}});S.post("/api/tracks/:id/loop-update-offer",async(e,t)=>{let{proposalId:n,action:r,nextFireAt:o}=e.body||{};try{let s=await oe(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await M$(s,n,r,{nextFireAt:o??null})})}catch(s){let a=s?.message||String(s);t.status(Hy(a)).json({error:a})}});S.post("/api/tracks/:id/loop-delete-offer",async(e,t)=>{let{proposalId:n,action:r}=e.body||{};try{let o=await oe(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await N$(o,n,r)})}catch(o){let s=o?.message||String(o);t.status(Hy(s)).json({error:s})}});S.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 oe(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await _$(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})}});S.post("/api/runbooks",async(e,t)=>{let{trackId:n,name:r,md:o,cwd:s}=e.body||{};try{let a=n?await oe(n):null;if(!a&&s&&(a=(await me()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Te.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 hE({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})}});S.post("/api/runbooks/:id/update",async(e,t)=>{try{let{md:n,note:r}=e.body||{};t.json({ok:!0,runbook:await wE(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})}});S.post("/api/runbooks/:id/status",async(e,t)=>{try{t.json({ok:!0,runbook:await gE(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})}});S.delete("/api/runbooks/:id",async(e,t)=>{try{t.json(await yE(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});S.get("/api/changelog/draft",async(e,t)=>{try{let n=V$(e.query.since||null);t.json({since:n,repos:wy(),...await J$(n)})}catch(n){let r=n?.message||String(n);t.status(/unparseable/i.test(r)?400:500).json({error:r})}});var dO=async({trackId:e,cwd:t})=>{let n=e?await oe(e):null;return!n&&t&&(n=(await me()).find(o=>o.cwd&&(t===o.cwd||String(t).startsWith(o.cwd+Te.sep)))||null),n};S.post("/api/changelog/publish",async(e,t)=>{let{md:n,day:r,trackId:o,cwd:s}=e.body||{};try{let a=await dO({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 Y$(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})}});S.post("/api/changelog/retract",async(e,t)=>{let{day:n,trackId:r,cwd:o}=e.body||{};try{let s=await dO({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 X$(s,{day:n})})}catch(s){let a=s?.message||String(s);t.status(/required|invalid/i.test(a)?400:500).json({error:a})}});var LK=120,By=400,Na=null,XR=null;S.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>By)return t.status(400).json({error:`message is ${i.length} chars \u2014 over the ${By} cap; a notification is a nudge, put the detail in chat`});let c=ic(`${n||""}
762
+ ${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 oe(a):null;if(!l&&s&&(l=(await me()).find(w=>w.cwd&&(s===w.cwd||s.startsWith(w.cwd+Te.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,LK):l.name,body:d(i,By),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:Na?Na.status().connected:null})}catch(i){t.status(500).json({error:i?.message||String(i)})}});S.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 qR(e.body,e.headers["content-type"]))}catch(n){t.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});S.get("/api/dictation/glossary",async(e,t)=>{t.json({configured:!!await Cc(),terms:await Ny(),problem:await WR()})});S.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 HR(n,r)})});S.get("/api/tracks/:id/voice-chat",async(e,t)=>{if(!await oe(e.params.id))return t.status(404).json({error:"track not found"});t.json(await KR())});S.post("/api/tracks/:id/voice-chat/session",async(e,t)=>{try{let n=await oe(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 GR())}catch(n){t.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});S.post("/api/tracks/:id/voice-chat/usage",async(e,t)=>{try{let n=await oe(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 zR(n,{model:r,usage:o,seconds:s})})}catch(n){t.status(n?.status||500).json({error:n?.message||String(n)})}});S.post("/api/tracks",async(e,t)=>{let{name:n,cwd:r,repo:o,repos:s,agent:a,skipPermissions:i,ticket:c,circuit:l}=e.body||{};try{let u=await Sd({name:n,cwd:r,repo:o,repos:s,agent:a,skipPermissions:i!==!1}),d=null;if(c)try{await Aa(u,c,{source:"create"})}catch(f){d=f?.message||String(f)}let p=null;if(l)try{await Bd(u,await va(l),{source:"picker"})}catch(f){p=f?.message||String(f)}t.json({ok:!0,track:u,...d?{ticketWarning:d}:{},...p?{circuitWarning:p}:{}})}catch(u){let d=u?.message||String(u);t.status(/required|unknown agent|invalid|must be/i.test(d)?400:500).json({error:d})}});S.get("/api/tracks/:id",async(e,t)=>{let n=await oe(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({track:n,handoff:pO(xa(e.params.id)),subtasks:Zo(e.params.id).map(ol),pendingOffers:await Mw(n)})});S.delete("/api/tracks/:id",async(e,t)=>{try{let n=await Jw(e.params.id,{cascadeMocks:e.query.mocks!=="0",cascadeRunbooks:e.query.runbooks==="1"});await Hg(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})}});S.post("/api/tracks/:id/archive",async(e,t)=>{try{t.json({ok:!0,track:await Yo(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})}});S.post("/api/tracks/:id/rename",async(e,t)=>{try{t.json({ok:!0,track:await Zw(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})}});S.post("/api/tracks/:id/unarchive",async(e,t)=>{try{t.json({ok:!0,track:await Ad(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})}});S.get("/api/tracks/:id/messages",async(e,t)=>{let n=await bd(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json(n)});S.get("/api/tracks/:id/events",async(e,t)=>{let n=await oe(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}
763
763
  data: ${JSON.stringify(i)}
764
764
 
765
765
  `),o=Number(e.query.since??e.headers["last-event-id"])||0;for(let i of await K(n))i.seq>o&&r(i);let s=kb(n.id,r),a=setInterval(()=>t.write(`: hb
766
766
 
767
- `),25e3);e.on("close",()=>{clearInterval(a),s()})});S.get("/api/tracks/:id/search",async(e,t)=>{let n=await oe(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=vi(await K(n)),a=zl(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}))})});S.get("/api/memory",async(e,t)=>{t.json({stores:await jb(),harvest:Mb()})});S.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 Bb(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 LK=["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(`
768
- `);S.post("/api/tracks/:id/memory/consolidate",async(e,t)=>{try{t.json({ok:!0,...await Dt(e.params.id,LK)})}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})}});S.post("/api/tracks/:id/lead/restart",async(e,t)=>{try{t.json({ok:!0,track:await Ad(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}:{}})}});S.post("/api/tracks/:id/say",async(e,t)=>{let{text:n,attachments:r,producer:o}=e.body||{};try{t.json(await Dt(e.params.id,n,{attachments:r,producer:typeof o=="string"?o:null}))}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})}});S.post("/api/tracks/:id/upload",async(e,t)=>{try{let n=await oe(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 SE(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})}});S.get("/api/tracks/:id/uploads/:file",async(e,t)=>{try{let n=await oe(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=Te.basename(String(e.params.file||""));if(!r||!rw(Te.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=nw(n.cwd),s,a;try{s=await wt.promises.realpath(o),a=await wt.promises.realpath(Te.join(o,r))}catch{return t.status(404).json({error:"upload not found"})}if(!a.startsWith(s+Te.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 FK=/^[0-9a-fA-F-]{8,64}$/;S.get("/api/tracks/:id/chat-images/:box/:uuid/:idx",async(e,t)=>{try{let n=await oe(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(!FK.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=tn(a.cwd,a.sessionId);if(!i)return t.status(404).json({error:"transcript not found"});let c=`"${o}"`,l=null,u=EK.createInterface({input:wt.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?wf(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)})}});S.post("/api/tracks/:id/interrupt",async(e,t)=>{try{t.json(await xd(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})}});S.delete("/api/tracks/:id/queue",async(e,t)=>{try{let{removed:n,restored:r,draftRev:o}=await Dw(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)})}});S.post("/api/tracks/:id/answer-prompt",async(e,t)=>{let{promptId:n,answers:r,text:o}=e.body||{};try{t.json(await bd(e.params.id,{promptId:n,answers:r,text:o}))}catch(s){let a=s?.message||String(s),i=/not found/i.test(a)?404:/no pending prompt|changed since|not running|not supported|needs a code|look like a sign-in code|no answer selected/i.test(a)?409:500;t.status(i).json({error:a})}});S.post("/api/setup/:provider/start",async(e,t)=>{try{let n=await Gw({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})}});S.post("/api/tracks/:id/navigate-prompt",async(e,t)=>{let{promptId:n,questionIndex:r}=e.body||{};try{t.json(await Nw(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})}});S.put("/api/tracks/:id/draft",async(e,t)=>{let{text:n,rev:r}=e.body||{};try{t.json(await Uw(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})}});S.get("/api/tracks/:id/usage",async(e,t)=>{let n=await oe(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 Qd(r,{fresh:o}))});S.post("/api/tracks/:id/model",async(e,t)=>{let{model:n}=e.body||{};try{t.json(await Hw(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})}});S.post("/api/tracks/:id/subtask",async(e,t)=>{let{agent:n,task:r,skipPermissions:o,reason:s}=e.body||{};try{let a=await ug(e.params.id,{agent:n,task:r,skipPermissions:o!==!1,reason:s});t.json({ok:!0,subtask:ol(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})}});S.get("/api/tracks/:id/subtasks",(e,t)=>{t.json({subtasks:Zo(e.params.id).map(ol)})});S.get("/api/tracks/:id/subtask/:sid/messages",async(e,t)=>{let n=await Mw(e.params.id,e.params.sid);if(!n)return t.status(404).json({error:"subtask not found"});t.json(n)});S.post("/api/tracks/:id/subtask/:sid/cancel",(e,t)=>{try{t.json({ok:!0,subtask:ol($d(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});S.post("/api/tracks/:id/subtask/:sid/merge-now",(e,t)=>{try{t.json({ok:!0,subtask:ol(dg(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});function ol(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}S.post("/api/tracks/:id/handoff-lead",async(e,t)=>{let{toAgent:n,skipPermissions:r,reason:o}=e.body||{};try{let s=await Ed(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})}});S.post("/api/tracks/:id/spin-up-view",async(e,t)=>{try{t.json(await Lw(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})}});S.get("/api/tracks/:id/handoff-lead",(e,t)=>{t.json(dO(xa(e.params.id))??{running:!1})});S.post("/api/tracks/:id/transfer-out",async(e,t)=>{try{let n=await og(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})}});S.get("/api/tracks/:id/transfer-out",(e,t)=>{let n=rg(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??{}})});S.post("/api/tracks/:id/transfer-out/commit",async(e,t)=>{try{t.json(await _d(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})}});S.post("/api/tracks/adopt",async(e,t)=>{let{trackId:n}=e.body||{};try{t.json(await ig({...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 dO(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}S.get("/api/debug/handoff",async(e,t)=>{let n=Math.min(Number(e.query.limit)||80,500);t.json({verbose:_l(),paths:Qb,trace:await Zb({limit:n})})});var jy=Te.resolve(eO,"..","..","client","dist");wt.existsSync(jy)&&(S.use(Ut.static(jy)),S.get(/^(?!\/api\/).*/,(e,t)=>t.sendFile(Te.join(jy,"index.html"),rl)));var pO=IK.createServer(S),UK=new OK({noServer:!0}),fO=(e,t,n)=>{if(!(Gc(e)||Ma.allowed(Ma.clientIp(e))||Ly.allows(e))){t.write(`HTTP/1.1 403 Forbidden\r
767
+ `),25e3);e.on("close",()=>{clearInterval(a),s()})});S.get("/api/tracks/:id/search",async(e,t)=>{let n=await oe(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=vi(await K(n)),a=zl(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}))})});S.get("/api/memory",async(e,t)=>{t.json({stores:await Bb(),harvest:Mb()})});S.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 jb(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 FK=["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(`
768
+ `);S.post("/api/tracks/:id/memory/consolidate",async(e,t)=>{try{t.json({ok:!0,...await Dt(e.params.id,FK)})}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})}});S.post("/api/tracks/:id/lead/restart",async(e,t)=>{try{t.json({ok:!0,track:await Ed(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}:{}})}});S.post("/api/tracks/:id/say",async(e,t)=>{let{text:n,attachments:r,producer:o}=e.body||{};try{t.json(await Dt(e.params.id,n,{attachments:r,producer:typeof o=="string"?o:null}))}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})}});S.post("/api/tracks/:id/upload",async(e,t)=>{try{let n=await oe(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 TE(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})}});S.get("/api/tracks/:id/uploads/:file",async(e,t)=>{try{let n=await oe(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=Te.basename(String(e.params.file||""));if(!r||!ow(Te.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=rw(n.cwd),s,a;try{s=await wt.promises.realpath(o),a=await wt.promises.realpath(Te.join(o,r))}catch{return t.status(404).json({error:"upload not found"})}if(!a.startsWith(s+Te.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 UK=/^[0-9a-fA-F-]{8,64}$/;S.get("/api/tracks/:id/chat-images/:box/:uuid/:idx",async(e,t)=>{try{let n=await oe(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(!UK.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=tn(a.cwd,a.sessionId);if(!i)return t.status(404).json({error:"transcript not found"});let c=`"${o}"`,l=null,u=_K.createInterface({input:wt.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?gf(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)})}});S.post("/api/tracks/:id/interrupt",async(e,t)=>{try{t.json(await vd(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})}});S.delete("/api/tracks/:id/queue",async(e,t)=>{try{let{removed:n,restored:r,draftRev:o}=await Bw(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)})}});S.post("/api/tracks/:id/answer-prompt",async(e,t)=>{let{promptId:n,answers:r,text:o}=e.body||{};try{t.json(await kd(e.params.id,{promptId:n,answers:r,text:o}))}catch(s){let a=s?.message||String(s),i=/not found/i.test(a)?404:/no pending prompt|changed since|not running|not supported|needs a code|look like a sign-in code|no answer selected/i.test(a)?409:500;t.status(i).json({error:a})}});S.post("/api/setup/:provider/start",async(e,t)=>{try{let n=await zw({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})}});S.post("/api/tracks/:id/navigate-prompt",async(e,t)=>{let{promptId:n,questionIndex:r}=e.body||{};try{t.json(await Pw(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})}});S.put("/api/tracks/:id/draft",async(e,t)=>{let{text:n,rev:r}=e.body||{};try{t.json(await Hw(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})}});S.get("/api/tracks/:id/usage",async(e,t)=>{let n=await oe(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 ep(r,{fresh:o}))});S.post("/api/tracks/:id/model",async(e,t)=>{let{model:n}=e.body||{};try{t.json(await Ww(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})}});S.post("/api/tracks/:id/subtask",async(e,t)=>{let{agent:n,task:r,skipPermissions:o,reason:s}=e.body||{};try{let a=await dg(e.params.id,{agent:n,task:r,skipPermissions:o!==!1,reason:s});t.json({ok:!0,subtask:ol(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})}});S.get("/api/tracks/:id/subtasks",(e,t)=>{t.json({subtasks:Zo(e.params.id).map(ol)})});S.get("/api/tracks/:id/subtask/:sid/messages",async(e,t)=>{let n=await Nw(e.params.id,e.params.sid);if(!n)return t.status(404).json({error:"subtask not found"});t.json(n)});S.post("/api/tracks/:id/subtask/:sid/cancel",(e,t)=>{try{t.json({ok:!0,subtask:ol(Rd(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});S.post("/api/tracks/:id/subtask/:sid/merge-now",(e,t)=>{try{t.json({ok:!0,subtask:ol(pg(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});function ol(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}S.post("/api/tracks/:id/handoff-lead",async(e,t)=>{let{toAgent:n,skipPermissions:r,reason:o}=e.body||{};try{let s=await _d(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})}});S.post("/api/tracks/:id/spin-up-view",async(e,t)=>{try{t.json(await Fw(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})}});S.get("/api/tracks/:id/handoff-lead",(e,t)=>{t.json(pO(xa(e.params.id))??{running:!1})});S.post("/api/tracks/:id/transfer-out",async(e,t)=>{try{let n=await sg(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})}});S.get("/api/tracks/:id/transfer-out",(e,t)=>{let n=og(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??{}})});S.post("/api/tracks/:id/transfer-out/commit",async(e,t)=>{try{t.json(await Id(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})}});S.post("/api/tracks/adopt",async(e,t)=>{let{trackId:n}=e.body||{};try{t.json(await cg({...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 pO(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}S.get("/api/debug/handoff",async(e,t)=>{let n=Math.min(Number(e.query.limit)||80,500);t.json({verbose:_l(),paths:Qb,trace:await Zb({limit:n})})});var jy=Te.resolve(tO,"..","..","client","dist");wt.existsSync(jy)&&(S.use(Ut.static(jy)),S.get(/^(?!\/api\/).*/,(e,t)=>t.sendFile(Te.join(jy,"index.html"),rl)));var fO=$K.createServer(S),HK=new CK({noServer:!0}),mO=(e,t,n)=>{if(!(Gc(e)||Ma.allowed(Ma.clientIp(e))||Fy.allows(e))){t.write(`HTTP/1.1 403 Forbidden\r
769
769
  \r
770
- `),t.destroy();return}if(g$(e,t,n))return;if(!m$(e,Fy,{enforce:nO})){t.write(`HTTP/1.1 401 Unauthorized\r
770
+ `),t.destroy();return}if(y$(e,t,n))return;if(!h$(e,Uy,{enforce:rO})){t.write(`HTTP/1.1 401 Unauthorized\r
771
771
  \r
772
772
  `),t.destroy();return}let r=bk(e.url);if(!r.ok){t.write(`HTTP/1.1 ${r.status} ${r.status===400?"Bad Request":"Not Found"}\r
773
773
  \r
774
- `),t.destroy();return}let o=r.sessionName;if(!Be(o)){t.write(`HTTP/1.1 400 Bad Request\r
774
+ `),t.destroy();return}let o=r.sessionName;if(!je(o)){t.write(`HTTP/1.1 400 Bad Request\r
775
775
  \r
776
- `),t.destroy();return}let{cols:s,rows:a}=r;UK.handleUpgrade(e,t,n,i=>wk(i,o,{cols:s,rows:a}))};pO.on("upgrade",fO);var mO=process.env.BOSTRAT_CERT_DIR||Te.join(process.env.HOME||gp.tmpdir(),".bostrat","certs"),XR=Number(process.env.BOSTRAT_TLS_PORT)||3443,ZR=Te.join(mO,"bostrat.globopi.key"),QR=Te.join(mO,"bostrat.globopi.crt");if(wt.existsSync(ZR)&&wt.existsSync(QR)){let e=$K.createServer({key:wt.readFileSync(ZR),cert:wt.readFileSync(QR)},S);e.on("upgrade",fO),e.on("error",t=>{console.error(`[bostrat-agent] https listener failed (${t?.code||t?.message}) \u2014 continuing HTTP-only`)}),e.listen(XR,yp,()=>{console.log(`[bostrat-agent] https listening on ${yp||"0.0.0.0"}:${XR}`)})}pO.listen(zR,yp,()=>{console.log(`[bostrat-agent] listening on ${yp||"0.0.0.0"}:${zR}`);let e=A_(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: ${Rt}`),console.log(`[bostrat-agent] auto-trigger default: ${tO}%`),console.log(`[bostrat-agent] ip allowlist: ${Ma.open?"OPEN":process.env.BOSTRAT_ALLOW_IPS||"CLOSED (BOSTRAT_ALLOW_IPS unset)"}`+(Ly.active?` \xB7 view front-door: ${process.env.BOSTRAT_VIEW_FRONT_CIDRS} (registered views only)`:"")),ng().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted handoff(s)")).catch(t=>console.error("[bostrat-agent] handoff reconcile failed:",t?.message||t)),cg().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted subtask(s)")).catch(t=>console.error("[bostrat-agent] subtask reconcile failed:",t?.message||t)),Zw().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(()=>Qw()).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)),Kw().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)),JK(),T_({listTracks:me}),qK(),KK(),VK(),xv({listTracks:me,getTrack:oe}).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)),IE()&&$E({listTracks:me}),tk().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)),mR(),yR(),SI({resolveTrack:oe}),MI({listTracks:me,createTrack:vd,archiveTrack:Yo,listRepos:Wn,resolveTrack:oe,sayToLead:Dt,answerPrompt:bd,startLeadHandoff:Ed,interruptLead:xd,listSubtaskJobs:Zo,cancelSubtask:$d,readEvents:K,appendEvent:C,divertShip:Ey,answerPrExists:_y,knownAgents:bc}),HK(),si().then(t=>{t||console.warn(`[boot] no host tmux server on ${Rt} and auto-start failed \u2014 boxes cannot spawn until one runs`)}),CR(),process.env.BOSTRAT_PLANE_URL&&process.env.BOSTRAT_PLANE_TOKEN&&(Na=P_({url:process.env.BOSTRAT_PLANE_URL,token:process.env.BOSTRAT_PLANE_TOKEN,apiToken:Fy,nodeId:process.env.BOSTRAT_NODE_ID||gp.hostname(),name:process.env.BOSTRAT_NODE_NAME||gp.hostname(),listTracks:me,detectAgents:gd,sampleMetrics:YI,deliverySample:()=>rA(Pw()),onHashKey:ZT,onTracksTransferred:ag,onDegraded:({since:t,unacked:n,oldestAgeMs:r,mode:o})=>{let s=Math.round(r/6e4),a=`${process.env.BOSTRAT_NODE_NAME||gp.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(()=>{}),YR=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(()=>{}),YR=null},onConnected:()=>{fR()},onUpdateAvailable:async t=>{try{By={latest:t.latest,current:t.current},await Bn({...t,policy:vt()}),vt()==="auto"&&await oO({to:t.latest,from:t.current})}catch(n){console.error(`[plane-link] update notice failed: ${n?.message||n}`)}},onUpdatePolicy:t=>PK(t).catch(()=>{}),onHelloRefused:async({current:t,min:n,latest:r,installKind:o,fix:s})=>{try{let a=r||n;if(await Bn({current:t,latest:a,min:n,installKind:o,required:!0,policy:vt(),status:"available",reason:"refused"}),vt()!=="off"&&a){let i=await Pd({to:a,kind:Xt,reason:"hard-floor"});i.ok?(tl.cancel(),await Bn({current:t,latest:a,min:n,installKind:o,required:!0,policy:vt(),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:vt}),console.log(`[bostrat-agent] plane link \u2192 ${process.env.BOSTRAT_PLANE_URL}`),ks().catch(()=>{}),kE().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} runbooks to the plane`),()=>{}),TI().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} ticket links to the plane`),()=>{}),qA().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} mocks to the plane`),()=>{}),iE().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} flows to the plane`),()=>{}),uS().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} PR links to the plane`),()=>{}))});process.on("SIGTERM",()=>{try{Na?.stop()}catch{}setTimeout(()=>process.exit(0),150)});function HK(){WK(),Qu().catch(()=>{}),setInterval(()=>Qu().catch(()=>{}),1e4)}function WK(){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=Te.resolve(eO,"..","bin",e),n=Te.join(process.env.HOME||"",".local","bin");if(!process.env.HOME||!wt.existsSync(t))continue;wt.mkdirSync(n,{recursive:!0});let r=Te.join(n,e);(wt.existsSync(r)?wt.readlinkSync(r):null)!==t&&(wt.rmSync(r,{force:!0}),wt.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 qK(){let e=!1,t=async()=>{if(!e){e=!0;try{let n=await me(),r=await QI({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 KK(){let e=null,t=async()=>{try{let n=Ps(),r=0,o=[],s=null,a=null;try{let u=await me(),d=await Zg(u);r=d.fleet.unpricedTurns||0,o=d.fleet.unpricedModels||[],s=await XI(u,{days:7}),a=(await ey(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(`
776
+ `),t.destroy();return}let{cols:s,rows:a}=r;HK.handleUpgrade(e,t,n,i=>wk(i,o,{cols:s,rows:a}))};fO.on("upgrade",mO);var hO=process.env.BOSTRAT_CERT_DIR||Te.join(process.env.HOME||yp.tmpdir(),".bostrat","certs"),ZR=Number(process.env.BOSTRAT_TLS_PORT)||3443,QR=Te.join(hO,"bostrat.globopi.key"),eO=Te.join(hO,"bostrat.globopi.crt");if(wt.existsSync(QR)&&wt.existsSync(eO)){let e=RK.createServer({key:wt.readFileSync(QR),cert:wt.readFileSync(eO)},S);e.on("upgrade",mO),e.on("error",t=>{console.error(`[bostrat-agent] https listener failed (${t?.code||t?.message}) \u2014 continuing HTTP-only`)}),e.listen(ZR,bp,()=>{console.log(`[bostrat-agent] https listening on ${bp||"0.0.0.0"}:${ZR}`)})}fO.listen(VR,bp,()=>{console.log(`[bostrat-agent] listening on ${bp||"0.0.0.0"}:${VR}`);let e=E_(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: ${Rt}`),console.log(`[bostrat-agent] auto-trigger default: ${nO}%`),console.log(`[bostrat-agent] ip allowlist: ${Ma.open?"OPEN":process.env.BOSTRAT_ALLOW_IPS||"CLOSED (BOSTRAT_ALLOW_IPS unset)"}`+(Fy.active?` \xB7 view front-door: ${process.env.BOSTRAT_VIEW_FRONT_CIDRS} (registered views only)`:"")),rg().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted handoff(s)")).catch(t=>console.error("[bostrat-agent] handoff reconcile failed:",t?.message||t)),lg().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted subtask(s)")).catch(t=>console.error("[bostrat-agent] subtask reconcile failed:",t?.message||t)),Qw().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(()=>eg()).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)),Gw().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)),YK(),A_({listTracks:me}),KK(),GK(),JK(),xv({listTracks:me,getTrack:oe}).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)),$E()&&RE({listTracks:me}),tk().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)),hR(),bR(),TI({resolveTrack:oe}),NI({listTracks:me,createTrack:Sd,archiveTrack:Yo,listRepos:Wn,resolveTrack:oe,sayToLead:Dt,answerPrompt:kd,startLeadHandoff:_d,interruptLead:vd,listSubtaskJobs:Zo,cancelSubtask:Rd,readEvents:K,appendEvent:C,divertShip:_y,answerPrExists:Iy,knownAgents:bc}),WK(),si().then(t=>{t||console.warn(`[boot] no host tmux server on ${Rt} and auto-start failed \u2014 boxes cannot spawn until one runs`)}),MR(),process.env.BOSTRAT_PLANE_URL&&process.env.BOSTRAT_PLANE_TOKEN&&(Na=D_({url:process.env.BOSTRAT_PLANE_URL,token:process.env.BOSTRAT_PLANE_TOKEN,apiToken:Uy,nodeId:process.env.BOSTRAT_NODE_ID||yp.hostname(),name:process.env.BOSTRAT_NODE_NAME||yp.hostname(),listTracks:me,detectAgents:yd,sampleMetrics:XI,deliverySample:()=>oA(Dw()),onHashKey:QT,onTracksTransferred:ig,onDegraded:({since:t,unacked:n,oldestAgeMs:r,mode:o})=>{let s=Math.round(r/6e4),a=`${process.env.BOSTRAT_NODE_NAME||yp.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(()=>{}),XR=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(()=>{}),XR=null},onConnected:()=>{mR()},onUpdateAvailable:async t=>{try{Ly={latest:t.latest,current:t.current},await jn({...t,policy:vt()}),vt()==="auto"&&await sO({to:t.latest,from:t.current})}catch(n){console.error(`[plane-link] update notice failed: ${n?.message||n}`)}},onUpdatePolicy:t=>DK(t).catch(()=>{}),onHelloRefused:async({current:t,min:n,latest:r,installKind:o,fix:s})=>{try{let a=r||n;if(await jn({current:t,latest:a,min:n,installKind:o,required:!0,policy:vt(),status:"available",reason:"refused"}),vt()!=="off"&&a){let i=await Dd({to:a,kind:Xt,reason:"hard-floor"});i.ok?(tl.cancel(),await jn({current:t,latest:a,min:n,installKind:o,required:!0,policy:vt(),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:vt}),console.log(`[bostrat-agent] plane link \u2192 ${process.env.BOSTRAT_PLANE_URL}`),ks().catch(()=>{}),xE().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} runbooks to the plane`),()=>{}),AI().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} ticket links to the plane`),()=>{}),KA().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} mocks to the plane`),()=>{}),cE().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} flows to the plane`),()=>{}),uS().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} PR links to the plane`),()=>{}))});process.on("SIGTERM",()=>{try{Na?.stop()}catch{}setTimeout(()=>process.exit(0),150)});function WK(){qK(),ed().catch(()=>{}),setInterval(()=>ed().catch(()=>{}),1e4)}function qK(){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=Te.resolve(tO,"..","bin",e),n=Te.join(process.env.HOME||"",".local","bin");if(!process.env.HOME||!wt.existsSync(t))continue;wt.mkdirSync(n,{recursive:!0});let r=Te.join(n,e);(wt.existsSync(r)?wt.readlinkSync(r):null)!==t&&(wt.rmSync(r,{force:!0}),wt.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 KK(){let e=!1,t=async()=>{if(!e){e=!0;try{let n=await me(),r=await e$({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 GK(){let e=null,t=async()=>{try{let n=Ps(),r=0,o=[],s=null,a=null;try{let u=await me(),d=await Qg(u);r=d.fleet.unpricedTurns||0,o=d.fleet.unpricedModels||[],s=await ZI(u,{days:7}),a=(await ty(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(`
777
777
  `);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(`
778
- `).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 GK=Number(process.env.BOSTRAT_MEMORY_RECONCILE_MS)||5*6e4,zK=Number(process.env.BOSTRAT_MEMORY_RECONCILE_FIRST_MS)||5*6e4;function VK(){let e=async()=>{try{let n=await Db();n.ran&&console.log(`[memory] one-time full backfill sweep: ${n.harvested} fact(s) harvested`);let o=(await me()).filter(a=>!Ve(a)&&a.kind!=="setup").flatMap(a=>[a.cwd,...(a.boxes||[]).map(i=>i.cwd)]).filter(Boolean),s=await Pb([...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,GK).unref()},zK).unref()}function JK(){let e=!1;setInterval(async()=>{if(!e){e=!0;try{let t=await me();for(let n of t)Ve(n)||!n.boxes?.some(r=>r.state==="live")||(await yd(n.id).catch(()=>{}),await nd(n).catch(()=>{}))}catch{}finally{e=!1}}},4e3)}
778
+ `).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 zK=Number(process.env.BOSTRAT_MEMORY_RECONCILE_MS)||5*6e4,VK=Number(process.env.BOSTRAT_MEMORY_RECONCILE_FIRST_MS)||5*6e4;function JK(){let e=async()=>{try{let n=await Db();n.ran&&console.log(`[memory] one-time full backfill sweep: ${n.harvested} fact(s) harvested`);let o=(await me()).filter(a=>!Ve(a)&&a.kind!=="setup").flatMap(a=>[a.cwd,...(a.boxes||[]).map(i=>i.cwd)]).filter(Boolean),s=await Pb([...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,zK).unref()},VK).unref()}function YK(){let e=!1;setInterval(async()=>{if(!e){e=!0;try{let t=await me();for(let n of t)Ve(n)||!n.boxes?.some(r=>r.state==="live")||(await bd(n.id).catch(()=>{}),await rd(n).catch(()=>{}))}catch{}finally{e=!1}}},4e3)}