bostrat-node 1.6.3 → 1.6.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.
package/dist/index.js CHANGED
@@ -1,89 +1,89 @@
1
- var Dv=Object.defineProperty;var M=(t,e)=>()=>(t&&(e=t(t=0)),e);var gl=(t,e)=>{for(var n in e)Dv(t,n,{get:e[n],enumerable:!0})};import{createHash as jv,randomBytes as Lv,timingSafeEqual as Fv}from"node:crypto";function xm(){return Lv(32).toString("hex")}function Yo(t){let e=typeof t=="string"?t.trim():"";return e?jv("sha256").update(e).digest("hex"):null}function Sm(t,e){return typeof t!="string"||typeof e!="string"||t.length!==e.length||!t?!1:Fv(Buffer.from(t),Buffer.from(e))}function Xo(t,e={},{now:n=Date.now(),log:r=console.warn}={}){if(yl.set(t,(yl.get(t)||0)+1),bl.has(t)&&n-bl.get(t)<Uv)return!1;bl.set(t,n);let o=Object.entries(e).filter(([,s])=>s!=null&&s!=="").map(([s,a])=>`${s}=${a}`).join(" ");return r(`[hook-audit] ${t} n=${yl.get(t)}${o?` ${o}`:""}`),!0}async function vm(t,{byToken:e,legacy:n,env:r=process.env}={}){let o=typeof t=="string"?t.trim():"";if(!o)return r.BOSTRAT_HOOK_LEGACY_DENY==="1"?{mode:"legacy-denied",target:null}:{mode:"legacy",target:await n()};let s=await e(o);return s?.track?{mode:"token",target:s}:{mode:"refused",target:null}}var La,Fa,yl,bl,Uv,Zo=M(()=>{La="BOSTRAT_HOOK_TOKEN",Fa="x-bostrat-hook";yl=new Map,bl=new Map,Uv=6e4});import Zt from"node:fs/promises";import Tm from"node:os";import Vt from"node:path";import{execFile as Hv}from"node:child_process";import{promisify as Wv}from"node:util";function Ua(){return/^(1|true|yes|on)$/i.test(process.env.BOSTRAT_CLAUDE_USE_API_KEY||"")&&process.env.ANTHROPIC_API_KEY?.trim()||null}function qv(){return process.env.CLAUDE_CONFIG_DIR?Vt.join(process.env.CLAUDE_CONFIG_DIR,".claude.json"):Vt.join(Tm.homedir(),".claude.json")}function Kv(){return process.env.CLAUDE_CONFIG_DIR?Vt.join(process.env.CLAUDE_CONFIG_DIR,"settings.json"):Vt.join(Tm.homedir(),".claude","settings.json")}async function mn(t){if(!t||typeof t!="string")return;let e=Vt.resolve(t),n=qv(),r=Kv(),o={};try{o=JSON.parse(await Zt.readFile(n,"utf8"))}catch{}o.hasCompletedOnboarding=!0,o.theme||(o.theme="dark"),o.projects=o.projects||{},o.projects[e]=o.projects[e]||{};let s=o.projects[e];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 Zt.mkdir(Vt.dirname(n),{recursive:!0}),await Zt.writeFile(n,JSON.stringify(o,null,2));let i={};try{i=JSON.parse(await Zt.readFile(r,"utf8"))}catch{}if(i.skipDangerousModePermissionPrompt=!0,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 "${Fa}: $${La}" --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 Zt.mkdir(Vt.dirname(r),{recursive:!0}),await Zt.writeFile(r,JSON.stringify(i,null,2)),await Gv(e)}async function Gv(t){try{let e=Vt.resolve(t),n=Vt.join(e,".bostrat","memory","claude"),r=Vt.join(e,".claude","settings.local.json"),o={};try{o=JSON.parse(await Zt.readFile(r,"utf8"))}catch{}let s=o.autoMemoryDirectory,a=typeof s=="string"&&s.includes(Vt.join(".bostrat","memory"));if(s&&!a||s===n)return;o.autoMemoryDirectory=n,await Zt.mkdir(n,{recursive:!0}),await Zt.mkdir(Vt.dirname(r),{recursive:!0}),await Zt.writeFile(r,JSON.stringify(o,null,2)),await Vv(e,["/.claude/settings.local.json"])}catch{}}async function Vv(t,e){try{let{stdout:n}=await Wv(Hv)("git",["-C",t,"rev-parse","--git-path","info/exclude"]),r=Vt.resolve(t,n.trim()),o=await Zt.readFile(r,"utf8").catch(()=>""),s=e.filter(a=>!o.split(`
2
- `).includes(a));if(!s.length)return;await Zt.mkdir(Vt.dirname(r),{recursive:!0}),await Zt.appendFile(r,(o&&!o.endsWith(`
1
+ var fT=Object.defineProperty;var M=(t,e,n)=>()=>{if(n)throw n[0];try{return t&&(e=t(t=0)),e}catch(r){throw n=[r],r}};var $l=(t,e)=>{for(var n in e)fT(t,n,{get:e[n],enumerable:!0})};import{createHash as pT,randomBytes as mT,timingSafeEqual as hT}from"node:crypto";function Gm(){return mT(32).toString("hex")}function as(t){let e=typeof t=="string"?t.trim():"";return e?pT("sha256").update(e).digest("hex"):null}function Vm(t,e){return typeof t!="string"||typeof e!="string"||t.length!==e.length||!t?!1:hT(Buffer.from(t),Buffer.from(e))}function is(t,e={},{now:n=Date.now(),log:r=console.warn}={}){if(Ol.set(t,(Ol.get(t)||0)+1),Cl.has(t)&&n-Cl.get(t)<wT)return!1;Cl.set(t,n);let o=Object.entries(e).filter(([,s])=>s!=null&&s!=="").map(([s,a])=>`${s}=${a}`).join(" ");return r(`[hook-audit] ${t} n=${Ol.get(t)}${o?` ${o}`:""}`),!0}async function zm(t,{byToken:e,legacy:n,env:r=process.env}={}){let o=typeof t=="string"?t.trim():"";if(!o)return r.BOSTRAT_HOOK_LEGACY_DENY==="1"?{mode:"legacy-denied",target:null}:{mode:"legacy",target:await n()};let s=await e(o);return s?.track?{mode:"token",target:s}:{mode:"refused",target:null}}var Ya,Xa,Ol,Cl,wT,cs=M(()=>{Ya="BOSTRAT_HOOK_TOKEN",Xa="x-bostrat-hook";Ol=new Map,Cl=new Map,wT=6e4});import ee from"node:fs/promises";import Jm from"node:os";import zt from"node:path";import{execFile as gT}from"node:child_process";import{promisify as yT}from"node:util";function Za(){return/^(1|true|yes|on)$/i.test(process.env.BOSTRAT_CLAUDE_USE_API_KEY||"")&&process.env.ANTHROPIC_API_KEY?.trim()||null}function bT(){return process.env.CLAUDE_CONFIG_DIR?zt.join(process.env.CLAUDE_CONFIG_DIR,".claude.json"):zt.join(Jm.homedir(),".claude.json")}function kT(){return process.env.CLAUDE_CONFIG_DIR?zt.join(process.env.CLAUDE_CONFIG_DIR,"settings.json"):zt.join(Jm.homedir(),".claude","settings.json")}async function gn(t){if(!t||typeof t!="string")return;let e=zt.resolve(t),n=bT(),r=kT(),o={};try{o=JSON.parse(await ee.readFile(n,"utf8"))}catch{}o.hasCompletedOnboarding=!0,o.theme||(o.theme="dark"),o.projects=o.projects||{},o.projects[e]=o.projects[e]||{};let s=o.projects[e];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 ee.mkdir(zt.dirname(n),{recursive:!0}),await ee.writeFile(n,JSON.stringify(o,null,2));let i={};try{i=JSON.parse(await ee.readFile(r,"utf8"))}catch{}if(i.skipDangerousModePermissionPrompt=!0,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 "${Xa}: $${Ya}" --data-binary @- >/dev/null 2>&1 || true`,u=[{hooks:[{type:"command",command:l}]}];i.hooks=i.hooks||{};for(let f of["SessionStart","UserPromptSubmit","Stop"])i.hooks[f]=u;i.hooks.PostToolUse=[{matcher:"*",hooks:[{type:"command",command:l}]}]}await ee.mkdir(zt.dirname(r),{recursive:!0}),await ee.writeFile(r,JSON.stringify(i,null,2)),await xT(e)}async function xT(t){try{let e=zt.resolve(t),n=zt.join(e,".bostrat","memory","claude"),r=zt.join(e,".claude","settings.local.json"),o={};try{o=JSON.parse(await ee.readFile(r,"utf8"))}catch{}let s=o.autoMemoryDirectory,a=typeof s=="string"&&s.includes(zt.join(".bostrat","memory"));if(s&&!a||s===n)return;o.autoMemoryDirectory=n,await ee.mkdir(n,{recursive:!0}),await ee.mkdir(zt.dirname(r),{recursive:!0}),await ee.writeFile(r,JSON.stringify(o,null,2)),await ST(e,["/.claude/settings.local.json"])}catch{}}async function ST(t,e){try{let{stdout:n}=await yT(gT)("git",["-C",t,"rev-parse","--git-path","info/exclude"]),r=zt.resolve(t,n.trim()),o=await ee.readFile(r,"utf8").catch(()=>""),s=e.filter(a=>!o.split(`
2
+ `).includes(a));if(!s.length)return;await ee.mkdir(zt.dirname(r),{recursive:!0}),await ee.appendFile(r,(o&&!o.endsWith(`
3
3
  `)?`
4
4
  `:"")+s.join(`
5
5
  `)+`
6
- `)}catch{}}var Qo=M(()=>{Zo()});import kl from"node:fs/promises";import zv from"node:os";import Ha from"node:path";function Jv(){let t=process.env.CODEX_HOME||Ha.join(zv.homedir(),".codex");return Ha.join(t,"config.toml")}function Am(t){return`[projects."${t}"]`}function Yv(t,e){let n=Am(e),r=t.indexOf(n);if(r===-1)return!1;let o=t.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 Br(t){if(!t||typeof t!="string")return;let e=Ha.resolve(t),n=Jv(),r="";try{r=await kl.readFile(n,"utf8")}catch{}if(Yv(r,e))return;let o=Am(e);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 ls=M(()=>{cs()});import Ml from"node:fs/promises";import vT from"node:os";import Qa from"node:path";function TT(){let t=process.env.CODEX_HOME||Qa.join(vT.homedir(),".codex");return Qa.join(t,"config.toml")}function Ym(t){return`[projects."${t}"]`}function AT(t,e){let n=Ym(e),r=t.indexOf(n);if(r===-1)return!1;let o=t.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 qr(t){if(!t||typeof t!="string")return;let e=Qa.resolve(t),n=TT(),r="";try{r=await Ml.readFile(n,"utf8")}catch{}if(AT(r,e))return;let o=Ym(e);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),f=/trust_level\s*=/.test(u)?u.replace(/trust_level\s*=\s*"[^"]*"/,'trust_level = "trusted"'):`${u.replace(/\s*$/,"")}
7
7
  trust_level = "trusted"
8
- `;r=r.slice(0,a)+d+r.slice(l)}else{let s=`
8
+ `;r=r.slice(0,a)+f+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 kl.mkdir(Ha.dirname(n),{recursive:!0}),await kl.writeFile(n,r)}catch(s){console.warn(`[codex-config] could not seed folder trust for ${e}: ${s?.message||s}`)}}var Wa=M(()=>{});import Em from"node:fs/promises";import Xv from"node:os";import ts from"node:path";function Zv(t){let n=ts.resolve(t).slice(1).replace(/\//g,"-").replace(/\./g,""),r=process.env.CURSOR_CONFIG_DIR||ts.join(Xv.homedir(),".cursor");return ts.join(r,"projects",n)}async function Dr(t){if(!t||typeof t!="string")return;let e=ts.resolve(t),n=Zv(e),r=ts.join(n,".workspace-trusted");await Em.mkdir(n,{recursive:!0}),await Em.writeFile(r,`${JSON.stringify({trustedAt:new Date().toISOString(),workspacePath:e},null,2)}
14
- `,"utf8")}var qa=M(()=>{});import Sl from"node:fs/promises";import hn from"node:path";import{execFile as Qv}from"node:child_process";import{promisify as tT}from"node:util";async function aT(t){try{return(await Sl.stat(hn.join(t,".git"))).isDirectory()?"repo":"worktree"}catch{return null}}async function iT(t){let e=i=>Sl.readFile(hn.join(t,".git",i),"utf8").then(c=>c.trim()).catch(()=>null),r=(await e("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 e(`refs/heads/${i}`)||(o??=await e("packed-refs")||"",new RegExp(`^[0-9a-f]{40} refs/heads/${i}$`,"m").test(o)))return i;let a=(await e("HEAD"))?.match(/^ref:\s*refs\/heads\/(.+)/);return a?a[1].trim():null}async function Ue(){let t=new Map;async function e(o,s){if(t.has(o))return;let a=await aT(o);if(a==="worktree")return;if(a==="repo"){t.set(o,{path:o,name:hn.basename(o),branch:await iT(o)});return}if(s>=oT)return;let i;try{i=await Sl.readdir(o,{withFileTypes:!0})}catch{return}for(let c of i)!c.isDirectory()||c.name.startsWith(".")||sT.has(c.name)||await e(hn.join(o,c.name),s+1)}for(let o of rT)await e(hn.resolve(o),0);let n=new Set,r=[];for(let o of t.values()){let s=(await st(o.path))?.toLowerCase();if(s){if(n.has(s))continue;n.add(s)}r.push(o)}return r.sort((o,s)=>o.name.localeCompare(s.name))}function cT(t){let e=String(t||"").trim().match(/github\.com[:/]+([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i);return e?`${e[1]}/${e[2]}`:null}async function st(t){if(!t)return null;if(xl.has(t))return xl.get(t);let e=null;try{let{stdout:n}=await eT("git",["-C",t,"config","--get","remote.origin.url"],{timeout:5e3});e=cT(n)}catch{e=null}return xl.set(t,e),e}async function es(t){let e=String(t||"").toLowerCase();if(!e)return null;for(let n of await Ue())if((await st(n.path))?.toLowerCase()===e)return n.path;return null}var eT,_m,nT,rT,oT,sT,xl,Qn=M(()=>{eT=tT(Qv),_m=process.env.HOME||"/home/globo",nT=hn.join(process.env.BOSTRAT_STATE_DIR||hn.join(_m,".bostrat"),"repos"),rT=[...(process.env.BOSTRAT_REPOS_ROOT||hn.join(_m,"Documents")).split(","),nT].map(t=>t.trim()).filter(Boolean),oT=Number(process.env.BOSTRAT_REPOS_DEPTH)||3,sT=new Set(["node_modules",".git",".cache","dist","build",".next","vendor","__pycache__","venv",".venv","target"]);xl=new Map});import lT from"node:fs";import Im from"node:fs/promises";import ns from"node:path";import uT from"node:os";import{fileURLToPath as dT}from"node:url";import{execFile as fT}from"node:child_process";import{promisify as pT}from"node:util";function vt(t=process.env){let e=t.BOSTRAT_PLANE_URL||"";if(!e)return null;try{let n=new URL(e);return n.protocol=n.protocol==="ws:"?"http:":"https:",n.origin}catch{return null}}function Ka(t=process.env){return!!(vt(t)&&t.BOSTRAT_PLANE_TOKEN)}async function Ga(t,{env:e=process.env}={}){let n=String(t||"").toLowerCase();if(!$m.test(n))throw jr("repo must be owner/name",400);let r=vl.get(n);if(r&&r.expiresAt-Date.now()>wT)return r;if(!Ka(e))throw jr("node is not plane-linked \u2014 GitHub auth unavailable",503);let o;try{o=await Om(`${vt(e)}/v1/github/token?repo=${encodeURIComponent(t)}`,{headers:Cm(e)})}catch(i){if(r&&r.expiresAt>Date.now())return r;throw jr(`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 jr(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 vl.set(n,a),a}async function rs({env:t=process.env,force:e=!1}={}){if(!Ka(t))return{configured:!1,repos:[],username:null};if(!e&&tr&&Date.now()-tr.at<gT)return tr.data;try{let n=await Om(`${vt(t)}/v1/github/repos`,{headers:Cm(t)});if(!n.ok)throw new Error(`plane replied ${n.status}`);let r=await n.json();return tr={at:Date.now(),data:r},r}catch(n){return tr?tr.data:{configured:!0,repos:[],username:null,error:n?.message||String(n)}}}function Mm(){vl.clear(),tr=null}async function Ae({cwd:t=null,slug:e=null,env:n=process.env}={}){try{let r=e||(t?await st(t):null);if(!r)return{};let{token:o}=await Ga(r,{env:n});return o?{GH_TOKEN:o}:{}}catch{return{}}}async function Tl({env:t=process.env}={}){return(await rs({env:t})).username??null}function xT(t){let[e,n]=String(t).split("/");return ns.join(hT,e,n)}async function Al(t,{env:e=process.env}={}){let n=(...r)=>Rm("git",["-C",t,...r],{timeout:1e4});await n("config","--replace-all","credential.helper",""),await n("config","--add","credential.helper",`!"${bT()}" ${kT(e)}`),await n("config","credential.useHttpPath","true")}async function El(t,{env:e=process.env,baseUrl:n="https://github.com"}={}){if(!$m.test(String(t||"")))throw jr(`bad repo slug "${t}"`,400);let r=xT(t);if(lT.existsSync(ns.join(r,".git")))return r;let{token:o}=await Ga(t,{env:e});await Im.mkdir(ns.dirname(r),{recursive:!0});let s="!f() { echo username=x-access-token; echo password=$BOSTRAT_GIT_TOKEN; }; f";try{await Rm("git",["-c","credential.helper=","-c",`credential.helper=${s}`,"clone","--no-tags","-q",`${n}/${t}.git`,r],{timeout:yT,env:{...e,BOSTRAT_GIT_TOKEN:o,GIT_TERMINAL_PROMPT:"0"}})}catch(a){throw await Im.rm(r,{recursive:!0,force:!0}).catch(()=>{}),jr(`clone of ${t} failed: ${a?.stderr?.trim?.()||a?.message||a}`,502)}return await Al(r,{env:e}),r}var Rm,mT,hT,$m,wT,gT,yT,Om,vl,tr,Cm,jr,bT,kT,Qt=M(()=>{Qn();Rm=pT(fT),mT=process.env.BOSTRAT_STATE_DIR||ns.join(process.env.HOME||uT.tmpdir(),".bostrat"),hT=ns.join(mT,"repos"),$m=/^[^/\s]+\/[^/\s]+$/,wT=5*6e4,gT=6e4,yT=10*6e4,Om=fetch,vl=new Map,tr=null;Cm=t=>({authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`}),jr=(t,e)=>Object.assign(new Error(t),{status:e});bT=()=>dT(new URL("../bin/bostrat-git-credential",import.meta.url)),kT=(t=process.env)=>`http://127.0.0.1:${Number(t.PORT)||3362}`});function Pm(t=process.env){return!!(vt(t)&&t.BOSTRAT_PLANE_TOKEN)}async function Bm(t,e,n){let r=vt(n),o=new AbortController,s=setTimeout(()=>o.abort(),vT);try{return await TT(`${r}${t}`,{...e,signal:o.signal})}finally{clearTimeout(s)}}async function Dm(t,{env:e=process.env,force:n=!1}={}){if(!Pm(e))return{facts:[],source:"unconfigured"};let r=_l.get(t);if(!n&&r&&Date.now()-r.at<ST)return{facts:r.facts,source:"cache"};try{let o=await Bm(`/v1/memory/${encodeURIComponent(t)}`,{headers:Nm(e)},e);if(!o.ok)throw new Error(`plane ${o.status}`);let s=await o.json(),a=Array.isArray(s?.facts)?s.facts:[];return _l.set(t,{at:Date.now(),facts:a}),{facts:a,source:"plane"}}catch(o){return r?{facts:r.facts,source:"stale",error:o?.message}:{facts:[],source:"unreachable",error:o?.message}}}async function Va(t,e,{env:n=process.env}={}){if(!Pm(n))return{pushed:0,source:"unconfigured"};if(!e?.length)return{pushed:0,source:"empty"};try{let r=await Bm(`/v1/memory/${encodeURIComponent(t)}`,{method:"POST",headers:{...Nm(n),"content-type":"application/json"},body:JSON.stringify({facts:e})},n);if(!r.ok)throw new Error(`plane ${r.status}`);let o=await r.json(),s=Array.isArray(o?.results)?o.results:[];return _l.delete(t),{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 ST,vT,_l,TT,Nm,jm=M(()=>{Qt();ST=6e4,vT=5e3,_l=new Map,TT=(...t)=>fetch(...t);Nm=t=>({authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`})});import F from"node:fs/promises";import AT from"node:os";import Z from"node:path";import{execFile as ET}from"node:child_process";import{promisify as _T}from"node:util";function za(){return Z.join(Il,"memory","repos")}function er(t){return t===He?Z.join(Il,"memory",He):Z.join(za(),t)}async function os(t){try{return JSON.parse(await F.readFile(Z.join(t,Wm),"utf8"))}catch{return{}}}async function Rl(t,e){let n=await os(t);for(let[r,o]of e)n[r]=Math.max(Number(n[r])||0,o);await F.mkdir(t,{recursive:!0}),await F.writeFile(Z.join(t,Wm),JSON.stringify(n))}function Fm(t){let e=String(t||"").trim();if(!e)return null;let r=(e.replace(/\/+$/,"").split(/[/:]/).pop()||"").replace(/\.git$/i,"").toLowerCase();return/^[a-z0-9][a-z0-9._-]*$/.test(r)?r:null}async function Um(t){try{let{stdout:e}=await IT("git",["-C",t,"config","--get","remote.origin.url"]);return e.trim()||null}catch{return null}}async function $l(t){if(!t)return[];let e=Fm(await Um(t));if(e)return[e];let n=[],r=[];try{r=await F.readdir(t,{withFileTypes:!0})}catch{return[]}for(let o of r){if(!o.isDirectory()||o.name.startsWith("."))continue;let s=Fm(await Um(Z.join(t,o.name)));s&&!n.includes(s)&&n.push(s)}return n}function Ja(t){let e=/^---\n([\s\S]*?)\n---\n?/.exec(t);return e?{fm:e[1],body:t.slice(e[0].length)}:{fm:null,body:t}}function wn(t,e){let n=new RegExp(`^\\s*${e}:\\s*(.+?)\\s*$`,"m").exec(t||"");return n?n[1].replace(/^"|"$/g,""):null}async function Ee(t,e=null){let n=e??await F.readFile(t,"utf8").catch(()=>""),{fm:r}=Ja(n),o=wn(r,"modified"),s=o?Date.parse(o):NaN;if(Number.isFinite(s))return s;try{return(await F.stat(t)).mtimeMs}catch{return 0}}function qm(t,e){let n=wn(t,"scope"),r=/^repo:([a-z0-9][a-z0-9._-]*)$/i.exec(n||"");if(r)return r[1].toLowerCase();if((n||"").toLowerCase()===He){let o=wn(t,"trust");if(!o||/^operator/i.test(o))return He}return e}function Ol(t,e,n,r=new Map){let o=(t||"").split(`
13
+ `:"")}try{await Ml.mkdir(Qa.dirname(n),{recursive:!0}),await Ml.writeFile(n,r)}catch(s){console.warn(`[codex-config] could not seed folder trust for ${e}: ${s?.message||s}`)}}var ti=M(()=>{});import Xm from"node:fs/promises";import ET from"node:os";import us from"node:path";function _T(t){let n=us.resolve(t).slice(1).replace(/\//g,"-").replace(/\./g,""),r=process.env.CURSOR_CONFIG_DIR||us.join(ET.homedir(),".cursor");return us.join(r,"projects",n)}async function Kr(t){if(!t||typeof t!="string")return;let e=us.resolve(t),n=_T(e),r=us.join(n,".workspace-trusted");await Xm.mkdir(n,{recursive:!0}),await Xm.writeFile(r,`${JSON.stringify({trustedAt:new Date().toISOString(),workspacePath:e},null,2)}
14
+ `,"utf8")}var ei=M(()=>{});import Pl from"node:fs/promises";import yn from"node:path";import{execFile as IT}from"node:child_process";import{promisify as RT}from"node:util";async function PT(t){try{return(await Pl.stat(yn.join(t,".git"))).isDirectory()?"repo":"worktree"}catch{return null}}async function DT(t){let e=i=>Pl.readFile(yn.join(t,".git",i),"utf8").then(c=>c.trim()).catch(()=>null),r=(await e("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 e(`refs/heads/${i}`)||(o??=await e("packed-refs")||"",new RegExp(`^[0-9a-f]{40} refs/heads/${i}$`,"m").test(o)))return i;let a=(await e("HEAD"))?.match(/^ref:\s*refs\/heads\/(.+)/);return a?a[1].trim():null}async function We(){let t=new Map;async function e(o,s){if(t.has(o))return;let a=await PT(o);if(a==="worktree")return;if(a==="repo"){t.set(o,{path:o,name:yn.basename(o),branch:await DT(o)});return}if(s>=MT)return;let i;try{i=await Pl.readdir(o,{withFileTypes:!0})}catch{return}for(let c of i)!c.isDirectory()||c.name.startsWith(".")||NT.has(c.name)||await e(yn.join(o,c.name),s+1)}for(let o of CT)await e(yn.resolve(o),0);let n=new Set,r=[];for(let o of t.values()){let s=(await lt(o.path))?.toLowerCase();if(s){if(n.has(s))continue;n.add(s)}r.push(o)}return r.sort((o,s)=>o.name.localeCompare(s.name))}function BT(t){let e=String(t||"").trim().match(/github\.com[:/]+([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i);return e?`${e[1]}/${e[2]}`:null}async function lt(t){if(!t)return null;if(Nl.has(t))return Nl.get(t);let e=null;try{let{stdout:n}=await $T("git",["-C",t,"config","--get","remote.origin.url"],{timeout:5e3});e=BT(n)}catch{e=null}return Nl.set(t,e),e}async function Gr(t){let e=String(t||"").toLowerCase();if(!e)return null;for(let n of await We())if((await lt(n.path))?.toLowerCase()===e)return n.path;return null}var $T,Zm,OT,CT,MT,NT,Nl,ar=M(()=>{$T=RT(IT),Zm=process.env.HOME||"/home/globo",OT=yn.join(process.env.BOSTRAT_STATE_DIR||yn.join(Zm,".bostrat"),"repos"),CT=[...(process.env.BOSTRAT_REPOS_ROOT||yn.join(Zm,"Documents")).split(","),OT].map(t=>t.trim()).filter(Boolean),MT=Number(process.env.BOSTRAT_REPOS_DEPTH)||3,NT=new Set(["node_modules",".git",".cache","dist","build",".next","vendor","__pycache__","venv",".venv","target"]);Nl=new Map});import jT from"node:fs";import Qm from"node:fs/promises";import ds from"node:path";import LT from"node:os";import{fileURLToPath as FT}from"node:url";import{execFile as UT}from"node:child_process";import{promisify as HT}from"node:util";function St(t=process.env){let e=t.BOSTRAT_PLANE_URL||"";if(!e)return null;try{let n=new URL(e);return n.protocol=n.protocol==="ws:"?"http:":"https:",n.origin}catch{return null}}function ni(t=process.env){return!!(St(t)&&t.BOSTRAT_PLANE_TOKEN)}async function ri(t,{env:e=process.env}={}){let n=String(t||"").toLowerCase();if(!eh.test(n))throw Vr("repo must be owner/name",400);let r=Dl.get(n);if(r&&r.expiresAt-Date.now()>KT)return r;if(!ni(e))throw Vr("node is not plane-linked \u2014 GitHub auth unavailable",503);let o;try{o=await nh(`${St(e)}/v1/github/token?repo=${encodeURIComponent(t)}`,{headers:rh(e)})}catch(i){if(r&&r.expiresAt>Date.now())return r;throw Vr(`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 Vr(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 Dl.set(n,a),a}async function fs({env:t=process.env,force:e=!1}={}){if(!ni(t))return{configured:!1,repos:[],username:null};if(!e&&ir&&Date.now()-ir.at<GT)return ir.data;try{let n=await nh(`${St(t)}/v1/github/repos`,{headers:rh(t)});if(!n.ok)throw new Error(`plane replied ${n.status}`);let r=await n.json();return ir={at:Date.now(),data:r},r}catch(n){return ir?ir.data:{configured:!0,repos:[],username:null,error:n?.message||String(n)}}}function oh(){Dl.clear(),ir=null}async function _e({cwd:t=null,slug:e=null,env:n=process.env}={}){try{let r=e||(t?await lt(t):null);if(!r)return{};let{token:o}=await ri(r,{env:n});return o?{GH_TOKEN:o}:{}}catch{return{}}}async function Bl({env:t=process.env}={}){return(await fs({env:t})).username??null}function YT(t){let[e,n]=String(t).split("/");return ds.join(qT,e,n)}async function jl(t,{env:e=process.env}={}){let n=(...r)=>th("git",["-C",t,...r],{timeout:1e4});await n("config","--replace-all","credential.helper",""),await n("config","--add","credential.helper",`!"${zT()}" ${JT(e)}`),await n("config","credential.useHttpPath","true")}async function oi(t,{env:e=process.env,baseUrl:n="https://github.com"}={}){if(!eh.test(String(t||"")))throw Vr(`bad repo slug "${t}"`,400);let r=YT(t);if(jT.existsSync(ds.join(r,".git")))return r;let{token:o}=await ri(t,{env:e});await Qm.mkdir(ds.dirname(r),{recursive:!0});let s="!f() { echo username=x-access-token; echo password=$BOSTRAT_GIT_TOKEN; }; f";try{await th("git",["-c","credential.helper=","-c",`credential.helper=${s}`,"clone","--no-tags","-q",`${n}/${t}.git`,r],{timeout:VT,env:{...e,BOSTRAT_GIT_TOKEN:o,GIT_TERMINAL_PROMPT:"0"}})}catch(a){throw await Qm.rm(r,{recursive:!0,force:!0}).catch(()=>{}),Vr(`clone of ${t} failed: ${a?.stderr?.trim?.()||a?.message||a}`,502)}return await jl(r,{env:e}),r}var th,WT,qT,eh,KT,GT,VT,nh,Dl,ir,rh,Vr,zT,JT,Jt=M(()=>{ar();th=HT(UT),WT=process.env.BOSTRAT_STATE_DIR||ds.join(process.env.HOME||LT.tmpdir(),".bostrat"),qT=ds.join(WT,"repos"),eh=/^[^/\s]+\/[^/\s]+$/,KT=5*6e4,GT=6e4,VT=10*6e4,nh=fetch,Dl=new Map,ir=null;rh=t=>({authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`}),Vr=(t,e)=>Object.assign(new Error(t),{status:e});zT=()=>FT(new URL("../bin/bostrat-git-credential",import.meta.url)),JT=(t=process.env)=>`http://127.0.0.1:${Number(t.PORT)||3362}`});function sh(t=process.env){return!!(St(t)&&t.BOSTRAT_PLANE_TOKEN)}async function ih(t,e,n){let r=St(n),o=new AbortController,s=setTimeout(()=>o.abort(),ZT);try{return await QT(`${r}${t}`,{...e,signal:o.signal})}finally{clearTimeout(s)}}async function ch(t,{env:e=process.env,force:n=!1}={}){if(!sh(e))return{facts:[],source:"unconfigured"};let r=Ll.get(t);if(!n&&r&&Date.now()-r.at<XT)return{facts:r.facts,source:"cache"};try{let o=await ih(`/v1/memory/${encodeURIComponent(t)}`,{headers:ah(e)},e);if(!o.ok)throw new Error(`plane ${o.status}`);let s=await o.json(),a=Array.isArray(s?.facts)?s.facts:[];return Ll.set(t,{at:Date.now(),facts:a}),{facts:a,source:"plane"}}catch(o){return r?{facts:r.facts,source:"stale",error:o?.message}:{facts:[],source:"unreachable",error:o?.message}}}async function si(t,e,{env:n=process.env}={}){if(!sh(n))return{pushed:0,source:"unconfigured"};if(!e?.length)return{pushed:0,source:"empty"};try{let r=await ih(`/v1/memory/${encodeURIComponent(t)}`,{method:"POST",headers:{...ah(n),"content-type":"application/json"},body:JSON.stringify({facts:e})},n);if(!r.ok)throw new Error(`plane ${r.status}`);let o=await r.json(),s=Array.isArray(o?.results)?o.results:[];return Ll.delete(t),{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 XT,ZT,Ll,QT,ah,lh=M(()=>{Jt();XT=6e4,ZT=5e3,Ll=new Map,QT=(...t)=>fetch(...t);ah=t=>({authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`})});import q from"node:fs/promises";import tA from"node:os";import tt from"node:path";import{execFile as eA}from"node:child_process";import{promisify as nA}from"node:util";function ai(){return tt.join(Fl,"memory","repos")}function cr(t){return t===qe?tt.join(Fl,"memory",qe):tt.join(ai(),t)}async function ps(t){try{return JSON.parse(await q.readFile(tt.join(t,mh),"utf8"))}catch{return{}}}async function Ul(t,e){let n=await ps(t);for(let[r,o]of e)n[r]=Math.max(Number(n[r])||0,o);await q.mkdir(t,{recursive:!0}),await q.writeFile(tt.join(t,mh),JSON.stringify(n))}function dh(t){let e=String(t||"").trim();if(!e)return null;let r=(e.replace(/\/+$/,"").split(/[/:]/).pop()||"").replace(/\.git$/i,"").toLowerCase();return/^[a-z0-9][a-z0-9._-]*$/.test(r)?r:null}async function fh(t){try{let{stdout:e}=await rA("git",["-C",t,"config","--get","remote.origin.url"]);return e.trim()||null}catch{return null}}async function Hl(t){if(!t)return[];let e=dh(await fh(t));if(e)return[e];let n=[],r=[];try{r=await q.readdir(t,{withFileTypes:!0})}catch{return[]}for(let o of r){if(!o.isDirectory()||o.name.startsWith("."))continue;let s=dh(await fh(tt.join(t,o.name)));s&&!n.includes(s)&&n.push(s)}return n}function ii(t){let e=/^---\n([\s\S]*?)\n---\n?/.exec(t);return e?{fm:e[1],body:t.slice(e[0].length)}:{fm:null,body:t}}function bn(t,e){let n=new RegExp(`^\\s*${e}:\\s*(.+?)\\s*$`,"m").exec(t||"");return n?n[1].replace(/^"|"$/g,""):null}async function Ie(t,e=null){let n=e??await q.readFile(t,"utf8").catch(()=>""),{fm:r}=ii(n),o=bn(r,"modified"),s=o?Date.parse(o):NaN;if(Number.isFinite(s))return s;try{return(await q.stat(t)).mtimeMs}catch{return 0}}function hh(t,e){let n=bn(t,"scope"),r=/^repo:([a-z0-9][a-z0-9._-]*)$/i.exec(n||"");if(r)return r[1].toLowerCase();if((n||"").toLowerCase()===qe){let o=bn(t,"trust");if(!o||/^operator/i.test(o))return qe}return e}function Wl(t,e,n,r=new Map){let o=(t||"").split(`
15
15
  `),s=new Map;for(let c of(e||"").split(`
16
- `)){let l=Lr(c);l&&c.trim().startsWith("-")&&s.set(l,c)}let a=new Set,i=o.map(c=>{let l=Lr(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(`
16
+ `)){let l=zr(c);l&&c.trim().startsWith("-")&&s.set(l,c)}let a=new Set,i=o.map(c=>{let l=zr(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(`
17
17
  `).replace(/\n{3,}/g,`
18
18
 
19
- `)}function Km(t,e){let n=wn(e,"name")||t.replace(/\.md$/,""),r=wn(e,"description")||"";return`- [${n}](${t})${r?` \u2014 ${r}`:""}`}async function ss(t){let e=[];try{e=await F.readdir(t,{withFileTypes:!0})}catch{return[]}return e.filter(n=>n.isFile()&&n.name.endsWith(".md")&&n.name!=="MEMORY.md").map(n=>n.name)}async function Gm(t,e){let n=Z.join(t,".bostrat","memory"),r=await ss(n);if(!r.length)return{harvested:0,changedByKey:new Map};let o=new Map,s=new Map,a=0,i=new Map;for(let l of r){let u=Z.join(n,l),d;try{d=await F.readFile(u,"utf8")}catch{continue}let{fm:f}=Ja(d),p=qm(f,e);if(!p)continue;let m=er(p),w=Z.join(m,l),y=await Ee(u,d);if(i.has(m)||i.set(m,await os(m)),(i.get(m)[l]||0)>=y)continue;let k=await Ee(w).catch(()=>0);if(await F.access(w).then(()=>!0).catch(()=>!1)&&k>=y)continue;await F.mkdir(m,{recursive:!0}),await F.writeFile(w,d),a++;let $=o.get(m);$||o.set(m,$={won:new Set,generated:new Map}),$.won.add(l),$.generated.set(l,Km(l,f)),s.has(p)||s.set(p,new Set),s.get(p).add(l)}let c=await F.readFile(Z.join(n,"MEMORY.md"),"utf8").catch(()=>"");for(let[l,u]of o){let d=Z.join(l,"MEMORY.md"),f=await F.readFile(d,"utf8").catch(()=>"");await F.writeFile(d,Ol(f,c,u.won,u.generated))}return{harvested:a,changedByKey:s}}async function $T(){let t=Z.join(Il,"workspaces"),e=[];try{e=await F.readdir(t,{withFileTypes:!0})}catch{return{harvested:0}}let n=0,r=new Map;for(let o of e){if(!o.isDirectory())continue;let s=Z.join(t,o.name);if(!await F.access(Z.join(s,".bostrat","memory")).then(()=>!0).catch(()=>!1))continue;let[i]=await $l(s),c=await Gm(s,i||null);n+=c.harvested;for(let[l,u]of c.changedByKey){r.has(l)||r.set(l,new Set);for(let d of u)r.get(l).add(d)}}return{harvested:n,changedByKey:r}}async function MT(t,e){let n=er(t),r=await os(n),o=new Set,s=new Map,a=[],i=0;for(let c of e||[]){let l=String(c?.file||"");if(!OT.test(l)||l==="MEMORY.md")continue;let u=Z.join(n,l),d=await F.access(u).then(()=>!0).catch(()=>!1),f=d?await Ee(u):0,p=Number(c.modified)||0;if(c.deleted){p>f&&(d&&await F.rm(u,{force:!0}),await Rl(n,[[l,p]]),d&&(a.push(l),i++));continue}d&&f>=p||(r[l]||0)>=p||(await F.mkdir(n,{recursive:!0}),await F.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=Z.join(n,"MEMORY.md"),l=await F.readFile(c,"utf8").catch(()=>""),u=Ol(l,[...s.values()].join(`
20
- `),o);if(a.length){let d=new Set(a);u=u.split(`
21
- `).filter(f=>!d.has(Lr(f))).join(`
22
- `)}await F.mkdir(n,{recursive:!0}),await F.writeFile(c,u)}return{changed:i,tombstoned:a.length}}async function Cl(t,e=null){let n=er(t),r=e?.length?e:await ss(n);if(!r.length)return{pushed:0,source:"empty"};let o=CT(await F.readFile(Z.join(n,"MEMORY.md"),"utf8").catch(()=>"")),s=[];for(let a of r){let i=Z.join(n,a),c;try{c=await F.readFile(i,"utf8")}catch{continue}s.push({file:a,content:c,modified:await Ee(i,c),indexLine:o.get(a)??null})}return Va(t,s)}async function PT(t){let{facts:e,source:n}=await Dm(t);e.length?await MT(t,e):n==="plane"&&await Cl(t)}function NT(t){let e=t.split(`
23
- `);e.length>Lm&&(e=e.slice(0,Lm));let n=e.join(`
24
- `);for(;Buffer.byteLength(n,"utf8")>RT&&e.length;)e.pop(),n=e.join(`
25
- `);return n}async function DT(t,e){if(!t||!e?.length)return{materialized:!1,reason:"no-repo-key"};let n=Z.join(t,".bostrat","memory"),r=0,o=0,s=[];for(let u of e){let d=er(u),f=await os(d);for(let[y,k]of Object.entries(f)){let S=Z.join(n,y);await F.access(S).then(()=>!0).catch(()=>!1)&&await Ee(S)<=k&&(await F.rm(S,{force:!0}),o++)}let p=await ss(d);if(!p.length)continue;await F.mkdir(n,{recursive:!0});for(let y of p){let k=Z.join(d,y),S=Z.join(n,y),$=await Ee(k),R=await Ee(S).catch(()=>0);await F.access(S).then(()=>!0).catch(()=>!1)&&R>=$||(await F.copyFile(k,S),r++)}let m=await F.readFile(Z.join(d,"MEMORY.md"),"utf8").catch(()=>""),w=u===He?"## operator memory":`## repo: ${u}`;m.trim()&&s.push(e.length>1?`${w}
19
+ `)}function wh(t,e){let n=bn(e,"name")||t.replace(/\.md$/,""),r=bn(e,"description")||"";return`- [${n}](${t})${r?` \u2014 ${r}`:""}`}async function ms(t){let e=[];try{e=await q.readdir(t,{withFileTypes:!0})}catch{return[]}return e.filter(n=>n.isFile()&&n.name.endsWith(".md")&&n.name!=="MEMORY.md").map(n=>n.name)}async function gh(t,e){let n=tt.join(t,".bostrat","memory"),r=await ms(n);if(!r.length)return{harvested:0,changedByKey:new Map};let o=new Map,s=new Map,a=0,i=new Map;for(let l of r){let u=tt.join(n,l),f;try{f=await q.readFile(u,"utf8")}catch{continue}let{fm:d}=ii(f),p=hh(d,e);if(!p)continue;let h=cr(p),w=tt.join(h,l),y=await Ie(u,f);if(i.has(h)||i.set(h,await ps(h)),(i.get(h)[l]||0)>=y)continue;let k=await Ie(w).catch(()=>0);if(await q.access(w).then(()=>!0).catch(()=>!1)&&k>=y)continue;await q.mkdir(h,{recursive:!0}),await q.writeFile(w,f),a++;let E=o.get(h);E||o.set(h,E={won:new Set,generated:new Map}),E.won.add(l),E.generated.set(l,wh(l,d)),s.has(p)||s.set(p,new Set),s.get(p).add(l)}let c=await q.readFile(tt.join(n,"MEMORY.md"),"utf8").catch(()=>"");for(let[l,u]of o){let f=tt.join(l,"MEMORY.md"),d=await q.readFile(f,"utf8").catch(()=>"");await q.writeFile(f,Wl(d,c,u.won,u.generated))}return{harvested:a,changedByKey:s}}async function sA(){let t=tt.join(Fl,"workspaces"),e=[];try{e=await q.readdir(t,{withFileTypes:!0})}catch{return{harvested:0}}let n=0,r=new Map;for(let o of e){if(!o.isDirectory())continue;let s=tt.join(t,o.name);if(!await q.access(tt.join(s,".bostrat","memory")).then(()=>!0).catch(()=>!1))continue;let[i]=await Hl(s),c=await gh(s,i||null);n+=c.harvested;for(let[l,u]of c.changedByKey){r.has(l)||r.set(l,new Set);for(let f of u)r.get(l).add(f)}}return{harvested:n,changedByKey:r}}async function cA(t,e){let n=cr(t),r=await ps(n),o=new Set,s=new Map,a=[],i=0;for(let c of e||[]){let l=String(c?.file||"");if(!aA.test(l)||l==="MEMORY.md")continue;let u=tt.join(n,l),f=await q.access(u).then(()=>!0).catch(()=>!1),d=f?await Ie(u):0,p=Number(c.modified)||0;if(c.deleted){p>d&&(f&&await q.rm(u,{force:!0}),await Ul(n,[[l,p]]),f&&(a.push(l),i++));continue}f&&d>=p||(r[l]||0)>=p||(await q.mkdir(n,{recursive:!0}),await q.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=tt.join(n,"MEMORY.md"),l=await q.readFile(c,"utf8").catch(()=>""),u=Wl(l,[...s.values()].join(`
20
+ `),o);if(a.length){let f=new Set(a);u=u.split(`
21
+ `).filter(d=>!f.has(zr(d))).join(`
22
+ `)}await q.mkdir(n,{recursive:!0}),await q.writeFile(c,u)}return{changed:i,tombstoned:a.length}}async function ql(t,e=null){let n=cr(t),r=e?.length?e:await ms(n);if(!r.length)return{pushed:0,source:"empty"};let o=iA(await q.readFile(tt.join(n,"MEMORY.md"),"utf8").catch(()=>"")),s=[];for(let a of r){let i=tt.join(n,a),c;try{c=await q.readFile(i,"utf8")}catch{continue}s.push({file:a,content:c,modified:await Ie(i,c),indexLine:o.get(a)??null})}return si(t,s)}async function lA(t){let{facts:e,source:n}=await ch(t);e.length?await cA(t,e):n==="plane"&&await ql(t)}function uA(t){let e=t.split(`
23
+ `);e.length>uh&&(e=e.slice(0,uh));let n=e.join(`
24
+ `);for(;Buffer.byteLength(n,"utf8")>oA&&e.length;)e.pop(),n=e.join(`
25
+ `);return n}async function fA(t,e){if(!t||!e?.length)return{materialized:!1,reason:"no-repo-key"};let n=tt.join(t,".bostrat","memory"),r=0,o=0,s=[];for(let u of e){let f=cr(u),d=await ps(f);for(let[y,k]of Object.entries(d)){let x=tt.join(n,y);await q.access(x).then(()=>!0).catch(()=>!1)&&await Ie(x)<=k&&(await q.rm(x,{force:!0}),o++)}let p=await ms(f);if(!p.length)continue;await q.mkdir(n,{recursive:!0});for(let y of p){let k=tt.join(f,y),x=tt.join(n,y),E=await Ie(k),O=await Ie(x).catch(()=>0);await q.access(x).then(()=>!0).catch(()=>!1)&&O>=E||(await q.copyFile(k,x),r++)}let h=await q.readFile(tt.join(f,"MEMORY.md"),"utf8").catch(()=>""),w=u===qe?"## operator memory":`## repo: ${u}`;h.trim()&&s.push(e.length>1?`${w}
26
26
 
27
- ${m.trim()}`:m.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(`
27
+ ${h.trim()}`:h.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(`
28
28
 
29
29
  `)+`
30
- `,c=NT(i);await F.mkdir(n,{recursive:!0}),await F.writeFile(Z.join(n,"MEMORY.md"),c);let l=Z.join(n,"claude");return await F.mkdir(l,{recursive:!0}),await F.writeFile(Z.join(l,"MEMORY.md"),BT,{flag:"wx"}).catch(()=>{}),{materialized:!0,facts:r,capped:c!==i}}async function Vm(t){try{let e=await $l(t);if(!e.length)return{materialized:!1,reason:"no-repo-key"};let n=[...e,He];if(Date.now()-Hm>jT){Hm=Date.now(),await LT();let{changedByKey:r}=await $T();for(let[o,s]of r)await Cl(o,[...s])}for(let r of n)await PT(r);return await DT(t,n)}catch(e){return{materialized:!1,reason:"error",error:e?.message||String(e)}}}async function LT(){let t=0,e=[];try{e=await F.readdir(za(),{withFileTypes:!0})}catch{return{moved:t}}for(let n of e){if(!n.isDirectory())continue;let r=Z.join(za(),n.name),o=er(He),s=new Set,a=new Map;for(let p of await ss(r)){let m=Z.join(r,p),w;try{w=await F.readFile(m,"utf8")}catch{continue}let{fm:y}=Ja(w);if(qm(y,n.name)!==He)continue;let k=Z.join(o,p),S=await Ee(k).catch(()=>0),$=await Ee(m,w);await F.mkdir(o,{recursive:!0}),$>S&&await F.writeFile(k,w),await F.rm(m,{force:!0}),s.add(p),a.set(p,Km(p,y)),t++}if(!s.size)continue;let i=Date.now();await Rl(r,[...s].map(p=>[p,i])),await Va(n.name,[...s].map(p=>({file:p,deleted:!0,modified:i})));let c=Z.join(r,"MEMORY.md"),l=await F.readFile(c,"utf8").catch(()=>""),u=l.split(`
31
- `).filter(p=>!s.has(Lr(p))).join(`
32
- `);await F.writeFile(c,u).catch(()=>{});let d=Z.join(o,"MEMORY.md"),f=await F.readFile(d,"utf8").catch(()=>"");await F.writeFile(d,Ol(f,l,s,a))}return{moved:t}}async function zm(){let t=[],e=[He];try{for(let n of await F.readdir(za(),{withFileTypes:!0}))n.isDirectory()&&e.push(n.name)}catch{}for(let n of e){let r=er(n),o=await ss(r),s=await os(r);if(!o.length&&!Object.keys(s).length)continue;let a=[];for(let i of o){let c=await F.readFile(Z.join(r,i),"utf8").catch(()=>""),{fm:l}=Ja(c);a.push({file:i,name:wn(l,"name")||i.replace(/\.md$/,""),description:wn(l,"description")||"",scope:wn(l,"scope")||null,modified:await Ee(Z.join(r,i),c)})}t.push({key:n,facts:a,tombstones:Object.keys(s).length})}return t}async function Jm(t,e){if(!/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/.test(e)||e==="MEMORY.md")throw new Error("bad fact filename");let n=er(t),r=Z.join(n,e);if(!await F.access(r).then(()=>!0).catch(()=>!1))throw new Error(`fact ${e} not found in ${t}`);let s=Date.now();await F.rm(r,{force:!0}),await Rl(n,[[e,s]]);let a=Z.join(n,"MEMORY.md"),i=await F.readFile(a,"utf8").catch(()=>"");await F.writeFile(a,i.split(`
33
- `).filter(l=>Lr(l)!==e).join(`
34
- `)).catch(()=>{});let c=await Va(t,[{file:e,deleted:!0,modified:s}]);return{deleted:e,key:t,plane:c.source}}async function Ym(t){try{let e=await $l(t),{harvested:n,changedByKey:r}=await Gm(t,e[0]||null);for(let[o,s]of r)await Cl(o,[...s]);return{harvested:n}}catch(e){return{harvested:0,error:e?.message||String(e)}}}var IT,Il,Lm,RT,He,Wm,Lr,OT,CT,BT,Hm,jT,Ya=M(()=>{jm();IT=_T(ET),Il=process.env.BOSTRAT_STATE_DIR||Z.join(process.env.HOME||AT.tmpdir(),".bostrat"),Lm=200,RT=25*1024;He="operator";Wm=".tombstones.json";Lr=t=>/\]\(([^)]+\.md)\)/.exec(t)?.[1]||null;OT=/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/,CT=t=>{let e=new Map;for(let n of(t||"").split(`
35
- `)){let r=Lr(n);r&&n.trim().startsWith("-")&&e.set(r,n)}return e};BT=`# Track memory
30
+ `,c=uA(i);await q.mkdir(n,{recursive:!0}),await q.writeFile(tt.join(n,"MEMORY.md"),c);let l=tt.join(n,"claude");return await q.mkdir(l,{recursive:!0}),await q.writeFile(tt.join(l,"MEMORY.md"),dA,{flag:"wx"}).catch(()=>{}),{materialized:!0,facts:r,capped:c!==i}}async function yh(t){try{let e=await Hl(t);if(!e.length)return{materialized:!1,reason:"no-repo-key"};let n=[...e,qe];if(Date.now()-ph>pA){ph=Date.now(),await mA();let{changedByKey:r}=await sA();for(let[o,s]of r)await ql(o,[...s])}for(let r of n)await lA(r);return await fA(t,n)}catch(e){return{materialized:!1,reason:"error",error:e?.message||String(e)}}}async function mA(){let t=0,e=[];try{e=await q.readdir(ai(),{withFileTypes:!0})}catch{return{moved:t}}for(let n of e){if(!n.isDirectory())continue;let r=tt.join(ai(),n.name),o=cr(qe),s=new Set,a=new Map;for(let p of await ms(r)){let h=tt.join(r,p),w;try{w=await q.readFile(h,"utf8")}catch{continue}let{fm:y}=ii(w);if(hh(y,n.name)!==qe)continue;let k=tt.join(o,p),x=await Ie(k).catch(()=>0),E=await Ie(h,w);await q.mkdir(o,{recursive:!0}),E>x&&await q.writeFile(k,w),await q.rm(h,{force:!0}),s.add(p),a.set(p,wh(p,y)),t++}if(!s.size)continue;let i=Date.now();await Ul(r,[...s].map(p=>[p,i])),await si(n.name,[...s].map(p=>({file:p,deleted:!0,modified:i})));let c=tt.join(r,"MEMORY.md"),l=await q.readFile(c,"utf8").catch(()=>""),u=l.split(`
31
+ `).filter(p=>!s.has(zr(p))).join(`
32
+ `);await q.writeFile(c,u).catch(()=>{});let f=tt.join(o,"MEMORY.md"),d=await q.readFile(f,"utf8").catch(()=>"");await q.writeFile(f,Wl(d,l,s,a))}return{moved:t}}async function bh(){let t=[],e=[qe];try{for(let n of await q.readdir(ai(),{withFileTypes:!0}))n.isDirectory()&&e.push(n.name)}catch{}for(let n of e){let r=cr(n),o=await ms(r),s=await ps(r);if(!o.length&&!Object.keys(s).length)continue;let a=[];for(let i of o){let c=await q.readFile(tt.join(r,i),"utf8").catch(()=>""),{fm:l}=ii(c);a.push({file:i,name:bn(l,"name")||i.replace(/\.md$/,""),description:bn(l,"description")||"",scope:bn(l,"scope")||null,modified:await Ie(tt.join(r,i),c)})}t.push({key:n,facts:a,tombstones:Object.keys(s).length})}return t}async function kh(t,e){if(!/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/.test(e)||e==="MEMORY.md")throw new Error("bad fact filename");let n=cr(t),r=tt.join(n,e);if(!await q.access(r).then(()=>!0).catch(()=>!1))throw new Error(`fact ${e} not found in ${t}`);let s=Date.now();await q.rm(r,{force:!0}),await Ul(n,[[e,s]]);let a=tt.join(n,"MEMORY.md"),i=await q.readFile(a,"utf8").catch(()=>"");await q.writeFile(a,i.split(`
33
+ `).filter(l=>zr(l)!==e).join(`
34
+ `)).catch(()=>{});let c=await si(t,[{file:e,deleted:!0,modified:s}]);return{deleted:e,key:t,plane:c.source}}async function xh(t){try{let e=await Hl(t),{harvested:n,changedByKey:r}=await gh(t,e[0]||null);for(let[o,s]of r)await ql(o,[...s]);return{harvested:n}}catch(e){return{harvested:0,error:e?.message||String(e)}}}var rA,Fl,uh,oA,qe,mh,zr,aA,iA,dA,ph,pA,ci=M(()=>{lh();rA=nA(eA),Fl=process.env.BOSTRAT_STATE_DIR||tt.join(process.env.HOME||tA.tmpdir(),".bostrat"),uh=200,oA=25*1024;qe="operator";mh=".tombstones.json";zr=t=>/\]\(([^)]+\.md)\)/.exec(t)?.[1]||null;aA=/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/,iA=t=>{let e=new Map;for(let n of(t||"").split(`
35
+ `)){let r=zr(n);r&&n.trim().startsWith("-")&&e.set(r,n)}return e};dA=`# Track memory
36
36
 
37
37
  Shared Track memory (all providers) lives one level up: read \`../MEMORY.md\` for the
38
38
  index and the fact files beside it. Facts you save here stay Claude-local but ride the
39
39
  same sync; prefer adding durable cross-provider facts to \`../\` following its format.
40
- `;Hm=0,jT=3e4});import Ml from"node:fs/promises";import FT from"node:path";async function zt(t,e,{mode:n}={}){await Ml.mkdir(FT.dirname(t),{recursive:!0});let r=`${t}.${process.pid}.${++UT}.tmp`;await Ml.writeFile(r,JSON.stringify(e,null,2)+`
41
- `,n!=null?{mode:n}:void 0),await Ml.rename(r,t)}var UT,gn=M(()=>{UT=0});import eh from"node:fs/promises";import nh from"node:os";import rh from"node:path";function wt(t=process.env){return!!(vt(t)&&t.BOSTRAT_PLANE_TOKEN)}async function cs(t,e={},n=process.env){let r=new AbortController,o=setTimeout(()=>r.abort(),HT);try{return await zT(`${vt(n)}${t}`,{...e,signal:r.signal})}finally{clearTimeout(o)}}async function sh(){return Za||(Pl||=eh.readFile(oh(),"utf8").then(t=>JSON.parse(t)).catch(()=>({ops:[]})).then(t=>Za={ops:Array.isArray(t?.ops)?t.ops:[],parked:Array.isArray(t?.parked)?t.parked:[]}).finally(()=>Pl=null),Pl)}async function Qa(){await zt(oh(),Za).catch(()=>{})}function Qm(t){return t.op==="blob"?`blob ${t.family} ${t.id} ${t.v} ${t.kind}`:`${t.op} ${t.family} ${t.id}`}async function Bl(t){let e=await sh(),n=Qm(t);if(t.op==="delete")e.ops=e.ops.filter(r=>!(r.family===t.family&&r.id===t.id)),e.ops.push(t);else{e.ops=e.ops.filter(o=>!(o.op==="delete"&&o.family===t.family&&o.id===t.id));let r=e.ops.findIndex(o=>Qm(o)===n);r>=0?e.ops[r]=t:e.ops.push(t)}e.ops.length>Xm&&(e.ops=e.ops.slice(-Xm)),await Qa()}function th(){Xa||(Xa=setTimeout(()=>{Xa=null,Fr().catch(()=>{})},JT),Xa.unref?.())}function Nl(t){let e=new Error(`plane ${t}`);return e.refused=!0,e}async function XT(t,e=process.env){if(t.op==="record"){let n=await cs(`/v1/content/${encodeURIComponent(t.family)}`,{method:"POST",headers:{...is(e),"content-type":"application/json"},body:JSON.stringify({records:[{id:t.id,trackId:t.trackId??null,data:t.data,updatedAt:t.updatedAt,originNode:VT()}]})},e);if(!n.ok)throw Nl(n.status);let o=(await n.json().catch(()=>null))?.results?.[0];return o?.outcome==="rejected"?{delivered:!1,rejected:o.reason}:{delivered:!0}}if(t.op==="blob"){let n=await eh.readFile(t.path).catch(()=>null);if(!n)return{delivered:!0,dropped:"source file gone"};let r=await cs(`/v1/content/${encodeURIComponent(t.family)}/${encodeURIComponent(t.id)}/blob?v=${t.v}&kind=${encodeURIComponent(t.kind)}`,{method:"POST",headers:{...is(e),"content-type":"application/octet-stream"},body:n},e);if(!r.ok&&r.status!==400)throw Nl(r.status);return r.status===400?{delivered:!1,rejected:(await r.json().catch(()=>null))?.error||"rejected"}:{delivered:!0}}if(t.op==="delete"){let n=await cs(`/v1/content/${encodeURIComponent(t.family)}/${encodeURIComponent(t.id)}?deletedAt=${t.deletedAt}`,{method:"DELETE",headers:is(e)},e);if(!n.ok)throw Nl(n.status);return{delivered:!0}}return{delivered:!0,dropped:"unknown op"}}async function Fr({env:t=process.env,log:e=console,now:n=Date.now()}={}){return wt(t)?as||(as=(async()=>{let r=await sh();ZT(r,n);let o=0,s=0;for(;r.ops.length;){let a=r.ops[0],i;try{i=await XT(a,t)}catch(c){if(!c?.refused)return th(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};if(a.refusals=(a.refusals||0)+1,a.refusals<qT)return th(),await Qa(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};e.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>Zm&&(r.parked=r.parked.slice(-Zm)),s++,await Qa();continue}i.rejected&&e.error?.(`[content-plane] ALARM plane rejected ${a.op} ${a.family}/${a.id}: ${i.rejected}`),r.ops.shift(),o++,await Qa()}return{flushed:o,parked:s,pending:0}})().finally(()=>{as=null}),as):{flushed:0,source:"unconfigured"}}function ZT(t,e){if(!t.parked.length||t.ops.length)return;let n=t.parked.filter(r=>e-(r.parkedAt||0)>=YT);if(n.length){t.parked=t.parked.filter(r=>!n.includes(r));for(let r of n)t.ops.push({...r,refusals:0,parkedAt:void 0,error:void 0})}}async function Ut(t,e,{trackId:n=null,env:r=process.env}={}){return wt(r)?(await Bl({op:"record",family:t,id:e.id,trackId:n??e.trackId??null,data:e,updatedAt:Number(e.updatedAt)||Date.now()}),Fr({env:r})):{queued:!1,source:"unconfigured"}}async function yn(t,e,n,r,o,{env:s=process.env}={}){return wt(s)?(await Bl({op:"blob",family:t,id:e,v:Number(n),kind:r,path:o}),Fr({env:s})):{queued:!1,source:"unconfigured"}}async function me(t,e,{deletedAt:n=Date.now(),env:r=process.env}={}){return wt(r)?(await Bl({op:"delete",family:t,id:e,deletedAt:n}),Fr({env:r})):{queued:!1,source:"unconfigured"}}async function $t(t,{env:e=process.env}={}){if(!wt(e))return{records:[],source:"unconfigured"};try{let n=await cs(`/v1/content/${encodeURIComponent(t)}?tombstones=1`,{headers:is(e)},e);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 ls(t,e,n,r,{env:o=process.env}={}){if(!wt(o))return null;try{let s=await cs(`/v1/content/${encodeURIComponent(t)}/${encodeURIComponent(e)}/blob?v=${Number(n)}&kind=${encodeURIComponent(r)}`,{headers:is(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 HT,WT,Xm,qT,Zm,KT,GT,oh,VT,zT,JT,YT,is,Za,Pl,Xa,as,bn=M(()=>{Qt();gn();HT=1e4,WT=3e4,Xm=2e3,qT=5,Zm=100,KT=60*6e4,GT=()=>process.env.BOSTRAT_STATE_DIR||rh.join(process.env.HOME||nh.tmpdir(),".bostrat"),oh=()=>rh.join(GT(),"content-outbox.json"),VT=()=>process.env.BOSTRAT_NODE_ID||nh.hostname(),zT=(...t)=>fetch(...t),JT=WT,YT=KT;is=(t=process.env)=>({authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`});Za=null,Pl=null,Xa=null,as=null});import Dl from"node:fs/promises";import ah from"node:path";async function ih(t,e,{box:n=null,agent:r=null}={}){if(!t||!wt())return{pushed:!1};try{let o=Date.now();return await Ut("checkpoints",{id:t,trackId:t,v:o,box:n,agent:r,updatedAt:o},{trackId:t}),await yn("checkpoints",t,o,"md",e),{pushed:!0,v:o}}catch{return{pushed:!1}}}async function ch(t){try{let e=eA(t);if(!e||!wt())return{restored:!1};let n=ah.join(t,QT,tA);if(await Dl.stat(n).then(()=>!0,()=>!1))return{restored:!1};let{records:r,source:o}=await $t("checkpoints");if(o!=="plane")return{restored:!1};let s=r.find(i=>!i.deletedAt&&i.data?.id===e);if(!s?.data?.v)return{restored:!1};let a=await ls("checkpoints",e,s.data.v,"md");return typeof a!="string"||!a?{restored:!1}:(await Dl.mkdir(ah.dirname(n),{recursive:!0}),await Dl.writeFile(n,a),{restored:!0,v:s.data.v})}catch{return{restored:!1}}}var QT,tA,eA,jl=M(()=>{bn();QT=".bostrat/handoff",tA="latest.md",eA=t=>/workspaces[/\\]([0-9a-f]{8})$/.exec(t||"")?.[1]??null});import us from"node:fs/promises";import nA from"node:os";import uh from"node:path";function nr(t){let e=String(t??"");for(let n of rA)e=e.replace(n,"\u2039redacted\u203A");return e}function ti(){let t=process.env.BOSTRAT_HANDOFF_DEBUG;return t==="1"||t==="true"}async function oA(t){try{await us.mkdir(Ll,{recursive:!0}),await us.appendFile(Ur,`${JSON.stringify(t)}
42
- `,"utf8");let n=(await us.readFile(Ur,"utf8")).split(`
43
- `).filter(Boolean);n.length>lh&&await us.writeFile(Ur,`${n.slice(-lh).join(`
40
+ `;ph=0,pA=3e4});import Kl from"node:fs/promises";import hA from"node:path";async function Yt(t,e,{mode:n}={}){await Kl.mkdir(hA.dirname(t),{recursive:!0});let r=`${t}.${process.pid}.${++wA}.tmp`;await Kl.writeFile(r,JSON.stringify(e,null,2)+`
41
+ `,n!=null?{mode:n}:void 0),await Kl.rename(r,t)}var wA,kn=M(()=>{wA=0});import Eh from"node:fs/promises";import _h from"node:os";import Ih from"node:path";function vt(t=process.env){return!!(St(t)&&t.BOSTRAT_PLANE_TOKEN)}async function gs(t,e={},n=process.env){let r=new AbortController,o=setTimeout(()=>r.abort(),gA);try{return await vA(`${St(n)}${t}`,{...e,signal:r.signal})}finally{clearTimeout(o)}}async function $h(){return ui||(Gl||=Eh.readFile(Rh(),"utf8").then(t=>JSON.parse(t)).catch(()=>({ops:[]})).then(t=>ui={ops:Array.isArray(t?.ops)?t.ops:[],parked:Array.isArray(t?.parked)?t.parked:[]}).finally(()=>Gl=null),Gl)}async function di(){await Yt(Rh(),ui).catch(()=>{})}function Th(t){return t.op==="blob"?`blob ${t.family} ${t.id} ${t.v} ${t.kind}`:`${t.op} ${t.family} ${t.id}`}async function zl(t){let e=await $h(),n=Th(t);if(t.op==="delete")e.ops=e.ops.filter(r=>!(r.family===t.family&&r.id===t.id)),e.ops.push(t);else{e.ops=e.ops.filter(o=>!(o.op==="delete"&&o.family===t.family&&o.id===t.id));let r=e.ops.findIndex(o=>Th(o)===n);r>=0?e.ops[r]=t:e.ops.push(t)}e.ops.length>Sh&&(e.ops=e.ops.slice(-Sh)),await di()}function Ah(){li||(li=setTimeout(()=>{li=null,Jr().catch(()=>{})},TA),li.unref?.())}function Vl(t){let e=new Error(`plane ${t}`);return e.refused=!0,e}async function EA(t,e=process.env){if(t.op==="record"){let n=await gs(`/v1/content/${encodeURIComponent(t.family)}`,{method:"POST",headers:{...ws(e),"content-type":"application/json"},body:JSON.stringify({records:[{id:t.id,trackId:t.trackId??null,data:t.data,updatedAt:t.updatedAt,originNode:SA()}]})},e);if(!n.ok)throw Vl(n.status);let o=(await n.json().catch(()=>null))?.results?.[0];return o?.outcome==="rejected"?{delivered:!1,rejected:o.reason}:{delivered:!0}}if(t.op==="blob"){let n=await Eh.readFile(t.path).catch(()=>null);if(!n)return{delivered:!0,dropped:"source file gone"};let r=await gs(`/v1/content/${encodeURIComponent(t.family)}/${encodeURIComponent(t.id)}/blob?v=${t.v}&kind=${encodeURIComponent(t.kind)}`,{method:"POST",headers:{...ws(e),"content-type":"application/octet-stream"},body:n},e);if(!r.ok&&r.status!==400)throw Vl(r.status);return r.status===400?{delivered:!1,rejected:(await r.json().catch(()=>null))?.error||"rejected"}:{delivered:!0}}if(t.op==="delete"){let n=await gs(`/v1/content/${encodeURIComponent(t.family)}/${encodeURIComponent(t.id)}?deletedAt=${t.deletedAt}`,{method:"DELETE",headers:ws(e)},e);if(!n.ok)throw Vl(n.status);return{delivered:!0}}return{delivered:!0,dropped:"unknown op"}}async function Jr({env:t=process.env,log:e=console,now:n=Date.now()}={}){return vt(t)?hs||(hs=(async()=>{let r=await $h();_A(r,n);let o=0,s=0;for(;r.ops.length;){let a=r.ops[0],i;try{i=await EA(a,t)}catch(c){if(!c?.refused)return Ah(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};if(a.refusals=(a.refusals||0)+1,a.refusals<bA)return Ah(),await di(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};e.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>vh&&(r.parked=r.parked.slice(-vh)),s++,await di();continue}i.rejected&&e.error?.(`[content-plane] ALARM plane rejected ${a.op} ${a.family}/${a.id}: ${i.rejected}`),r.ops.shift(),o++,await di()}return{flushed:o,parked:s,pending:0}})().finally(()=>{hs=null}),hs):{flushed:0,source:"unconfigured"}}function _A(t,e){if(!t.parked.length||t.ops.length)return;let n=t.parked.filter(r=>e-(r.parkedAt||0)>=AA);if(n.length){t.parked=t.parked.filter(r=>!n.includes(r));for(let r of n)t.ops.push({...r,refusals:0,parkedAt:void 0,error:void 0})}}async function Wt(t,e,{trackId:n=null,env:r=process.env}={}){return vt(r)?(await zl({op:"record",family:t,id:e.id,trackId:n??e.trackId??null,data:e,updatedAt:Number(e.updatedAt)||Date.now()}),Jr({env:r})):{queued:!1,source:"unconfigured"}}async function xn(t,e,n,r,o,{env:s=process.env}={}){return vt(s)?(await zl({op:"blob",family:t,id:e,v:Number(n),kind:r,path:o}),Jr({env:s})):{queued:!1,source:"unconfigured"}}async function we(t,e,{deletedAt:n=Date.now(),env:r=process.env}={}){return vt(r)?(await zl({op:"delete",family:t,id:e,deletedAt:n}),Jr({env:r})):{queued:!1,source:"unconfigured"}}async function Mt(t,{env:e=process.env}={}){if(!vt(e))return{records:[],source:"unconfigured"};try{let n=await gs(`/v1/content/${encodeURIComponent(t)}?tombstones=1`,{headers:ws(e)},e);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 ys(t,e,n,r,{env:o=process.env}={}){if(!vt(o))return null;try{let s=await gs(`/v1/content/${encodeURIComponent(t)}/${encodeURIComponent(e)}/blob?v=${Number(n)}&kind=${encodeURIComponent(r)}`,{headers:ws(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 gA,yA,Sh,bA,vh,kA,xA,Rh,SA,vA,TA,AA,ws,ui,Gl,li,hs,Sn=M(()=>{Jt();kn();gA=1e4,yA=3e4,Sh=2e3,bA=5,vh=100,kA=60*6e4,xA=()=>process.env.BOSTRAT_STATE_DIR||Ih.join(process.env.HOME||_h.tmpdir(),".bostrat"),Rh=()=>Ih.join(xA(),"content-outbox.json"),SA=()=>process.env.BOSTRAT_NODE_ID||_h.hostname(),vA=(...t)=>fetch(...t),TA=yA,AA=kA;ws=(t=process.env)=>({authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`});ui=null,Gl=null,li=null,hs=null});import Jl from"node:fs/promises";import Oh from"node:path";async function Ch(t,e,{box:n=null,agent:r=null}={}){if(!t||!vt())return{pushed:!1};try{let o=Date.now();return await Wt("checkpoints",{id:t,trackId:t,v:o,box:n,agent:r,updatedAt:o},{trackId:t}),await xn("checkpoints",t,o,"md",e),{pushed:!0,v:o}}catch{return{pushed:!1}}}async function fi(t){try{let e=$A(t);if(!e||!vt())return{restored:!1};let n=Oh.join(t,IA,RA);if(await Jl.stat(n).then(()=>!0,()=>!1))return{restored:!1};let{records:r,source:o}=await Mt("checkpoints");if(o!=="plane")return{restored:!1};let s=r.find(i=>!i.deletedAt&&i.data?.id===e);if(!s?.data?.v)return{restored:!1};let a=await ys("checkpoints",e,s.data.v,"md");return typeof a!="string"||!a?{restored:!1}:(await Jl.mkdir(Oh.dirname(n),{recursive:!0}),await Jl.writeFile(n,a),{restored:!0,v:s.data.v})}catch{return{restored:!1}}}var IA,RA,$A,pi=M(()=>{Sn();IA=".bostrat/handoff",RA="latest.md",$A=t=>/workspaces[/\\]([0-9a-f]{8})$/.exec(t||"")?.[1]??null});import bs from"node:fs/promises";import OA from"node:os";import Nh from"node:path";function lr(t){let e=String(t??"");for(let n of CA)e=e.replace(n,"\u2039redacted\u203A");return e}function mi(){let t=process.env.BOSTRAT_HANDOFF_DEBUG;return t==="1"||t==="true"}async function MA(t){try{await bs.mkdir(Yl,{recursive:!0}),await bs.appendFile(Yr,`${JSON.stringify(t)}
42
+ `,"utf8");let n=(await bs.readFile(Yr,"utf8")).split(`
43
+ `).filter(Boolean);n.length>Mh&&await bs.writeFile(Yr,`${n.slice(-Mh).join(`
44
44
  `)}
45
- `,"utf8")}catch(e){console.warn(`[handoff-debug] failed to write ${Ur}: ${e?.message||e}`)}}async function G(t={}){let e={at:new Date().toISOString(),ts:Date.now(),...t},n=[e.flow||"handoff",e.phase||e.step||"?",e.trackId?`track=${e.trackId}`:"",e.sessionName?`box=${e.sessionName}`:"",e.error?`ERR=${e.error}`:""].filter(Boolean).join(" \xB7 ");if(console.log(`[handoff-debug] ${n}`),e.sessionName&&ti())try{e.paneTail=nr((await yt(e.sessionName,{lines:35})).slice(-4e3))}catch{e.paneTail=null}(ti()||e.error||/^(checkpoint|spawn|hydrate|commit|done|summarize|clear|resume|ready|send|failed|launch)/.test(String(e.phase||e.step||"")))&&await oA(e)}async function dh({limit:t=80}={}){try{return(await us.readFile(Ur,"utf8")).split(`
46
- `).filter(Boolean).slice(-t).map(r=>{try{let o=JSON.parse(r);return typeof o?.paneTail=="string"&&(o.paneTail=nr(o.paneTail)),o}catch{return{raw:nr(r)}}})}catch{return[]}}var rA,Ll,Ur,lh,fh,We=M(()=>{Ht();rA=[/[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];Ll=process.env.BOSTRAT_DEBUG_DIR||uh.join(nA.homedir(),".bostrat","debug"),Ur=uh.join(Ll,"handoff.jsonl"),lh=Number(process.env.BOSTRAT_HANDOFF_DEBUG_MAX)||500;fh={DEBUG_DIR:Ll,LOG_FILE:Ur}});import{execFile as sA}from"node:child_process";import{promisify as aA}from"node:util";import ni from"node:fs";import{randomUUID as iA}from"node:crypto";function qr(t){return new Promise(e=>setTimeout(e,t))}function ei(t,e){if(!e)return t;let n=o=>typeof o=="string"?o.split(e).join("<redacted>"):o,r=new Error(n(t?.message)||"command failed");return t?.code!==void 0&&(r.code=t.code),t?.stderr!==void 0&&(r.stderr=n(t.stderr)),r}function mh(t){return`/tmp/tmux-${t}/default`}function cA({explicit:t,legacyExists:e,runtimeDir:n,uid:r}){if(t)return t;let o=mh(r);return e?o:n?`${n}/bostrat/tmux-default`:o}function Hl(){return process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1"?[]:["-e",`${uA}=1`]}function ql(t,e,n){let r=rr(t),o=/(^|\s)(--session-id|--resume|--continue|-r|-c)(\s|=|$)/.test(t);if(!r||o)return t;let s=`${t} --session-id ${e}`,a=/(^|\s)(--name|-n)(\s|=)/.test(t);return n&&!a&&bt(n)&&(s+=` --name ${n}`),s}function rr(t){return/(^|\/|\s)claude(\s|$)/.test(String(t||""))}function kn(t){return/(^|\/|\s)claude(\s|$)/.test(t)?"claude":/cursor/.test(t)?"cursor":/codex/.test(t)?"codex":/gemini/.test(t)?"gemini":"agent"}function fA(t){let e=String(t||"").trim();return!e||/fake-|\.sh(\s|$)/.test(e)?!1:rr(e)||/(^|\/|\s)codex(\s|$)/.test(e)||/cursor-agent/.test(e)||/(^|\/|\s)gemini(\s|$)/.test(e)}async function hh(t,{loginShell:e=!1,failOpen:n=!1}={}){let r=await wh(t,{loginShell:e});return r===ri?!0:r===Hr?!1:n}async function wh(t,{loginShell:e=!1,timeoutMs:n=Fl}={}){if(!t)return Hr;let r=e?process.env.SHELL||"/bin/sh":"sh",o=e?"-lic":"-c";try{return await lt(r,[o,'command -v "$1" >/dev/null 2>&1',"_",t],{timeout:n}),ri}catch(s){return s?.killed||s?.signal?Wr:s?.code===1||s?.code===127?Hr:Wr}}async function oi(t,{retries:e=pA,sleep:n=mA,probe:r=wh}={}){let o=String(t||"").trim().split(/\s+/)[0],s=await r(o,{timeoutMs:Fl});for(let a=0;s===Wr&&a<e.length;a++)await n(e[a]),s=await r(o,{timeoutMs:Fl*2});return s}function j(...t){return["-S",te,...t]}async function xn(){if(!ni.existsSync(te))return!1;try{return await lt(B,j("list-sessions")),!0}catch(t){let e=t&&t.stderr?String(t.stderr):"";return!/no server running/i.test(e)}}async function ds(){if(await xn())return!0;try{ni.mkdirSync(te.replace(/\/[^/]+$/,""),{recursive:!0}),await lt(B,j("new-session","-d","-s","keeper","sleep 2147483647"))}catch{}return await xn()}function bt(t){return typeof t=="string"&&hA.test(t)}async function he(){if(!ni.existsSync(te))return[];try{let t="#{session_name}|#{session_windows}|#{session_attached}|#{session_activity}|#{pane_current_path}|#{@bostrat-session}|#{@bostrat-title}|#{@bostrat-sid}|#{@bostrat-agent}|#{alternate_on}",{stdout:e}=await lt(B,j("list-sessions","-F",t)),n=Date.now();return e.trim().split(`
47
- `).filter(Boolean).map(r=>{let[o,s,a,i,c,l,u,d,f,p]=r.split("|"),m=Number(i);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:f||(l==="1"?"claude":null),alternateOn:p==="1"}}).filter(r=>!dA.has(r.name)&&!r.name.startsWith("bostrat-view-"))}catch{return[]}}async function tt(t){return(await he()).find(n=>n.name===t)||null}function yA(t){if(typeof t!="string")return!1;let e=t.trim();return e.length>=1&&e.length<=gA&&wA.test(e)}function Gl(t){return t.trim().replace(/\s+/g,"-").toLowerCase().replace(/[^A-Za-z0-9_.-]/g,"").replace(/^-+|-+$/g,"")}async function gh(t){try{let{stdout:e}=await lt(B,j("list-sessions","-F","#{session_name}"));return e.split(`
48
- `).map(n=>n.trim()).includes(t)}catch{return!1}}function SA(t){let e=String(t||"").trim().split(/\s+/)[0]||"";if(e.includes("/"))return null;let n=[];for(let o=1;o<=e.length-3;o++)n.push(e.slice(o));if(!n.length)return null;let r=n.map(o=>o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));return new RegExp(`\\b(?:${r.join("|")})`)}async function vA(t,e){let n=Date.now()+bA(),r=SA(e),o=!1,s=0;for(;;){if(await qr(kA),s+=1,!await gh(t))return;let a=await yt(t,{lines:15}),i=!o&&xA.test(a)&&!!r?.test(a);if(!i&&s>1&&!await Kr(t))return;if(i){o=!0,await G({flow:"spawn",phase:"launch-retry",sessionName:t,agent:kn(e),promptHead:e.slice(0,120)}).catch(()=>{}),await lt(B,j("send-keys","-t",t,"C-u")),await lt(B,j("send-keys","-t",t,"-l",e)),await lt(B,j("send-keys","-t",t,"Enter"));continue}if(Date.now()>n){await G({flow:"spawn",phase:"launch-failed",sessionName:t,agent:kn(e),retried:o,error:"agent CLI never started after launch was typed"}).catch(()=>{});return}}}async function or(t,e=lA,n={}){if(!yA(t))throw new Error("displayName must be 1\u201364 chars (letters, digits, space . _ -)");let r=t.trim(),o=Gl(r);if(!bt(o))throw new Error("resulting tmux session name is invalid");if(!await ds())throw new Error(`host tmux server not running on ${te} and auto-start failed \u2014 start one: ${B} -S ${te} new-session -d -s keeper "sleep 2147483647"`);if(await gh(o))throw new Error(`tmux session "${o}" already exists`);let s=n.agentCmd||Ul,a=n.agent||kn(s),i=!!n.resumeSessionId,c=n.resumeSessionId||iA(),l=i?s:ql(s,c,o),u=i?n.pinned===!0:/(^|\s)--session-id(\s|=)/.test(l),d=a==="claude"&&rr(s),f=n.firstRun===!0;f||(d&&await mn(e),a==="codex"&&await Br(e),a==="cursor"&&await Dr(e),await Vm(e),await ch(e));let p=d&&!f?Ua():null,m=xm(),w=["-e",`${La}=${m}`];p&&w.push("-e",`ANTHROPIC_API_KEY=${p}`),d&&w.push(...Hl());try{await lt(B,j("new-session","-d","-s",o,"-c",e,...w))}catch(y){throw ei(p?ei(y,p):y,m)}return await sr(o),await lt(B,j("set-option","-t",o,"@bostrat-session","1")),await lt(B,j("set-option","-t",o,"@bostrat-title",r)),await lt(B,j("set-option","-t",o,"@bostrat-sid",c)),await lt(B,j("set-option","-t",o,"@bostrat-agent",a)),await lt(B,j("send-keys","-t",o,l,"Enter")),fA(l)&&vA(o,l).catch(()=>{}),{name:o,title:r,cwd:e,sessionId:c,agent:a,pinned:u,hookToken:m}}async function _e(t){if(!bt(t))throw new Error("invalid session name");await lt(B,j("kill-session","-t",t))}async function yh(t,e){if(bt(t))try{let n=e?j("set-option","-t",t,"@bostrat-sid",e):j("set-option","-u","-t",t,"@bostrat-sid");await lt(B,n)}catch{}}async function yt(t,{lines:e=40}={}){if(!bt(t))return"";try{let n=j("capture-pane","-t",t,"-p");Number.isFinite(e)&&e>0&&n.push("-S",`-${Math.floor(e)}`);let{stdout:r}=await lt(B,n);return String(r||"")}catch{return""}}async function bh(t){if(!bt(t))return 0;try{let{stdout:e}=await lt(B,j("list-clients","-t",t,"-F","1"));return String(e||"").trim().split(`
49
- `).filter(Boolean).length}catch{return 0}}async function sr(t,{cols:e=EA,rows:n=_A}={}){if(!bt(t))return!0;if(await bh(t))return!1;try{let r=await kh(t);if(r.cols===e&&r.rows===n)return!0;await lt(B,j("resize-window","-t",t,"-x",String(e),"-y",String(n))),await lt(B,j("set-window-option","-t",t,"window-size","latest")),await qr(80)}catch{}return!0}async function IA(t){if(!bt(t))return 0;try{let{stdout:e}=await lt(B,j("display-message","-t",t,"-p","#{pane_pid}"));return Number(String(e||"").trim())||0}catch{return 0}}async function Kr(t){let e=await IA(t);if(!e)return!1;try{return await lt("pgrep",["-P",String(e)]),!1}catch(n){return n?.code===1}}async function kh(t){if(!bt(t))return{cols:0,rows:0};try{let{stdout:e}=await lt(B,j("display-message","-t",t,"-p","#{window_width} #{window_height}")),[n,r]=String(e||"").trim().split(/\s+/).map(o=>Number(o)||0);return{cols:n,rows:r}}catch{return{cols:0,rows:0}}}async function si(t,{cols:e=TA,rows:n=AA}={}){if(bt(t)&&!await bh(t))try{let r=await kh(t),o=Math.max(r.cols,e),s=Math.max(r.rows,n);(o>r.cols||s>r.rows)&&(await lt(B,j("resize-window","-t",t,"-x",String(o),"-y",String(s))),await lt(B,j("set-window-option","-t",t,"window-size","latest")),await qr(80))}catch{}}async function Sn(t){return await si(t),yt(t,{lines:Ct})}async function Tt(t,e,{settleMs:n=40,kind:r}={}){if(!bt(t))throw new Error("invalid session name");let o=(Array.isArray(e)?e:[e]).filter(s=>RA.has(s));for(let s=0;s<o.length;s++)await lt(B,j("send-keys","-t",t,o[s])),n>0&&s<o.length-1&&await qr(n);return G({flow:"tmux",phase:"send-keys",sessionName:t,kind:r||"keys",keys:o.join(" ")}).catch(()=>{}),o.length}async function Gr(t,e,{kind:n}={}){if(!bt(t))throw new Error("invalid session name");let r=Math.max(0,Math.floor(Number(e)||0));return r>0&&await lt(B,j("send-keys","-t",t,"-N",String(r),"BSpace")),G({flow:"tmux",phase:"send-keys",sessionName:t,kind:n||"wipe",keys:`BSpace x${r}`}).catch(()=>{}),r}async function ii(t,e,{perCharDelayMs:n=120,kind:r}={}){if(!bt(t))throw new Error("invalid session name");let o=[...String(e)];for(let s of o)await lt(B,j("send-keys","-t",t,"-l",s)),n>0&&await qr(n);G({flow:"tmux",phase:"type",sessionName:t,kind:r||"type",textLen:o.length,textHead:String(e).slice(0,120)}).catch(()=>{})}async function Mt(t,e,{enter:n=!0,submitDelayMs:r=0,kind:o}={}){if(!bt(t))throw new Error("invalid session name");if(typeof e=="string"&&e.length>0&&await lt(B,j("send-keys","-t",t,"-l",e)),n){let s=Number(r);Number.isFinite(s)&&s>0&&await qr(s),await lt(B,j("send-keys","-t",t,"Enter"))}G({flow:"tmux",phase:"send",sessionName:t,kind:o||"text",textLen:typeof e=="string"?e.length:0,textHead:typeof e=="string"?e.slice(0,120):"",enter:n,submitDelayMs:r}).catch(()=>{})}var lt,B,ph,te,lA,Ul,uA,Wl,dA,ri,Hr,Wr,Fl,pA,mA,Kl,hA,wA,gA,bA,kA,xA,TA,AA,Ct,EA,_A,RA,ai,Ht=M(()=>{Qo();Wa();qa();Ya();jl();We();Zo();lt=aA(sA);B=process.env.BOSTRAT_TMUX_BIN||"/usr/bin/tmux";ph=typeof process.getuid=="function"?process.getuid():0,te=cA({explicit:process.env.BOSTRAT_TMUX_SOCKET,legacyExists:(()=>{try{return ni.existsSync(mh(ph))}catch{return!1}})(),runtimeDir:process.env.XDG_RUNTIME_DIR,uid:ph}),lA=process.env.BOSTRAT_DEFAULT_CWD||process.env.HOME||"/",Ul=process.env.BOSTRAT_AGENT_CMD||"claude --dangerously-skip-permissions",uA="CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN";Wl="bostrat-usage-probe",dA=new Set([Wl]);ri="present",Hr="absent",Wr="unknown",Fl=5e3,pA=[250,1e3,3e3],mA=t=>new Promise(e=>setTimeout(e,t));Kl={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"};hA=/^[A-Za-z0-9_.-]{1,64}$/;wA=/^[A-Za-z0-9 ._↻-]+$/,gA=64;bA=()=>Number(process.env.BOSTRAT_LAUNCH_VERIFY_MS)||12e3,kA=1e3,xA=/not found|Unknown command/i;TA=Number(process.env.BOSTRAT_PROMPT_CAPTURE_COLS)||100,AA=Number(process.env.BOSTRAT_PROMPT_CAPTURE_ROWS)||40,Ct=Number(process.env.BOSTRAT_PROMPT_CAPTURE_LINES)||80,EA=Number(process.env.BOSTRAT_BOX_COLS)||120,_A=Number(process.env.BOSTRAT_BOX_ROWS)||40;RA=new Set(["Up","Down","Left","Right","Space","Enter","Tab","BTab","Escape","BSpace"]);ai=1600});import fs from"node:fs";import NA from"node:fs/promises";import Vr from"node:path";import BA from"node:os";function Jl(t){return t.replace(/[^A-Za-z0-9]/g,"-")}function Yl(t){let e=Vr.join(zl,Jl(t)),n;try{n=fs.readdirSync(e).filter(o=>o.endsWith(".jsonl"))}catch{return null}let r=null;for(let o of n){let s=Vr.join(e,o);try{let{mtimeMs:a}=fs.statSync(s);(!r||a>r.mtimeMs)&&(r={full:s,mtimeMs:a})}catch{}}return r?r.full:null}function qe(t,e){if(!e)return null;let n=Vr.join(zl,Jl(t),`${e}.jsonl`);return fs.existsSync(n)?n:null}function _h(t){if(!t)return[];let e=Vr.join(zl,Jl(t)),n;try{n=fs.readdirSync(e).filter(o=>o.endsWith(".jsonl"))}catch{return[]}let r=[];for(let o of n)try{let s=fs.statSync(Vr.join(e,o));r.push({id:o.slice(0,-6),birthMs:s.birthtimeMs||s.ctimeMs||s.mtimeMs})}catch{}return r}async function Jt(t,e=131072){let n=await NA.open(t,"r");try{let{size:r}=await n.stat(),o=Math.max(0,r-e),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 jA(t){let e=t.split(`
50
- `);for(let n=e.length-1;n>=0;n--){let r=e[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 ps(t,e=null,{fallbackNewest:n=!0}={}){if(!t)return null;let r,o;if(e){if(r=qe(t,e),o=!0,!r)return null}else if(n){if(r=Yl(t),o=!1,!r)return null}else return null;let s;try{s=jA(await Jt(r))}catch{return null}if(!s)return null;let a=Object.prototype.hasOwnProperty.call(Eh,s.model),i=Eh[s.model]||DA;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 Eh,DA,zl,we=M(()=>{Eh={"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},DA=2e5,zl=process.env.BOSTRAT_CLAUDE_PROJECTS||Vr.join(BA.homedir(),".claude","projects")});function LA(t,e){return!t||!e?null:qe(t,e)}function FA(t){return typeof t=="string"?t.trim():Array.isArray(t)?t.filter(e=>e&&e.type==="text"&&typeof e.text=="string").map(e=>e.text).join(`
51
- `).trim():""}function UA(t){if(!Array.isArray(t))return null;let e=t.filter(n=>n&&n.type==="tool_use").map(n=>n.name).filter(Boolean);return e.length?e:null}function HA(t){return Array.isArray(t)&&t.length>0&&t.every(e=>e&&e.type==="tool_result")}function Xl(t){let e=[],n=t?.message?.content;if(!Array.isArray(n))return e;for(let r of n)if(r){if(r.type==="image"&&r.source?.type==="base64"&&r.source.data)e.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&&e.push({mediaType:o.source.media_type||"image/png",data:o.source.data,toolUseId:r.tool_use_id||null})}return e}function Ih(t,e){if(!t.uuid)return null;let n=Xl(t).map((r,o)=>({uuid:t.uuid,index:o,mediaType:r.mediaType,name:r.toolUseId&&e.get(r.toolUseId)||null}));return n.length?n:null}async function Zl(t,{maxBytes:e=524288,limit:n=80}={}){let r;try{r=await Jt(t,e)}catch{return[]}let o=[],s=new Map;for(let a of r.split(`
52
- `)){let i=a.trim();if(!i||i[0]!=="{")continue;let c;try{c=JSON.parse(i)}catch{continue}if(c.type==="attachment"){let m=c.attachment;m?.type==="queued_command"&&m.commandMode==="task-notification"&&typeof m.prompt=="string"&&m.prompt.trim()&&o.push({role:"user",text:m.prompt.trim(),ts:c.timestamp?Date.parse(c.timestamp):null,model:null});continue}let l=c.message;if(!l)continue;let u=l.role||c.type;if(u!=="user"&&u!=="assistant"||u==="assistant"&&l.model==="<synthetic>"&&!c.isApiErrorMessage)continue;if(u==="assistant"&&Array.isArray(l.content))for(let m of l.content){let w=m?.type==="tool_use"?m.input?.file_path||m.input?.path:null;typeof w=="string"&&WA.test(w)&&s.set(m.id,w.split("/").pop())}if(HA(l.content)){let m=Ih(c,s);m&&o.push({role:"assistant",text:"",images:m,ts:c.timestamp?Date.parse(c.timestamp):null,model:null});continue}let d=FA(l.content),f=u==="assistant"?UA(l.content):null,p=u==="user"?Ih(c,s):null;!d&&!f&&!p||o.push({role:u,text:d,tools:f||void 0,images:p||void 0,ts:c.timestamp?Date.parse(c.timestamp):null,model:l.model||null})}return o.slice(-n)}async function Rh(t,e,{turns:n=16}={}){let r=LA(t,e);if(!r)return"";let o=await Zl(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}:** ${qA(s.text||c,700)} ${i}`.trim()}).join(`
53
-
54
- `):""}var WA,qA,li=M(()=>{we();WA=/\.(png|jpe?g|gif|webp|bmp|svg|tiff?|avif|heic|heif|ico)$/i;qA=(t,e)=>t.length>e?`${t.slice(0,e).trimEnd()}\u2026`:t});import KA from"node:fs/promises";import{execFile as GA}from"node:child_process";import{promisify as VA}from"node:util";function Mh(t){tu=typeof t=="function"?t:null}function JA(t){let e=String(t||""),n=e.indexOf("/lib/node_modules/");return n>0?e.slice(0,n):null}function Ph({sessionName:t,from:e,to:n}={}){let r=String(n||"").trim();!r||$h.has(r)||($h.add(r),Oh=Oh.then(()=>YA({sessionName:t,from:e,to:r})).catch(()=>{}))}async function YA({sessionName:t,from:e,to:n}){await G({flow:"codex-update",phase:"start",sessionName:t,from:e,to:n}).catch(()=>{});try{let r=(await Ql("/bin/sh",["-c","command -v codex"])).stdout.trim();if(!r)throw new Error("codex not on PATH");let o=await KA.realpath(r),s=JA(o),a=s?{...process.env,PATH:`${s}/bin:${process.env.PATH||""}`}:process.env;await Ql("npm",["install","-g","@openai/codex"],{env:a,timeout:zA});let i=(await Ql(r,["--version"])).stdout.trim().replace(/^codex-cli\s*/,"")||n;await G({flow:"codex-update",phase:"done",sessionName:t,from:e,to:n,version:i}).catch(()=>{}),await Ch({sessionName:t,from:e,to:n,version:i,status:"updated"})}catch(r){let o=String(r?.message||r).slice(0,300);await G({flow:"codex-update",phase:"failed",sessionName:t,from:e,to:n,error:o}).catch(()=>{}),await Ch({sessionName:t,from:e,to:n,status:"failed",error:o})}}async function Ch(t){if(tu)try{await tu(t)}catch{}}var Ql,zA,$h,Oh,tu,eu=M(()=>{We();Ql=VA(GA),zA=Number(process.env.BOSTRAT_CODEX_UPDATE_TIMEOUT_MS)||5*6e4,$h=new Set,Oh=Promise.resolve(),tu=null});function ZA(t,{provider:e,box:n}){let r=String(t).replace(/\r/g,"").split(`
55
- `);if(!Nh.test(t))return null;let o=[],s=!1;for(let l=r.length-1;l>=0;l--){let u=r[l].match(XA);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"&&Nh.test(a)?a:"The agent is asking for approval";return{provider:e,box:n,promptId:`${e}:${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 ar(t){let e=String(t??"").replace(/\r/g,""),n=e.split(`
56
- `);for(let r=n.length-1;r>=0;r--)if(jh.test(n[r]))return n.slice(r).join(`
57
- `);return e}function QA(t){let e=String(t).trim();if(!e)return!1;let n=(e.match(/[A-Za-z]/g)||[]).length;return n>=3&&n/e.length>=.5}function tE(t){return/device code/i.test(t)?"works from the device you're reading this on":/sign in with chatgpt/i.test(t)?"opens a browser link on the node itself \u2014 can't finish from another device":""}function eE(t,e=""){let n=ar(t);if(ms.test(n)||!/Sign in with ChatGPT/.test(n)||!/Press enter to continue/.test(n))return null;let r=n.split(`
58
- `),o=[],s=-1;for(let l=0;l<r.length;l++){let u=r[l].match(Bh);if(!u)continue;s<0&&(s=l);let d="";for(let f=l+1;f<Math.min(l+3,r.length);f++){let p=r[f].trim();if(p){if(Bh.test(r[f])||/^Press enter/.test(p))break;d=p;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&&!jh.test(r[l])&&QA(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:e,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=tE(l.label);return{label:l.label,description:[l.desc,u].filter(Boolean).join(" \xB7 ")}})}]}}function oE(t,e=""){let n=ar(t);if(ms.test(n)||!nE.test(n))return null;let r=n.trimEnd().split(`
59
- `).pop()||"";return rE.test(r)?{provider:"codex",box:e,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 aE(t,e=""){let n=ar(t);if(ms.test(n)||!Dh.test(n))return null;let r=n.split(`
60
- `),o=r.findIndex(i=>Dh.test(i)),s="";for(let i=o+1;i<r.length;i++){let c=r[i].match(sE);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:e,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 iE(t,e=""){let n=ar(t);return ms.test(n)||!/open the following link to authenticate/.test(n)?null:{provider:"codex",box:e,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 cE(t,e=""){let n=ar(t);return ms.test(n)||!/Paste or type your API key/.test(n)?null:{provider:"codex",box:e,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 lE(t,e=""){let n=String(t);if(!/Press any key to log in/.test(n)||nu.test(n))return null;let r=n.replace(/\r/g,"").split(`
61
- `).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:e,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 dE(t,e=""){let n=String(t);if(!uE.test(n)||nu.test(n))return null;let r=n.replace(/\r/g,"").split(`
62
- `),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:e,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 fE(t,e=""){let n=String(t);return!/Scan this QR code to log in/.test(n)||nu.test(n)?null:{provider:"cursor",box:e,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 Lh(t,e,n=""){if(t!=="cursor"&&t!=="codex")return null;if(t==="codex"){let r=oE(e,n)||aE(e,n)||iE(e,n)||cE(e,n)||eE(e,n);if(r)return r}if(t==="cursor"){let r=dE(e,n)||fE(e,n)||lE(e,n);if(r)return r}return ZA(e,{provider:t,box:n})}function Fh(t,e){let n=Array.isArray(e?.[0])?e[0]:[],o=(Number.isInteger(n[0])&&n[0]>=0?n[0]:0)+1;return String(o)}var XA,Nh,ms,jh,Bh,nE,rE,Dh,sE,nu,uE,ui=M(()=>{XA=/^\s*[›>*\-❯]?\s*(\d+)[.)]\s+(.+?)\s*$/,Nh=/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i;ms=/(^|\n)\s*›/,jh=/^\s*Welcome to Codex\b/;Bh=/^\s*(>)?\s*(\d+)\.\s+(.+?)\s*$/;nE=/Successfully logged in\./,rE=/^\s*Press Enter to continue\.\s*$/;Dh=/Enter this one-time code/,sE=/^\s*([A-Z0-9]{2,10}-[A-Z0-9]{2,10})\s*$/;nu=/Run Everything|Add a follow-up|Plan, search, build anything/;uE=/click this link to log in|Signing in with the browser/});function wE(t){let e=String(t||"");if(!Dt.codex.block.test(e))return null;let n=ar(e);if(!Dt.codex.block.test(n))return null;let r=n.match(hE);return{from:r?.[1]||null,to:r?.[2]||null}}function vn(t){return new Promise(e=>setTimeout(e,t))}function Uh(t,e){let n=Date.now(),r=gE();for(let[s,a]of di)n-a>=r&&di.delete(s);let o=`${t}::${e}`;return di.has(o)?!1:(di.set(o,n),!0)}function kE(t){let e=0;for(let n of String(t).split(`
63
- `))bE.test(n)&&(e=Math.max(e,n.trimEnd().length));return e}function ou(t,e){let n=Dt[t];if(!n?.busy)return{state:"idle",reason:null};if(au(t,e))return{state:"unknown",reason:"blocked"};if(n.up&&!n.up.test(e))return{state:"idle",reason:null};if(n.busy.test(e))return{state:"busy",reason:null};if(n.busyAlt&&n.busyAlt.test(e))return{state:"busy",reason:null};let r=kE(e);return t==="claude"&&r>0&&r<yE?{state:"unknown",reason:"narrow"}:{state:"idle",reason:null}}function su(t,e){return ou(t,e).state}function Wh(t,e){if(t!=="claude")return!1;let n=String(e||"").split(`
64
- `).slice(-SE).join(`
65
- `);return xE.test(n)}function ws(t,e){return su(t,e)==="busy"}function fi(t,e){return su(t,e)!=="idle"}function pi(t,e){let n=Dt[t];return n?.up?n.up.test(e):!0}function vE(t,e){let n=Dt[t];return n?au(t,e)?!1:n.up.test(e)&&su(t,e)==="idle":!0}function au(t,e){let n=Dt[t];return n?n.auth?.test(e)&&!n.up.test(e)?!0:n.block?.test(e)?t==="codex"?!0:!n.up.test(e):!1:!1}async function Hh(t,e,n){let r=Date.now()+n,o=0;for(await sr(t).catch(()=>{});;){let s=await yt(t);if(vE(e,s)){await vn(hs);return}if(e==="cursor"&&mE.test(s)&&!Dt.cursor.up.test(s)&&o<3){if(!Uh(t,"cursor-trust")){await vn(ru);continue}o+=1,await G({flow:"agent-ready",phase:"gate-accept",sessionName:t,agent:e,attempt:o}).catch(()=>{}),await Mt(t,"a",{enter:!1,kind:"cursor-trust-accept"}),await vn(hs);continue}if(e==="codex"&&o<3){let a=wE(s);if(a){if(!Uh(t,`codex-update:${a.from}->${a.to}`)){await vn(ru);continue}o+=1,await G({flow:"agent-ready",phase:"gate-accept",sessionName:t,agent:e,attempt:o,update:`${a.from} -> ${a.to}`}).catch(()=>{}),await Mt(t,"3",{enter:!1,kind:"codex-update-skip"}),Ph({sessionName:t,from:a.from,to:a.to}),await vn(hs);continue}}if(Date.now()>r){if(au(e,s)){let a=`${e} is blocked on an interactive prompt`;throw e==="codex"?a=Dt.codex.auth.test(s)?"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":e==="cursor"&&Dt.cursor.auth.test(s)?a="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":e==="claude"&&Dt.claude.auth.test(s)?a="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":e==="claude"&&Dt.claude.block.test(s)&&(a='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'),G({flow:"agent-ready",phase:"blocked",sessionName:t,agent:e,timeoutMs:n,gateAccepts:o,error:a}).catch(()=>{}),new Error(a)}if(await Kr(t)){let a=`${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.`;throw G({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:t,agent:e,timeoutMs:n,gateAccepts:o,error:a}).catch(()=>{}),new Error(a)}console.warn(`[agent-ready] ${e} readiness unconfirmed in ${t} after ${n}ms \u2014 driving the box anyway.`),G({flow:"agent-ready",phase:"timeout",sessionName:t,agent:e,timeoutMs:n,gateAccepts:o,paneBlocked:!!Dt[e]?.block?.test(s),paneUp:!!Dt[e]?.up?.test(s),paneBusy:!!Dt[e]?.busy?.test(s)}).catch(()=>{}),await vn(hs);return}await vn(ru)}}function qh({agent:t,agentCmd:e}={}){let n=e?kn(e):kn(t||"");return{label:n,realClaude:e?rr(e):n==="claude",realCodex:e?/codex/.test(e)&&!/fake-codex|fake-lead/.test(e):n==="codex",realCursor:e?/cursor/.test(e)&&!/fake-cursor|fake-box/.test(e):n==="cursor"}}function mi({cwd:t,sessionName:e,agent:n,agentCmd:r}={}){let{realCodex:o,realCursor:s}=qh({agent:n,agentCmd:r});return!e||!o&&!s?null:Tn({cwd:t,sessionName:e,agent:n,agentCmd:r}).catch(()=>{})}async function Tn({cwd:t,sessionId:e,sessionName:n,agent:r,agentCmd:o,timeoutMs:s=pE()}={}){let{label:a,realClaude:i,realCodex:c,realCursor:l}=qh({agent:r,agentCmd:o});if(i&&t&&await mn(t),c&&t&&await Br(t),l&&t&&await Dr(t),(i||c||l)&&n){await Hh(n,a,s);return}let u=Dt[r]?r:Dt[a]?a:null;if(process.env.BOSTRAT_FAKE_POLL_READY==="1"&&n&&u){await Hh(n,u,s);return}await vn(hs)}var pE,ru,hs,Dt,mE,hE,gE,di,yE,bE,xE,SE,hi=M(()=>{Ht();Qo();Wa();qa();eu();ui();We();pE=()=>Number(process.env.BOSTRAT_AGENT_READY_TIMEOUT_MS)||9e4,ru=Number(process.env.BOSTRAT_AGENT_READY_POLL_MS)||500,hs=Number(process.env.BOSTRAT_AGENT_READY_SETTLE_MS)||800,Dt={claude:{up:/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/,busy:/esc to interrupt/,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:/(^|\n)\s*›/,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/}},mE=/Trust this workspace|\[a\]\s*Trust/,hE=/Update available!\s*([\d][\w.-]*)\s*->\s*([\d][\w.-]*)/;gE=()=>Number(process.env.BOSTRAT_GATE_RESEND_MS)||3e3,di=new Map;yE=68,bE=/^\s*[─━]{10,}\s*$/;xE=/\bWaiting for \d+\b[^\n]*\bto finish\b|\/workflows to (?:stop|monitor)\b/,SE=15});function Ie(t){return t==="codex"?{enter:!0,submitDelayMs:TE}:t==="claude"?{enter:!0,submitDelayMs:AE}:{enter:!0}}var TE,AE,gs=M(()=>{TE=(()=>{let t=Number(process.env.BOSTRAT_CODEX_SUBMIT_SETTLE_MS??120);return Number.isFinite(t)&&t>=0?t:120})(),AE=(()=>{let t=Number(process.env.BOSTRAT_CLAUDE_SUBMIT_SETTLE_MS??120);return Number.isFinite(t)&&t>=0?t:120})()});function ir(t){let e=String(t||"").toLowerCase();if(!e.trim())return null;let n=null;for(let r of EE){let o=0;for(let s of _E[r])s.test(e)&&o++;o>0&&(!n||o>n.score)&&(n={category:r,score:o})}return n}function Kh(t){let e=0,n=0;for(let[r,o]of Object.entries(t||{}))IE.has(r)&&(e+=o||0),RE.has(r)&&(n+=o||0);return e>=5&&n===0?{category:"research",score:1}:n>=3?{category:"feature-build",score:1}:null}function ys(t){return String(t||"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").replace(/[-_/]+/g," ")}var EE,_E,IE,RE,iu=M(()=>{EE=["bug-fix","orchestration","design","ops-infra","docs-writing","research","feature-build"],_E={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 out\b/,/\btalk through\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/],"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/],design:[/\bdesign/,/\bui\b/,/\bux\b/,/\bstyl(e|es|ing)\b/,/\bcss\b/,/\blayout\b/,/\bmock-?up/,/\brender(ing|s)?\b/,/\bpolish/,/\btheme\b/,/\bfonts?\b/,/\bresponsive\b/,/\banimation/,/\bvisual/,/\bpopover\b/],orchestration:[/\bhand[ -]?(off|over)/,/\bhand (it|the lead|this) (over|off)\b/,/\bdelegat/,/\bsubtask/,/\bmerge[ -]?back\b/,/\borchestrat/,/\b(switch|change) (the )?model\b/,/\bmodel switch/],"docs-writing":[/\bdocs?\b/,/\bdocument/,/\bmemo\b/,/\breadme\b/,/\bwrite-?up\b/,/\bchangelog\b/,/\bclaude\.md\b/,/\bblog/,/\bproofread/,/\bcopy(edit|writ)/],"ops-infra":[/\bdeploy/,/\bsystemd\b/,/\bdaemon\b/,/\btmux\b/,/\bdns\b/,/\bwireguard\b/,/\brestart/,/\bnginx\b/,/\bprovision/,/\binstall/,/\bupgrade/,/\bcron\b/,/\bbackups?\b/,/\bcertificat/,/\bssh\b/,/\bsecrets?\b/]};IE=new Set(["Read","Grep","Glob","LS","WebSearch","WebFetch","NotebookRead"]),RE=new Set(["Edit","Write","MultiEdit","NotebookEdit"])});function Jh(t){let e=ys(String(t||"")).toLowerCase(),n=[];for(let r of e.split(/[^a-z0-9]+/))r.length<2||$E.has(r)||n.push(r);return n}function OE(t){let e=[];for(let n of t||[]){let r=n.payload||{},o=String(r.text||"").trim();if(n.type==="turn.user"){if(n.source==="hook"||!o)continue;e.push(zh(n,"user",o))}else if(n.type==="turn.agent"){if(!o)continue;e.push(zh(n,"assistant",o))}}return e}function zh(t,e,n){let r=ir(n);return{id:t.id,seq:t.seq,ts:t.payload?.ts??t.ts,role:e,boxId:t.boxId??null,provider:t.provider??null,text:n,tags:r?[r.category]:[]}}function bs(t){let e=OE(t),n=new Map,r=new Array(e.length).fill(0),o=0;e.forEach((a,i)=>{let c=Jh(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 f=n.get(u);f||n.set(u,f=new Map),f.set(i,d)}});let s=e.length;return{chunks:e,postings:n,lengths:r,N:s,avgdl:s?o/s:0}}function wi(t,e,n={}){let{k:r=8,role:o=null,tag:s=null,boxId:a=null}=n;if(!t||!t.N)return[];let i=[...new Set(Jh(e))];if(!i.length)return[];let c=new Map;for(let u of i){let d=t.postings.get(u);if(!d)continue;let f=d.size,p=Math.log(1+(t.N-f+.5)/(f+.5));for(let[m,w]of d){let y=t.lengths[m],k=w+Gh*(1-Vh+Vh*(y/(t.avgdl||1))),S=p*(w*(Gh+1)/k);c.set(m,(c.get(m)||0)+S)}}let l=[];for(let[u,d]of c){let f=t.chunks[u];o&&f.role!==o||s&&!f.tags.includes(s)||a&&f.boxId!==a||l.push({chunk:f,score:d})}return l.sort((u,d)=>d.score-u.score||d.chunk.seq-u.chunk.seq),l.slice(0,r)}var Gh,Vh,$E,cu=M(()=>{iu();Gh=1.5,Vh=.75,$E=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 gi from"node:fs/promises";import Yh from"node:path";async function CE(t){let e=Yh.join(t,".bostrat","events"),n;try{n=await gi.readdir(e)}catch{return bs([])}let r=[];for(let o of n)if(o.endsWith(".ndjson"))try{let s=await gi.readFile(Yh.join(e,o),"utf8");for(let a of s.split(`
66
- `))if(a.trim())try{r.push(JSON.parse(a))}catch{}}catch{}return bs(r)}function ME(t){let e=String(t||""),n=a=>{let i=e.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}
67
- ${o}`.trim()||e.slice(0,2e3)}function PE(t,e,{k:n=6,maxChars:r=4e3,exclude:o=null}={}){let s=wi(t,e,{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,f=`- **${l}:** ${d}`;if(i+f.length>r||(a.push(f),i+=f.length,a.length>=n))break}return a.length?["",`## ${Xh}, 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(`
68
- `):""}async function Zh(t,e,n={}){let{k:r=6,maxChars:o=4e3,exclude:s=null}=n;try{let a=await gi.readFile(e,"utf8");if(a.includes(Xh))return{appended:!1,reason:"already-enriched"};let i=await CE(t);if(!i.N)return{appended:!1,reason:"empty-index"};let c=PE(i,ME(a),{k:r,maxChars:o,exclude:s});return c?(await gi.appendFile(e,`
45
+ `,"utf8")}catch(e){console.warn(`[handoff-debug] failed to write ${Yr}: ${e?.message||e}`)}}async function G(t={}){let e={at:new Date().toISOString(),ts:Date.now(),...t},n=[e.flow||"handoff",e.phase||e.step||"?",e.trackId?`track=${e.trackId}`:"",e.sessionName?`box=${e.sessionName}`:"",e.error?`ERR=${e.error}`:""].filter(Boolean).join(" \xB7 ");if(console.log(`[handoff-debug] ${n}`),e.sessionName&&mi())try{e.paneTail=lr((await Tt(e.sessionName,{lines:35})).slice(-4e3))}catch{e.paneTail=null}(mi()||e.error||/^(checkpoint|spawn|hydrate|commit|done|summarize|clear|resume|ready|send|failed|launch)/.test(String(e.phase||e.step||"")))&&await MA(e)}async function Ph({limit:t=80}={}){try{return(await bs.readFile(Yr,"utf8")).split(`
46
+ `).filter(Boolean).slice(-t).map(r=>{try{let o=JSON.parse(r);return typeof o?.paneTail=="string"&&(o.paneTail=lr(o.paneTail)),o}catch{return{raw:lr(r)}}})}catch{return[]}}var CA,Yl,Yr,Mh,Dh,Ke=M(()=>{qt();CA=[/[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];Yl=process.env.BOSTRAT_DEBUG_DIR||Nh.join(OA.homedir(),".bostrat","debug"),Yr=Nh.join(Yl,"handoff.jsonl"),Mh=Number(process.env.BOSTRAT_HANDOFF_DEBUG_MAX)||500;Dh={DEBUG_DIR:Yl,LOG_FILE:Yr}});import{execFile as NA}from"node:child_process";import{promisify as PA}from"node:util";import wi from"node:fs";import{randomUUID as DA}from"node:crypto";function Qr(t){return new Promise(e=>setTimeout(e,t))}function hi(t,e){if(!e)return t;let n=o=>typeof o=="string"?o.split(e).join("<redacted>"):o,r=new Error(n(t?.message)||"command failed");return t?.code!==void 0&&(r.code=t.code),t?.stderr!==void 0&&(r.stderr=n(t.stderr)),r}function jh(t){return`/tmp/tmux-${t}/default`}function BA({explicit:t,legacyExists:e,runtimeDir:n,uid:r}){if(t)return t;let o=jh(r);return e?o:n?`${n}/bostrat/tmux-default`:o}function Ql(){return process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1"?[]:["-e",`${LA}=1`]}function eu(t,e,n){let r=ur(t),o=/(^|\s)(--session-id|--resume|--continue|-r|-c)(\s|=|$)/.test(t);if(!r||o)return t;let s=`${t} --session-id ${e}`,a=/(^|\s)(--name|-n)(\s|=)/.test(t);return n&&!a&&At(n)&&(s+=` --name ${n}`),s}function ur(t){return/(^|\/|\s)claude(\s|$)/.test(String(t||""))}function vn(t){return/(^|\/|\s)claude(\s|$)/.test(t)?"claude":/cursor/.test(t)?"cursor":/codex/.test(t)?"codex":/gemini/.test(t)?"gemini":"agent"}function UA(t){let e=String(t||"").trim();return!e||/fake-|\.sh(\s|$)/.test(e)?!1:ur(e)||/(^|\/|\s)codex(\s|$)/.test(e)||/cursor-agent/.test(e)||/(^|\/|\s)gemini(\s|$)/.test(e)}async function Lh(t,{loginShell:e=!1,failOpen:n=!1}={}){let r=await Fh(t,{loginShell:e});return r===gi?!0:r===Xr?!1:n}async function Fh(t,{loginShell:e=!1,timeoutMs:n=Xl}={}){if(!t)return Xr;let r=e?process.env.SHELL||"/bin/sh":"sh",o=e?"-lic":"-c";try{return await ft(r,[o,'command -v "$1" >/dev/null 2>&1',"_",t],{timeout:n}),gi}catch(s){return s?.killed||s?.signal?Zr:s?.code===1||s?.code===127?Xr:Zr}}async function yi(t,{retries:e=HA,sleep:n=WA,probe:r=Fh}={}){let o=String(t||"").trim().split(/\s+/)[0],s=await r(o,{timeoutMs:Xl});for(let a=0;s===Zr&&a<e.length;a++)await n(e[a]),s=await r(o,{timeoutMs:Xl*2});return s}function U(...t){return["-S",ne,...t]}async function Tn(){if(!wi.existsSync(ne))return!1;try{return await ft(L,U("list-sessions")),!0}catch(t){let e=t&&t.stderr?String(t.stderr):"";return!/no server running/i.test(e)}}async function ks(){if(await Tn())return!0;try{wi.mkdirSync(ne.replace(/\/[^/]+$/,""),{recursive:!0}),await ft(L,U("new-session","-d","-s","keeper","sleep 2147483647"))}catch{}return await Tn()}function At(t){return typeof t=="string"&&qA.test(t)}async function ge(){if(!wi.existsSync(ne))return[];try{let t="#{session_name}|#{session_windows}|#{session_attached}|#{session_activity}|#{pane_current_path}|#{@bostrat-session}|#{@bostrat-title}|#{@bostrat-sid}|#{@bostrat-agent}|#{alternate_on}",{stdout:e}=await ft(L,U("list-sessions","-F",t)),n=Date.now();return e.trim().split(`
47
+ `).filter(Boolean).map(r=>{let[o,s,a,i,c,l,u,f,d,p]=r.split("|"),h=Number(i);return{name:o,title:u||null,windows:Number(s),attached:Number(a),lastActivityMs:Number.isFinite(h)?n-h*1e3:null,cwd:c||null,isBostrat:l==="1",sessionId:f||null,agent:d||(l==="1"?"claude":null),alternateOn:p==="1"}}).filter(r=>!FA.has(r.name)&&!r.name.startsWith("bostrat-view-"))}catch{return[]}}async function et(t){return(await ge()).find(n=>n.name===t)||null}function VA(t){if(typeof t!="string")return!1;let e=t.trim();return e.length>=1&&e.length<=GA&&KA.test(e)}function bi(t){return t.trim().replace(/\s+/g,"-").toLowerCase().replace(/[^A-Za-z0-9_.-]/g,"").replace(/^-+|-+$/g,"")}async function Uh(t){try{let{stdout:e}=await ft(L,U("list-sessions","-F","#{session_name}"));return e.split(`
48
+ `).map(n=>n.trim()).includes(t)}catch{return!1}}function XA(t){let e=String(t||"").trim().split(/\s+/)[0]||"";if(e.includes("/"))return null;let n=[];for(let o=1;o<=e.length-3;o++)n.push(e.slice(o));if(!n.length)return null;let r=n.map(o=>o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));return new RegExp(`\\b(?:${r.join("|")})`)}async function ZA(t,e){let n=Date.now()+zA(),r=XA(e),o=!1,s=0;for(;;){if(await Qr(JA),s+=1,!await Uh(t))return;let a=await Tt(t,{lines:15}),i=!o&&YA.test(a)&&!!r?.test(a);if(!i&&s>1&&!await to(t))return;if(i){o=!0,await G({flow:"spawn",phase:"launch-retry",sessionName:t,agent:vn(e),promptHead:e.slice(0,120)}).catch(()=>{}),await ft(L,U("send-keys","-t",t,"C-u")),await ft(L,U("send-keys","-t",t,"-l",e)),await ft(L,U("send-keys","-t",t,"Enter"));continue}if(Date.now()>n){await G({flow:"spawn",phase:"launch-failed",sessionName:t,agent:vn(e),retried:o,error:"agent CLI never started after launch was typed"}).catch(()=>{});return}}}async function An(t,e=jA,n={}){if(!VA(t))throw new Error("displayName must be 1\u201364 chars (letters, digits, space . _ -)");let r=t.trim(),o=bi(r);if(!At(o))throw new Error("resulting tmux session name is invalid");if(!await ks())throw new Error(`host tmux server not running on ${ne} and auto-start failed \u2014 start one: ${L} -S ${ne} new-session -d -s keeper "sleep 2147483647"`);if(await Uh(o))throw new Error(`tmux session "${o}" already exists`);let s=n.agentCmd||Zl,a=n.agent||vn(s),i=!!n.resumeSessionId,c=n.resumeSessionId||DA(),l=i?s:eu(s,c,o),u=i?n.pinned===!0:/(^|\s)--session-id(\s|=)/.test(l),f=a==="claude"&&ur(s),d=n.firstRun===!0;d||(f&&await gn(e),a==="codex"&&await qr(e),a==="cursor"&&await Kr(e),await yh(e),await fi(e));let p=f&&!d?Za():null,h=Gm(),w=["-e",`${Ya}=${h}`];p&&w.push("-e",`ANTHROPIC_API_KEY=${p}`),f&&w.push(...Ql());try{await ft(L,U("new-session","-d","-s",o,"-c",e,...w))}catch(y){throw hi(p?hi(y,p):y,h)}return await dr(o),await ft(L,U("set-option","-t",o,"@bostrat-session","1")),await ft(L,U("set-option","-t",o,"@bostrat-title",r)),await ft(L,U("set-option","-t",o,"@bostrat-sid",c)),await ft(L,U("set-option","-t",o,"@bostrat-agent",a)),await ft(L,U("send-keys","-t",o,l,"Enter")),UA(l)&&ZA(o,l).catch(()=>{}),{name:o,title:r,cwd:e,sessionId:c,agent:a,pinned:u,hookToken:h}}async function Re(t){if(!At(t))throw new Error("invalid session name");await ft(L,U("kill-session","-t",t))}async function Hh(t,e){if(At(t))try{let n=e?U("set-option","-t",t,"@bostrat-sid",e):U("set-option","-u","-t",t,"@bostrat-sid");await ft(L,n)}catch{}}async function Tt(t,{lines:e=40}={}){if(!At(t))return"";try{let n=U("capture-pane","-t",t,"-p");Number.isFinite(e)&&e>0&&n.push("-S",`-${Math.floor(e)}`);let{stdout:r}=await ft(L,n);return String(r||"")}catch{return""}}async function Wh(t){if(!At(t))return 0;try{let{stdout:e}=await ft(L,U("list-clients","-t",t,"-F","1"));return String(e||"").trim().split(`
49
+ `).filter(Boolean).length}catch{return 0}}async function dr(t,{cols:e=eE,rows:n=nE}={}){if(!At(t))return!0;if(await Wh(t))return!1;try{let r=await qh(t);if(r.cols===e&&r.rows===n)return!0;await ft(L,U("resize-window","-t",t,"-x",String(e),"-y",String(n))),await ft(L,U("set-window-option","-t",t,"window-size","latest")),await Qr(80)}catch{}return!0}async function rE(t){if(!At(t))return 0;try{let{stdout:e}=await ft(L,U("display-message","-t",t,"-p","#{pane_pid}"));return Number(String(e||"").trim())||0}catch{return 0}}async function to(t){let e=await rE(t);if(!e)return!1;try{return await ft("pgrep",["-P",String(e)]),!1}catch(n){return n?.code===1}}async function qh(t){if(!At(t))return{cols:0,rows:0};try{let{stdout:e}=await ft(L,U("display-message","-t",t,"-p","#{window_width} #{window_height}")),[n,r]=String(e||"").trim().split(/\s+/).map(o=>Number(o)||0);return{cols:n,rows:r}}catch{return{cols:0,rows:0}}}async function ki(t,{cols:e=QA,rows:n=tE}={}){if(At(t)&&!await Wh(t))try{let r=await qh(t),o=Math.max(r.cols,e),s=Math.max(r.rows,n);(o>r.cols||s>r.rows)&&(await ft(L,U("resize-window","-t",t,"-x",String(o),"-y",String(s))),await ft(L,U("set-window-option","-t",t,"window-size","latest")),await Qr(80))}catch{}}async function En(t){return await ki(t),Tt(t,{lines:Nt})}async function It(t,e,{settleMs:n=40,kind:r}={}){if(!At(t))throw new Error("invalid session name");let o=(Array.isArray(e)?e:[e]).filter(s=>oE.has(s));for(let s=0;s<o.length;s++)await ft(L,U("send-keys","-t",t,o[s])),n>0&&s<o.length-1&&await Qr(n);return G({flow:"tmux",phase:"send-keys",sessionName:t,kind:r||"keys",keys:o.join(" ")}).catch(()=>{}),o.length}async function eo(t,e,{kind:n}={}){if(!At(t))throw new Error("invalid session name");let r=Math.max(0,Math.floor(Number(e)||0));return r>0&&await ft(L,U("send-keys","-t",t,"-N",String(r),"BSpace")),G({flow:"tmux",phase:"send-keys",sessionName:t,kind:n||"wipe",keys:`BSpace x${r}`}).catch(()=>{}),r}async function Si(t,e,{perCharDelayMs:n=120,kind:r}={}){if(!At(t))throw new Error("invalid session name");let o=[...String(e)];for(let s of o)await ft(L,U("send-keys","-t",t,"-l",s)),n>0&&await Qr(n);G({flow:"tmux",phase:"type",sessionName:t,kind:r||"type",textLen:o.length,textHead:String(e).slice(0,120)}).catch(()=>{})}async function Pt(t,e,{enter:n=!0,submitDelayMs:r=0,kind:o}={}){if(!At(t))throw new Error("invalid session name");if(typeof e=="string"&&e.length>0&&await ft(L,U("send-keys","-t",t,"-l",e)),n){let s=Number(r);Number.isFinite(s)&&s>0&&await Qr(s),await ft(L,U("send-keys","-t",t,"Enter"))}G({flow:"tmux",phase:"send",sessionName:t,kind:o||"text",textLen:typeof e=="string"?e.length:0,textHead:typeof e=="string"?e.slice(0,120):"",enter:n,submitDelayMs:r}).catch(()=>{})}var ft,L,Bh,ne,jA,Zl,LA,tu,FA,gi,Xr,Zr,Xl,HA,WA,nu,qA,KA,GA,zA,JA,YA,QA,tE,Nt,eE,nE,oE,xi,qt=M(()=>{ls();ti();ei();ci();pi();Ke();cs();ft=PA(NA);L=process.env.BOSTRAT_TMUX_BIN||"/usr/bin/tmux";Bh=typeof process.getuid=="function"?process.getuid():0,ne=BA({explicit:process.env.BOSTRAT_TMUX_SOCKET,legacyExists:(()=>{try{return wi.existsSync(jh(Bh))}catch{return!1}})(),runtimeDir:process.env.XDG_RUNTIME_DIR,uid:Bh}),jA=process.env.BOSTRAT_DEFAULT_CWD||process.env.HOME||"/",Zl=process.env.BOSTRAT_AGENT_CMD||"claude --dangerously-skip-permissions",LA="CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN";tu="bostrat-usage-probe",FA=new Set([tu]);gi="present",Xr="absent",Zr="unknown",Xl=5e3,HA=[250,1e3,3e3],WA=t=>new Promise(e=>setTimeout(e,t));nu={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"};qA=/^[A-Za-z0-9_.-]{1,64}$/;KA=/^[A-Za-z0-9 ._↻-]+$/,GA=64;zA=()=>Number(process.env.BOSTRAT_LAUNCH_VERIFY_MS)||12e3,JA=1e3,YA=/not found|Unknown command/i;QA=Number(process.env.BOSTRAT_PROMPT_CAPTURE_COLS)||100,tE=Number(process.env.BOSTRAT_PROMPT_CAPTURE_ROWS)||40,Nt=Number(process.env.BOSTRAT_PROMPT_CAPTURE_LINES)||80,eE=Number(process.env.BOSTRAT_BOX_COLS)||120,nE=Number(process.env.BOSTRAT_BOX_ROWS)||40;oE=new Set(["Up","Down","Left","Right","Space","Enter","Tab","BTab","Escape","BSpace"]);xi=1600});import xs from"node:fs";import uE from"node:fs/promises";import no from"node:path";import dE from"node:os";function su(t){return t.replace(/[^A-Za-z0-9]/g,"-")}function au(t){let e=no.join(ou,su(t)),n;try{n=xs.readdirSync(e).filter(o=>o.endsWith(".jsonl"))}catch{return null}let r=null;for(let o of n){let s=no.join(e,o);try{let{mtimeMs:a}=xs.statSync(s);(!r||a>r.mtimeMs)&&(r={full:s,mtimeMs:a})}catch{}}return r?r.full:null}function Ge(t,e){if(!e)return null;let n=no.join(ou,su(t),`${e}.jsonl`);return xs.existsSync(n)?n:null}function Xh(t){if(!t)return[];let e=no.join(ou,su(t)),n;try{n=xs.readdirSync(e).filter(o=>o.endsWith(".jsonl"))}catch{return[]}let r=[];for(let o of n)try{let s=xs.statSync(no.join(e,o));r.push({id:o.slice(0,-6),birthMs:s.birthtimeMs||s.ctimeMs||s.mtimeMs})}catch{}return r}async function Xt(t,e=131072){let n=await uE.open(t,"r");try{let{size:r}=await n.stat(),o=Math.max(0,r-e),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 pE(t){let e=t.split(`
50
+ `);for(let n=e.length-1;n>=0;n--){let r=e[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 Ss(t,e=null,{fallbackNewest:n=!0}={}){if(!t)return null;let r,o;if(e){if(r=Ge(t,e),o=!0,!r)return null}else if(n){if(r=au(t),o=!1,!r)return null}else return null;let s;try{s=pE(await Xt(r))}catch{return null}if(!s)return null;let a=Object.prototype.hasOwnProperty.call(Yh,s.model),i=Yh[s.model]||fE;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 Yh,fE,ou,ye=M(()=>{Yh={"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},fE=2e5,ou=process.env.BOSTRAT_CLAUDE_PROJECTS||no.join(dE.homedir(),".claude","projects")});function mE(t,e){return!t||!e?null:Ge(t,e)}function hE(t){return typeof t=="string"?t.trim():Array.isArray(t)?t.filter(e=>e&&e.type==="text"&&typeof e.text=="string").map(e=>e.text).join(`
51
+ `).trim():""}function wE(t){if(!Array.isArray(t))return null;let e=t.filter(n=>n&&n.type==="tool_use").map(n=>n.name).filter(Boolean);return e.length?e:null}function gE(t){return Array.isArray(t)&&t.length>0&&t.every(e=>e&&e.type==="tool_result")}function iu(t){let e=[],n=t?.message?.content;if(!Array.isArray(n))return e;for(let r of n)if(r){if(r.type==="image"&&r.source?.type==="base64"&&r.source.data)e.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&&e.push({mediaType:o.source.media_type||"image/png",data:o.source.data,toolUseId:r.tool_use_id||null})}return e}function Zh(t,e){if(!t.uuid)return null;let n=iu(t).map((r,o)=>({uuid:t.uuid,index:o,mediaType:r.mediaType,name:r.toolUseId&&e.get(r.toolUseId)||null}));return n.length?n:null}async function cu(t,{maxBytes:e=524288,limit:n=80}={}){let r;try{r=await Xt(t,e)}catch{return[]}let o=[],s=new Map;for(let a of r.split(`
52
+ `)){let i=a.trim();if(!i||i[0]!=="{")continue;let c;try{c=JSON.parse(i)}catch{continue}if(c.type==="attachment"){let h=c.attachment;h?.type==="queued_command"&&h.commandMode==="task-notification"&&typeof h.prompt=="string"&&h.prompt.trim()&&o.push({role:"user",text:h.prompt.trim(),ts:c.timestamp?Date.parse(c.timestamp):null,model:null});continue}let l=c.message;if(!l)continue;let u=l.role||c.type;if(u!=="user"&&u!=="assistant"||u==="assistant"&&l.model==="<synthetic>"&&!c.isApiErrorMessage)continue;if(u==="assistant"&&Array.isArray(l.content))for(let h of l.content){let w=h?.type==="tool_use"?h.input?.file_path||h.input?.path:null;typeof w=="string"&&yE.test(w)&&s.set(h.id,w.split("/").pop())}if(gE(l.content)){let h=Zh(c,s);h&&o.push({role:"assistant",text:"",images:h,ts:c.timestamp?Date.parse(c.timestamp):null,model:null});continue}let f=hE(l.content),d=u==="assistant"?wE(l.content):null,p=u==="user"?Zh(c,s):null;!f&&!d&&!p||o.push({role:u,text:f,tools:d||void 0,images:p||void 0,ts:c.timestamp?Date.parse(c.timestamp):null,model:l.model||null})}return o.slice(-n)}async function Qh(t,e,{turns:n=16}={}){let r=mE(t,e);if(!r)return"";let o=await cu(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}:** ${bE(s.text||c,700)} ${i}`.trim()}).join(`
53
+
54
+ `):""}var yE,bE,Ti=M(()=>{ye();yE=/\.(png|jpe?g|gif|webp|bmp|svg|tiff?|avif|heic|heif|ico)$/i;bE=(t,e)=>t.length>e?`${t.slice(0,e).trimEnd()}\u2026`:t});import kE from"node:fs/promises";import{execFile as xE}from"node:child_process";import{promisify as SE}from"node:util";function rw(t){uu=typeof t=="function"?t:null}function TE(t){let e=String(t||""),n=e.indexOf("/lib/node_modules/");return n>0?e.slice(0,n):null}function ow({sessionName:t,from:e,to:n}={}){let r=String(n||"").trim();!r||tw.has(r)||(tw.add(r),ew=ew.then(()=>AE({sessionName:t,from:e,to:r})).catch(()=>{}))}async function AE({sessionName:t,from:e,to:n}){await G({flow:"codex-update",phase:"start",sessionName:t,from:e,to:n}).catch(()=>{});try{let r=(await lu("/bin/sh",["-c","command -v codex"])).stdout.trim();if(!r)throw new Error("codex not on PATH");let o=await kE.realpath(r),s=TE(o),a=s?{...process.env,PATH:`${s}/bin:${process.env.PATH||""}`}:process.env;await lu("npm",["install","-g","@openai/codex"],{env:a,timeout:vE});let i=(await lu(r,["--version"])).stdout.trim().replace(/^codex-cli\s*/,"")||n;await G({flow:"codex-update",phase:"done",sessionName:t,from:e,to:n,version:i}).catch(()=>{}),await nw({sessionName:t,from:e,to:n,version:i,status:"updated"})}catch(r){let o=String(r?.message||r).slice(0,300);await G({flow:"codex-update",phase:"failed",sessionName:t,from:e,to:n,error:o}).catch(()=>{}),await nw({sessionName:t,from:e,to:n,status:"failed",error:o})}}async function nw(t){if(uu)try{await uu(t)}catch{}}var lu,vE,tw,ew,uu,du=M(()=>{Ke();lu=SE(xE),vE=Number(process.env.BOSTRAT_CODEX_UPDATE_TIMEOUT_MS)||5*6e4,tw=new Set,ew=Promise.resolve(),uu=null});function _E(t,{provider:e,box:n}){let r=String(t).replace(/\r/g,"").split(`
55
+ `);if(!sw.test(t))return null;let o=[],s=!1;for(let l=r.length-1;l>=0;l--){let u=r[l].match(EE);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"&&sw.test(a)?a:"The agent is asking for approval";return{provider:e,box:n,promptId:`${e}:${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 fr(t){let e=String(t??"").replace(/\r/g,""),n=e.split(`
56
+ `);for(let r=n.length-1;r>=0;r--)if(cw.test(n[r]))return n.slice(r).join(`
57
+ `);return e}function IE(t){let e=String(t).trim();if(!e)return!1;let n=(e.match(/[A-Za-z]/g)||[]).length;return n>=3&&n/e.length>=.5}function RE(t){return/device code/i.test(t)?"works from the device you're reading this on":/sign in with chatgpt/i.test(t)?"opens a browser link on the node itself \u2014 can't finish from another device":""}function $E(t,e=""){let n=fr(t);if(vs.test(n)||!/Sign in with ChatGPT/.test(n)||!/Press enter to continue/.test(n))return null;let r=n.split(`
58
+ `),o=[],s=-1;for(let l=0;l<r.length;l++){let u=r[l].match(aw);if(!u)continue;s<0&&(s=l);let f="";for(let d=l+1;d<Math.min(l+3,r.length);d++){let p=r[d].trim();if(p){if(aw.test(r[d])||/^Press enter/.test(p))break;f=p;break}}o.push({n:Number(u[2]),cursor:!!u[1],label:u[3].trim(),desc:f})}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&&!cw.test(r[l])&&IE(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:e,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=RE(l.label);return{label:l.label,description:[l.desc,u].filter(Boolean).join(" \xB7 ")}})}]}}function ME(t,e=""){let n=fr(t);if(vs.test(n)||!OE.test(n))return null;let r=n.trimEnd().split(`
59
+ `).pop()||"";return CE.test(r)?{provider:"codex",box:e,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 PE(t,e=""){let n=fr(t);if(vs.test(n)||!iw.test(n))return null;let r=n.split(`
60
+ `),o=r.findIndex(i=>iw.test(i)),s="";for(let i=o+1;i<r.length;i++){let c=r[i].match(NE);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:e,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 DE(t,e=""){let n=fr(t);return vs.test(n)||!/open the following link to authenticate/.test(n)?null:{provider:"codex",box:e,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 BE(t,e=""){let n=fr(t);return vs.test(n)||!/Paste or type your API key/.test(n)?null:{provider:"codex",box:e,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 jE(t,e=""){let n=String(t);if(!/Press any key to log in/.test(n)||fu.test(n))return null;let r=n.replace(/\r/g,"").split(`
61
+ `).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:e,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 FE(t,e=""){let n=String(t);if(!LE.test(n)||fu.test(n))return null;let r=n.replace(/\r/g,"").split(`
62
+ `),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:e,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 UE(t,e=""){let n=String(t);return!/Scan this QR code to log in/.test(n)||fu.test(n)?null:{provider:"cursor",box:e,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 lw(t,e,n=""){if(t!=="cursor"&&t!=="codex")return null;if(t==="codex"){let r=ME(e,n)||PE(e,n)||DE(e,n)||BE(e,n)||$E(e,n);if(r)return r}if(t==="cursor"){let r=FE(e,n)||UE(e,n)||jE(e,n);if(r)return r}return _E(e,{provider:t,box:n})}function uw(t,e){let n=Array.isArray(e?.[0])?e[0]:[],o=(Number.isInteger(n[0])&&n[0]>=0?n[0]:0)+1;return String(o)}var EE,sw,vs,cw,aw,OE,CE,iw,NE,fu,LE,Ai=M(()=>{EE=/^\s*[›>*\-❯]?\s*(\d+)[.)]\s+(.+?)\s*$/,sw=/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i;vs=/(^|\n)\s*›/,cw=/^\s*Welcome to Codex\b/;aw=/^\s*(>)?\s*(\d+)\.\s+(.+?)\s*$/;OE=/Successfully logged in\./,CE=/^\s*Press Enter to continue\.\s*$/;iw=/Enter this one-time code/,NE=/^\s*([A-Z0-9]{2,10}-[A-Z0-9]{2,10})\s*$/;fu=/Run Everything|Add a follow-up|Plan, search, build anything/;LE=/click this link to log in|Signing in with the browser/});function KE(t){let e=String(t||"");if(!jt.codex.block.test(e))return null;let n=fr(e);if(!jt.codex.block.test(n))return null;let r=n.match(qE);return{from:r?.[1]||null,to:r?.[2]||null}}function _n(t){return new Promise(e=>setTimeout(e,t))}function dw(t,e){let n=Date.now(),r=GE();for(let[s,a]of Ei)n-a>=r&&Ei.delete(s);let o=`${t}::${e}`;return Ei.has(o)?!1:(Ei.set(o,n),!0)}function JE(t){let e=0;for(let n of String(t).split(`
63
+ `))zE.test(n)&&(e=Math.max(e,n.trimEnd().length));return e}function mu(t,e){let n=jt[t];if(!n?.busy)return{state:"idle",reason:null};if(wu(t,e))return{state:"unknown",reason:"blocked"};if(n.up&&!n.up.test(e))return{state:"idle",reason:null};if(n.busy.test(e))return{state:"busy",reason:null};if(n.busyAlt&&n.busyAlt.test(e))return{state:"busy",reason:null};let r=JE(e);return t==="claude"&&r>0&&r<VE?{state:"unknown",reason:"narrow"}:{state:"idle",reason:null}}function hu(t,e){return mu(t,e).state}function pw(t,e){if(t!=="claude")return!1;let n=String(e||"").split(`
64
+ `).slice(-XE).join(`
65
+ `);return YE.test(n)}function As(t,e){return hu(t,e)==="busy"}function _i(t,e){return hu(t,e)!=="idle"}function Ii(t,e){let n=jt[t];return n?.up?n.up.test(e):!0}function ZE(t,e){let n=jt[t];return n?wu(t,e)?!1:n.up.test(e)&&hu(t,e)==="idle":!0}function wu(t,e){let n=jt[t];return n?n.auth?.test(e)&&!n.up.test(e)?!0:n.block?.test(e)?t==="codex"?!0:!n.up.test(e):!1:!1}async function fw(t,e,n){let r=Date.now()+n,o=0;for(await dr(t).catch(()=>{});;){let s=await Tt(t);if(ZE(e,s)){await _n(Ts);return}if(e==="cursor"&&WE.test(s)&&!jt.cursor.up.test(s)&&o<3){if(!dw(t,"cursor-trust")){await _n(pu);continue}o+=1,await G({flow:"agent-ready",phase:"gate-accept",sessionName:t,agent:e,attempt:o}).catch(()=>{}),await Pt(t,"a",{enter:!1,kind:"cursor-trust-accept"}),await _n(Ts);continue}if(e==="codex"&&o<3){let a=KE(s);if(a){if(!dw(t,`codex-update:${a.from}->${a.to}`)){await _n(pu);continue}o+=1,await G({flow:"agent-ready",phase:"gate-accept",sessionName:t,agent:e,attempt:o,update:`${a.from} -> ${a.to}`}).catch(()=>{}),await Pt(t,"3",{enter:!1,kind:"codex-update-skip"}),ow({sessionName:t,from:a.from,to:a.to}),await _n(Ts);continue}}if(Date.now()>r){if(wu(e,s)){let a=`${e} is blocked on an interactive prompt`;throw e==="codex"?a=jt.codex.auth.test(s)?"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":e==="cursor"&&jt.cursor.auth.test(s)?a="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":e==="claude"&&jt.claude.auth.test(s)?a="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":e==="claude"&&jt.claude.block.test(s)&&(a='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'),G({flow:"agent-ready",phase:"blocked",sessionName:t,agent:e,timeoutMs:n,gateAccepts:o,error:a}).catch(()=>{}),new Error(a)}if(await to(t)){let a=`${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.`;throw G({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:t,agent:e,timeoutMs:n,gateAccepts:o,error:a}).catch(()=>{}),new Error(a)}console.warn(`[agent-ready] ${e} readiness unconfirmed in ${t} after ${n}ms \u2014 driving the box anyway.`),G({flow:"agent-ready",phase:"timeout",sessionName:t,agent:e,timeoutMs:n,gateAccepts:o,paneBlocked:!!jt[e]?.block?.test(s),paneUp:!!jt[e]?.up?.test(s),paneBusy:!!jt[e]?.busy?.test(s)}).catch(()=>{}),await _n(Ts);return}await _n(pu)}}function mw({agent:t,agentCmd:e}={}){let n=e?vn(e):vn(t||"");return{label:n,realClaude:e?ur(e):n==="claude",realCodex:e?/codex/.test(e)&&!/fake-codex|fake-lead/.test(e):n==="codex",realCursor:e?/cursor/.test(e)&&!/fake-cursor|fake-box/.test(e):n==="cursor"}}function Es({cwd:t,sessionName:e,agent:n,agentCmd:r}={}){let{realCodex:o,realCursor:s}=mw({agent:n,agentCmd:r});return!e||!o&&!s?null:In({cwd:t,sessionName:e,agent:n,agentCmd:r}).catch(()=>{})}async function In({cwd:t,sessionId:e,sessionName:n,agent:r,agentCmd:o,timeoutMs:s=HE()}={}){let{label:a,realClaude:i,realCodex:c,realCursor:l}=mw({agent:r,agentCmd:o});if(i&&t&&await gn(t),c&&t&&await qr(t),l&&t&&await Kr(t),(i||c||l)&&n){await fw(n,a,s);return}let u=jt[r]?r:jt[a]?a:null;if(process.env.BOSTRAT_FAKE_POLL_READY==="1"&&n&&u){await fw(n,u,s);return}await _n(Ts)}var HE,pu,Ts,jt,WE,qE,GE,Ei,VE,zE,YE,XE,Ri=M(()=>{qt();ls();ti();ei();du();Ai();Ke();HE=()=>Number(process.env.BOSTRAT_AGENT_READY_TIMEOUT_MS)||9e4,pu=Number(process.env.BOSTRAT_AGENT_READY_POLL_MS)||500,Ts=Number(process.env.BOSTRAT_AGENT_READY_SETTLE_MS)||800,jt={claude:{up:/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/,busy:/esc to interrupt/,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:/(^|\n)\s*›/,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/}},WE=/Trust this workspace|\[a\]\s*Trust/,qE=/Update available!\s*([\d][\w.-]*)\s*->\s*([\d][\w.-]*)/;GE=()=>Number(process.env.BOSTRAT_GATE_RESEND_MS)||3e3,Ei=new Map;VE=68,zE=/^\s*[─━]{10,}\s*$/;YE=/\bWaiting for \d+\b[^\n]*\bto finish\b|\/workflows to (?:stop|monitor)\b/,XE=15});function $e(t){return t==="codex"?{enter:!0,submitDelayMs:QE}:t==="claude"?{enter:!0,submitDelayMs:t_}:{enter:!0}}var QE,t_,_s=M(()=>{QE=(()=>{let t=Number(process.env.BOSTRAT_CODEX_SUBMIT_SETTLE_MS??120);return Number.isFinite(t)&&t>=0?t:120})(),t_=(()=>{let t=Number(process.env.BOSTRAT_CLAUDE_SUBMIT_SETTLE_MS??120);return Number.isFinite(t)&&t>=0?t:120})()});function pr(t){let e=String(t||"").toLowerCase();if(!e.trim())return null;let n=null;for(let r of e_){let o=0;for(let s of n_[r])s.test(e)&&o++;o>0&&(!n||o>n.score)&&(n={category:r,score:o})}return n}function hw(t){let e=0,n=0;for(let[r,o]of Object.entries(t||{}))r_.has(r)&&(e+=o||0),o_.has(r)&&(n+=o||0);return e>=5&&n===0?{category:"research",score:1}:n>=3?{category:"feature-build",score:1}:null}function Is(t){return String(t||"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").replace(/[-_/]+/g," ")}var e_,n_,r_,o_,gu=M(()=>{e_=["bug-fix","orchestration","design","ops-infra","docs-writing","research","feature-build"],n_={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 out\b/,/\btalk through\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/],"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/],design:[/\bdesign/,/\bui\b/,/\bux\b/,/\bstyl(e|es|ing)\b/,/\bcss\b/,/\blayout\b/,/\bmock-?up/,/\brender(ing|s)?\b/,/\bpolish/,/\btheme\b/,/\bfonts?\b/,/\bresponsive\b/,/\banimation/,/\bvisual/,/\bpopover\b/],orchestration:[/\bhand[ -]?(off|over)/,/\bhand (it|the lead|this) (over|off)\b/,/\bdelegat/,/\bsubtask/,/\bmerge[ -]?back\b/,/\borchestrat/,/\b(switch|change) (the )?model\b/,/\bmodel switch/],"docs-writing":[/\bdocs?\b/,/\bdocument/,/\bmemo\b/,/\breadme\b/,/\bwrite-?up\b/,/\bchangelog\b/,/\bclaude\.md\b/,/\bblog/,/\bproofread/,/\bcopy(edit|writ)/],"ops-infra":[/\bdeploy/,/\bsystemd\b/,/\bdaemon\b/,/\btmux\b/,/\bdns\b/,/\bwireguard\b/,/\brestart/,/\bnginx\b/,/\bprovision/,/\binstall/,/\bupgrade/,/\bcron\b/,/\bbackups?\b/,/\bcertificat/,/\bssh\b/,/\bsecrets?\b/]};r_=new Set(["Read","Grep","Glob","LS","WebSearch","WebFetch","NotebookRead"]),o_=new Set(["Edit","Write","MultiEdit","NotebookEdit"])});function bw(t){let e=Is(String(t||"")).toLowerCase(),n=[];for(let r of e.split(/[^a-z0-9]+/))r.length<2||s_.has(r)||n.push(r);return n}function a_(t){let e=[];for(let n of t||[]){let r=n.payload||{},o=String(r.text||"").trim();if(n.type==="turn.user"){if(n.source==="hook"||!o)continue;e.push(yw(n,"user",o))}else if(n.type==="turn.agent"){if(!o)continue;e.push(yw(n,"assistant",o))}}return e}function yw(t,e,n){let r=pr(n);return{id:t.id,seq:t.seq,ts:t.payload?.ts??t.ts,role:e,boxId:t.boxId??null,provider:t.provider??null,text:n,tags:r?[r.category]:[]}}function Rs(t){let e=a_(t),n=new Map,r=new Array(e.length).fill(0),o=0;e.forEach((a,i)=>{let c=bw(a.text);r[i]=c.length,o+=c.length;let l=new Map;for(let u of c)l.set(u,(l.get(u)||0)+1);for(let[u,f]of l){let d=n.get(u);d||n.set(u,d=new Map),d.set(i,f)}});let s=e.length;return{chunks:e,postings:n,lengths:r,N:s,avgdl:s?o/s:0}}function $i(t,e,n={}){let{k:r=8,role:o=null,tag:s=null,boxId:a=null}=n;if(!t||!t.N)return[];let i=[...new Set(bw(e))];if(!i.length)return[];let c=new Map;for(let u of i){let f=t.postings.get(u);if(!f)continue;let d=f.size,p=Math.log(1+(t.N-d+.5)/(d+.5));for(let[h,w]of f){let y=t.lengths[h],k=w+ww*(1-gw+gw*(y/(t.avgdl||1))),x=p*(w*(ww+1)/k);c.set(h,(c.get(h)||0)+x)}}let l=[];for(let[u,f]of c){let d=t.chunks[u];o&&d.role!==o||s&&!d.tags.includes(s)||a&&d.boxId!==a||l.push({chunk:d,score:f})}return l.sort((u,f)=>f.score-u.score||f.chunk.seq-u.chunk.seq),l.slice(0,r)}var ww,gw,s_,yu=M(()=>{gu();ww=1.5,gw=.75,s_=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 Oi from"node:fs/promises";import kw from"node:path";async function i_(t){let e=kw.join(t,".bostrat","events"),n;try{n=await Oi.readdir(e)}catch{return Rs([])}let r=[];for(let o of n)if(o.endsWith(".ndjson"))try{let s=await Oi.readFile(kw.join(e,o),"utf8");for(let a of s.split(`
66
+ `))if(a.trim())try{r.push(JSON.parse(a))}catch{}}catch{}return Rs(r)}function c_(t){let e=String(t||""),n=a=>{let i=e.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}
67
+ ${o}`.trim()||e.slice(0,2e3)}function l_(t,e,{k:n=6,maxChars:r=4e3,exclude:o=null}={}){let s=$i(t,e,{k:n*2+4}),a=[],i=0;for(let{chunk:c}of s){if(o&&o(c))continue;let l=c.role==="user"?"Operator":`Agent${c.provider?` (${c.provider})`:""}`,u=c.text.trim(),f=u.length>800?u.slice(0,800)+"\u2026":u,d=`- **${l}:** ${f}`;if(i+d.length>r||(a.push(d),i+=d.length,a.length>=n))break}return a.length?["",`## ${xw}, 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(`
68
+ `):""}async function Sw(t,e,n={}){let{k:r=6,maxChars:o=4e3,exclude:s=null}=n;try{let a=await Oi.readFile(e,"utf8");if(a.includes(xw))return{appended:!1,reason:"already-enriched"};let i=await i_(t);if(!i.N)return{appended:!1,reason:"empty-index"};let c=l_(i,c_(a),{k:r,maxChars:o,exclude:s});return c?(await Oi.appendFile(e,`
69
69
  `+c),{appended:!0,chars:c.length,chunks:c.split(`
70
- - `).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 Xh,Qh=M(()=>{cu();Xh="Relevant prior discussion (verbatim, retrieved"});import lu from"node:fs/promises";import zr from"node:path";import NE from"node:os";import{EventEmitter as BE}from"node:events";import{randomUUID as DE}from"node:crypto";function bi(t){return t?.cwd?zr.join(t.cwd,".bostrat","events"):zr.join(uu,"events")}async function UE(t,e){if(!yi.has(e)){let o=(await L(t,e)).reduce((s,a)=>a.seq>s?a.seq:s,0);yi.set(e,o)}let n=yi.get(e)+1;return yi.set(e,n),n}function HE(t,e){let n=Array.isArray(t?.epochs)?t.epochs:null;if(!(!n||n.length===0)){if(!Number.isFinite(e))return n.length-1;for(let r=n.length-1;r>=0;r--){let o=n[r].startedAt;if(o==null||o<=e)return r}return 0}}async function I(t,e){let n=typeof t=="string"?t:t?.id;if(!n)throw new Error("appendEvent: a track (or trackId) is required");if(!e||!jE.has(e.type))throw new Error(`appendEvent: unknown event type "${e?.type}"`);if(e.actor&&!LE.has(e.actor))throw new Error(`appendEvent: bad actor "${e.actor}"`);if(e.source&&!FE.has(e.source))throw new Error(`appendEvent: bad source "${e.source}"`);let r=typeof t=="string"?zr.join(uu,"events"):bi(t),o=e.epoch;if(o==null&&typeof t=="object"&&e.boxId&&Array.isArray(t?.boxes)){let c=t.boxes.find(l=>l.name===e.boxId);o=HE(c,Number(e.payload?.ts??e.ts)||Date.now())}let s=await UE(r,n),a=e.userId??process.env.BOSTRAT_OWNER??null,i={id:e.id||DE(),trackId:n,boxId:e.boxId??null,...o!=null?{epoch:o}:{},...a?{userId:a}:{},seq:s,ts:e.ts??Date.now(),type:e.type,actor:e.actor??"system",provider:e.provider??null,source:e.source??"orchestrator",payload:e.payload??{},...e.causationId?{causationId:e.causationId}:{},...e.correlationId?{correlationId:e.correlationId}:{}};return await lu.mkdir(r,{recursive:!0}),await lu.appendFile(tw(r,n),JSON.stringify(i)+`
71
- `),Yt.emit("event",i),Yt.emit(`track:${n}`,i),i}async function L(t,e){let n,r;typeof t=="string"&&e?(n=t,r=e):(r=typeof t=="string"?t:t?.id,n=typeof t=="string"?zr.join(uu,"events"):bi(t));let o;try{o=await lu.readFile(tw(n,r),"utf8")}catch{return[]}let s=[];for(let a of o.split(`
72
- `))if(a.trim())try{s.push(JSON.parse(a))}catch{}return s}function ew(t,e){let n=`track:${t}`;return Yt.on(n,e),()=>Yt.off(n,e)}var jE,LE,FE,Yt,uu,tw,yi,ct=M(()=>{jE=new Set(["session.ready","turn.user","turn.agent","turn.retracted","peer.message","turn.interrupted","tool.called","tool.result","prompt.raised","prompt.answered","prompt.autoRejected","box.fullscreen.detected","box.fullscreen.answered","context.usage","cost.recorded","memory.seed","handoff.artifact","code.pushed","handoff.started","handoff.step","handoff.done","handoff.failed","subtask.delegated","subtask.merged","job.started","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","notify.raised","usage.cap.hit","usage.cap.warning","provider.connected","track.summary.recorded","track.circuit.tagged","blueprint.item.bound","changelog.published","stall.detected","error"]),LE=new Set(["user","agent","orchestrator","system","peer"]),FE=new Set(["hook","otel","statusline","transcript","pane","orchestrator","vendor"]),Yt=new BE;Yt.setMaxListeners(0);uu=process.env.BOSTRAT_STATE_DIR||zr.join(process.env.HOME||NE.tmpdir(),".bostrat");tw=(t,e)=>zr.join(t,`${e}.ndjson`),yi=new Map});function WE(t){let e=[],n="",r=null;for(let o=0;o<t.length;o++){let s=t[o];if(r){n+=s,s===r&&t[o-1]!=="\\"&&(r=null);continue}if(s==="'"||s==='"'||s==="`"){r=s,n+=s;continue}if(s==="&"&&t[o+1]==="&"){e.push(n),n="",o++;continue}if(s==="|"&&t[o+1]==="|"){e.push(n),n="",o++;continue}if(s==="|"||s===";"||s===`
73
- `){e.push(n),n="";continue}n+=s}return e.push(n),e.map(o=>o.trim()).filter(Boolean)}function ks(t){let e=[],n="",r=null,o=!1,s=()=>{if(o){if(/^\d*[<>]/.test(n)||n.startsWith(">")){n="",o=!1;return}e.push(n),n="",o=!1}};for(let a=0;a<t.length;a++){let i=t[a];if(r){i===r&&t[a-1]!=="\\"?r=null:n+=i,o=!0;continue}if(i==="'"||i==='"'){r=i,o=!0;continue}if(i==="<"&&t[a+1]==="<")return s(),e.push("<<"),e;if(/\s/.test(i)){s();continue}n+=i,o=!0}return s(),e}function xs(t){let e=t;for(;e.length&&/^[A-Za-z_][A-Za-z0-9_]*=/.test(e[0]);)e=e.slice(1);for(;e.length&&(e[0]==="sudo"||e[0]==="time"||e[0]==="env");)e=e.slice(1);return e}function ft(t,e=new Set){let n=[];for(let r=1;r<t.length;r++){let o=t[r];if(o==="<<")break;if(ow(o)){e.has(o)&&r++;continue}n.push(o)}return n}function sw(t){let e=t.indexOf("-n"),n=e!==-1?t[e+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 GE(t){let e=sw(t),n=jt(ft(t).find(r=>!/^\d+(,\d+)?p$/.test(r)));return e&&n?e.from===e.to?`Read line ${e.from} of ${kt(n)}`:`Read lines ${e.from}\u2013${e.to} of ${kt(n)}`:t.includes("-i")&&n?`Edit ${kt(n)}`:null}function du(t){if(t.includes("--files")){let s=jt(ft(t,nw)[0]);return s&&s!=="."?`List files in ${Jr(s)}`:"List files"}let e=ft(t,nw),n=e[0];if(!n)return null;let r=jt(e.slice(1).find(s=>s!==".")),o=Yr(n,40);return r?`Search for \u201C${o}\u201D in ${Jr(r)}`:`Search for \u201C${o}\u201D`}function fu(t){let e=ft(t,new Set(["--prefix"])),n=e[0];return n?n==="test"||n==="t"?"Run tests":n==="run"||n==="run-script"?e[1]?`Run ${e[1]}`:null:n==="ci"||n==="install"||n==="i"||n==="add"?"Install dependencies":null:null}function pu(t,e){if(t.includes("-e")||t.includes("--eval")||t.includes("-c")||t[1]==="-"||t.includes("<<"))return`Run an inline ${e} script`;if(t.includes("--test"))return"Run tests";let n=ft(t)[0];return n?`Run ${kt(n)}`:null}function VE(t){let e=ft(t),n=e[0],r=e.find(a=>/\.(service|timer|socket|target)$/.test(a))||e[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 rw(t){return t.find(e=>/^https?:\/\//.test(e))||null}function YE(t){let e=xs(ks(t));if(!e.length)return null;if(/^(ba|z)?sh$/.test(kt(e[0]))&&(e[1]==="-lc"||e[1]==="-c")&&e[2])return mu(e[2]);let n=kt(e[0]);if(JE.has(n))return null;if(e.includes("--version"))return`Check ${n} version`;if(n.endsWith(".sh"))return`Run ${n}`;let r=zE[n];return r?r(e.map((o,s)=>s===0?n:o)):null}function mu(t){let e=String(t||"").trim();if(!e)return null;let n=e.indexOf("<<");if(n!==-1){let i=e.indexOf(`
74
- `,n);i!==-1&&(e=e.slice(0,i))}let r=WE(e);for(let i=0;i<r.length-1;i++){let c=xs(ks(r[i])),l=xs(ks(r[i+1]));if(!(!c.length||!l.length)&&["nl","cat"].includes(kt(c[0]))&&kt(l[0])==="sed"){let u=sw(l),d=ft(c)[0];if(u&&d)return Yr(u.from===u.to?`Read line ${u.from} of ${kt(d)}`:`Read lines ${u.from}\u2013${u.to} of ${kt(d)}`,88)}}let o=[];for(let i of r){let c=YE(i);c&&o.push({d:c,head:kt(xs(ks(i))[0]||""),sub:ft(xs(ks(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":Yr(s?s.d:o[0].d,88)}var Yr,jt,kt,Jr,ow,nw,qE,KE,zE,JE,aw=M(()=>{Yr=(t,e)=>t.length>e?`${t.slice(0,e).trimEnd()}\u2026`:t,jt=t=>t&&!/[$`]/.test(t)?t:null,kt=t=>t.replace(/\/+$/,"").split("/").pop()||t,Jr=t=>{let e=t.replace(/\/+$/,"").split("/").filter(Boolean);return e.length>3?e.slice(-2).join("/"):t},ow=t=>t.startsWith("-"),nw=new Set(["-g","--glob","-t","--type","-A","-B","-C","-m","--max-count","-e","--regexp","-f","--file"]);qE={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:t=>t[1]?`Clone ${kt(t[1])}`:"Clone repository",checkout:()=>"Switch branches",switch:()=>"Switch branches",restore:()=>"Restore files",reset:()=>"Reset git state",branch:(t,e)=>e.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"},KE={pr:t=>({create:"Create a pull request",list:"List pull requests",view:"View a pull request",merge:"Merge a pull request",checks:"Check PR status"})[t[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"};zE={git:t=>{let e=ft(t,new Set(["-C","-c"])),n=qE[e[0]];return n?n(e,t):null},gh:t=>{let e=ft(t),n=KE[e[0]];return n?n(e):null},sed:GE,rg:du,grep:du,egrep:du,nl:t=>{let e=jt(ft(t)[0]);return e?`Read ${kt(e)}`:null},cat:t=>{let e=jt(ft(t)[0]);return e?`Read ${kt(e)}`:null},head:t=>{let e=jt(ft(t,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return e?`Read the start of ${kt(e)}`:null},tail:t=>{let e=jt(ft(t,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return e?`Read the end of ${kt(e)}`:null},wc:t=>{let e=jt(ft(t)[0]);return e?`Count lines in ${kt(e)}`:"Count input lines"},ls:t=>{let e=jt(ft(t)[0]);return e&&e!=="."?`List files in ${Jr(e)}`:"List files"},find:t=>jt(t[1])&&!ow(t[1])&&t[1]!=="."?`Find files in ${Jr(t[1])}`:"Find files",tree:()=>"List the directory tree",mkdir:t=>{let e=jt(ft(t)[0]);return e?`Create directory ${Jr(e)}`:null},touch:t=>{let e=jt(ft(t)[0]);return e?`Create ${kt(e)}`:null},rm:t=>{let e=jt(ft(t)[0]);return e?`Delete ${Jr(e)}`:null},mv:t=>{let e=jt(ft(t)[0]);return e?`Move ${kt(e)}`:null},cp:t=>{let e=jt(ft(t)[0]);return e?`Copy ${kt(e)}`:null},chmod:t=>{let e=jt(ft(t)[1]);return e?`Change permissions on ${kt(e)}`:null},diff:t=>{let e=ft(t);return e.length>=2?`Compare ${kt(e[0])} and ${kt(e[1])}`:null},curl:t=>{let e=rw(t);return e?`Fetch ${Yr(e,56)}`:"Fetch a URL"},wget:t=>{let e=rw(t);return e?`Fetch ${Yr(e,56)}`:"Fetch a URL"},npm:fu,pnpm:fu,yarn:fu,npx:t=>{let e=ft(t)[0];return e?`Run ${e}`:null},node:t=>pu(t,"Node"),python:t=>pu(t,"Python"),python3:t=>pu(t,"Python"),make:t=>{let e=ft(t)[0];return e?`Run make ${e}`:"Run make"},systemctl:VE,journalctl:t=>{let e=t.findIndex(r=>r==="-u"||r==="--unit"||r==="--user-unit"),n=e!==-1?t[e+1]:null;return n?`Read ${n.replace(/\.service$/,"")} logs`:"Read system logs"},tmux:t=>{let e=ft(t,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"}[e]||null},ps:()=>"List processes",which:t=>{let e=ft(t)[0];return e?`Locate ${e}`:null},command:t=>t[1]==="-v"&&t[2]?`Locate ${t[2]}`:null,fly:t=>{let e=ft(t)[0];return e==="deploy"?"Deploy to Fly":e?`Run fly ${e}`:null}},JE=new Set(["pwd","echo","cd","sleep","true","false","test","[","set","export","exit","read"])});function Xr(t){let e=t.split(`
75
- `).map(n=>n.trim()).find(Boolean)||t;return e.length>88?`${e.slice(0,88).trimEnd()}\u2026`:e}function An(t,e=""){let n=e.trim();return n||mu(t)||Xr(t)}function hu(t,e){if(t){if(Array.isArray(t)){for(let n of t)hu(n,e);return}if(typeof t=="object"){if(t.type==="tool_use"&&wu.has(t.name)){let n=String(t.input?.command||"").trim();n&&e.push({id:t.id||null,tool:t.name,command:n,description:String(t.input?.description||"").trim()})}for(let n of Object.values(t))hu(n,e)}}}async function iw(t,{maxBytes:e=1048576,limit:n=400}={}){let r;try{r=await Jt(t,e)}catch{return[]}let o=[];for(let s of r.split(`
76
- `)){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(hu(c.content,l),!l.length)continue;let u=i.timestamp?Date.parse(i.timestamp):null;for(let d of l)o.push({...d,summary:An(d.command,d.description),ts:u})}return o.slice(-n)}function cw(t,e){let n=e.filter(l=>l.role==="assistant"&&(l.text||"").trim()).sort((l,u)=>(l.ts||0)-(u.ts||0)),r=[...t].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((m,w)=>w>=s&&(m.ts||0)>(l.ts||0)),d=u===-1?r.length:u,f=r.slice(s,d);if(s=d,!f.length)continue;let p=f.map(m=>({...m,n:i(m)}));o.push({id:`batch-${l.ts}-${l.box}`,anchorTs:l.ts,anchorBox:l.box,agent:l.agent,boxRole:l.boxRole,commands:p,ts:Math.max(...p.map(m=>m.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 wu,Zr=M(()=>{we();aw();wu=new Set(["Bash"])});import lw from"node:fs";import yu from"node:fs/promises";import gu from"node:path";import XE from"node:os";async function uw(t){try{return await yu.realpath(t)}catch{return t}}function QE(t=ZE){let e=[],n=r=>{let o;try{o=lw.readdirSync(r,{withFileTypes:!0})}catch{return}for(let s of o){let a=gu.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{e.push({id:i?i[1]:null,file:a,mtimeMs:lw.statSync(a).mtimeMs})}catch{}}}};return n(t),e.sort((r,o)=>o.mtimeMs-r.mtimeMs)}async function t_(t,e=1048576){let n;try{n=await yu.open(t,"r")}catch{return""}try{let r=Buffer.alloc(Math.min(e,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(`
77
- `);if(i!==-1)return o.slice(0,i);if(s+=a,o.length>=e)break}return o}finally{await n.close()}}async function e_(t){let e=await t_(t);if(!e)return null;let n;try{n=JSON.parse(e)}catch{return null}return n?.type==="session_meta"&&n?.payload?.cwd||null}async function cr(t,e){if(!t&&!e)return null;let n=QE();if(e){let o=n.find(s=>s.id===e);return o||null}let r=await uw(t);for(let o of n){let s=await e_(o.file);if(s&&(s===t||await uw(s)===r))return o}return null}async function dw(t,e,{limit:n=80,maxBytes:r=524288}={}){let o=await cr(t,e);if(!o)return[];let s;try{s=await Jt(o.file,r)}catch{return[]}let a=[],i=null,c=[],l=!1,u=!1,d=null;for(let f of s.split(`
78
- `)){let p=f.trim();if(!p||p[0]!=="{")continue;let m;try{m=JSON.parse(p)}catch{continue}if((m.type==="turn_context"&&m.payload?.model||m.type==="session_meta"&&m.payload?.model)&&(i=m.payload.model),m.type==="event_msg"){let S=m.payload?.type;S==="task_started"?(l=!0,u=!1,d=m.payload?.turn_id||null):S==="task_complete"&&l&&(l=!1,!u&&m.payload?.last_agent_message==null&&a.push({role:"assistant",failed:!0,text:ku,sourceId:m.payload?.turn_id||d||void 0,ts:m.timestamp?Date.parse(m.timestamp):null,model:i}));continue}if(m.type!=="response_item")continue;let w=m.payload;if(!w)continue;if((w.type==="function_call"||w.type==="custom_tool_call")&&w.name){u=!0,bu.has(w.name)||c.push(w.name);continue}if(w.type!=="message"||w.role!=="assistant")continue;u=!0;let y=r_(w.content),k=c.length?c.slice():null;c=[],!(!y&&!k)&&a.push({role:"assistant",text:y,tools:k||void 0,ts:m.timestamp?Date.parse(m.timestamp):null,model:i})}if(i)for(let f of a)f.model||(f.model=i);return a.slice(-n)}function o_(t){if(typeof t?.cmd=="string"&&t.cmd.trim())return t.cmd.trim();let e=t?.command;return typeof e=="string"&&e.trim()?e.trim():Array.isArray(e)&&e.length?e.length===3&&/^(ba)?sh$/.test(e[0])&&e[1]==="-lc"?String(e[2]).trim():e.map(String).join(" ").trim():null}function s_(t){let e=t[0];if(e!=='"'&&e!=="'"&&e!=="`")return null;let n="";for(let r=1;r<t.length;r++){let o=t[r];if(o==="\\"){let s=t[++r];if(s===void 0)return null;if(s==="n")n+=`
79
- `;else if(s==="t")n+=" ";else if(s==="r")n+="\r";else if(s==="u")if(t[r+1]==="{"){let a=t.indexOf("}",r+2);if(a===-1)return null;n+=String.fromCodePoint(parseInt(t.slice(r+2,a),16)),r=a}else n+=String.fromCharCode(parseInt(t.slice(r+1,r+5),16)),r+=4;else n+=s}else{if(o===e)return n;if(e==="`"&&o==="$"&&t[r+1]==="{")return null;n+=o}}return null}function a_(t){let e=String(t||""),n=[],r=/exec_command\s*\(/g;for(let s;s=r.exec(e);)n.push(s.index+s[0].length);let o=[];return n.forEach((s,a)=>{let i=e.slice(s,a+1<n.length?n[a+1]:e.length),c=/(?:^|[{,\s])["'`]?cmd["'`]?\s*:\s*/.exec(i);if(!c)return;let l=s_(i.slice(c.index+c[0].length).trimStart());l&&l.trim()&&o.push(l.trim())}),o}async function fw(t,e,{limit:n=400,maxBytes:r=524288}={}){let o=await cr(t,e);if(!o)return[];let s;try{s=await Jt(o.file,r)}catch{return[]}let a=[];for(let i of s.split(`
80
- `)){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"&&Ss.has(u.name)){let p;try{p=JSON.parse(u.arguments||"{}")}catch{continue}let m=o_(p);m&&(d=[m])}else u.type==="custom_tool_call"&&u.name==="exec"&&(d=a_(u.input));if(!d.length)continue;let f=u.call_id||u.id||null;d.forEach((p,m)=>{a.push({id:f?m?`${f}:${m}`:f:null,tool:u.name,command:p,description:"",summary:An(p),ts:l.timestamp?Date.parse(l.timestamp):null})})}return a.slice(-n)}async function pw(t,e){let n=await cr(t,e);if(!n)return null;try{return Math.round((await yu.stat(n.file)).mtimeMs)}catch{return n.mtimeMs||null}}var ZE,n_,r_,Ss,bu,ku,Qr=M(()=>{we();Zr();ZE=process.env.BOSTRAT_CODEX_SESSIONS||gu.join(process.env.CODEX_HOME||gu.join(XE.homedir(),".codex"),"sessions");n_=new Set(["output_text","text"]),r_=t=>typeof t=="string"?t.trim():Array.isArray(t)?t.filter(e=>e&&typeof e.text=="string"&&n_.has(e.type)).map(e=>e.text).join(`
81
- `).trim():"";Ss=new Set(["exec_command","shell","exec"]),bu=new Set(["wait","write_stdin"]),ku="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 vs(t,e){if(t!=="claude")return null;let n=String(e).replace(/\r/g,"").split(`
82
- `).map(c=>c.replace(/\s+$/,"")),r=-1;for(let c=n.length-1;c>=0;c--)if(mw.test(n[c])){r=c;break}if(r<=0)return null;let o=-1;for(let c=r-1;c>=0;c--)if(mw.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(i_);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 It(t){return String(t||"").replace(/\s+/g," ").trim()}function hw(t,e,{slackMs:n=2e4}={}){let r=It(e?.text);return!r||typeof e?.at!="number"?!1:(Array.isArray(t)?t:[]).some(o=>o?.role==="user"&&typeof o.ts=="number"&&o.ts>=e.at-n&&It(o.text).includes(r))}function ww(t,e,n,{busy:r=!1}={}){let o=vs(t,n);return o&&xu(e,o)?"stuck":r||o?"submitted":"unknown"}function xu(t,e){let n=It(t),r=It(e).replace(/^…\s*/,"").replace(/\s*…$/,"");return!n||!r||r.length<Math.min(n.length,12)?!1:n===r||n.includes(r)}var mw,i_,Su=M(()=>{mw=/^\s*─{8,}\s*$/,i_=/^❯[  ]?(.*)$/});function p_(t){return c_.test(String(t||"").trimStart())}function bw(t){let e=String(t||"");if(!p_(e.trimStart()))return null;let n=e.replace(l_,"").trim(),r=m_(n),o=[];for(let u of d_){let d=u.from.map(f=>to(r.get(f))).find(f=>f&&!gw(f));d&&o.push({h:u.h,text:Ts(d,u_)})}let s=to(r.get("Current Work"))||to(r.get("Primary Request and Intent"))||w_(n),a=xi(s),i=Ts(ki(Au(a[0]||"")),f_)||"Context resumed from summary",c=[],l=a.slice(1).join(" ").trim();l&&c.push(Ts(ki(Au(l)),Tu));for(let u of["Pending Tasks","Optional Next Step"]){let d=xi(to(r.get(u)))[0]||"";if(!(!d||gw(d))){c.push(Ts(`Left to do: ${ki(Au(d))}`,Tu));break}}if(!c.length){let u=xi(to(r.get("Problem Solving"))||"")[0];u&&c.push(Ts(ki(u),Tu))}return{kind:"resume-summary",title:i,bullets:c.slice(0,2),sections:o,rawChars:e.length}}function m_(t){let e=new Map,n=[];vu.lastIndex=0;for(let r=vu.exec(t);r;r=vu.exec(t))n.push({name:h_(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??t.length;e.has(n[r].name)||e.set(n[r].name,t.slice(n[r].end,o).trim())}return e}function h_(t){return yw.find(n=>n.toLowerCase()===t.toLowerCase())||t}function to(t){return t?String(t).replace(/```[\s\S]*?(?:```|$)/g," ").split(`
83
- `).map(e=>e.replace(/^[ \t]*(?:[-*•]|\d+[.)]|[a-z][.)])[ \t]+/i,"").trim()).filter(e=>e&&!/^#{1,6}[ \t]/.test(e)).join(" ").replace(/\*\*(.+?)\*\*/g,"$1").replace(/`([^`]+)`/g,"$1").replace(/\s+/g," ").trim():""}function w_(t){let e=t.replace(/^[\s\S]*?\bSummary:\s*/i,"");return to(e.split(/\n{2,}/).slice(0,2).join(" "))}function xi(t){let e=String(t||"").trim();if(!e)return[];let r=e.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 Au(t){return String(t||"").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)/,e=>e.toUpperCase()).trim()}function ki(t){return String(t||"").replace(/(?<![:\w/])(?:\/[\w.@+-]+){4,}/g,e=>`\u2026/${e.split("/").slice(-2).join("/")}`)}function gw(t){return/^(none|nothing|n\/a|no pending|there are no)\b/i.test(String(t||"").trim())}function Ts(t,e){let n=String(t||"").trim();if(n.length<=e)return n;let r=xi(n),o="";for(let i of r){let c=o?`${o} ${i}`:i;if(c.length>e)break;o=c}if(o.length>=Math.min(60,e*.4))return o;let s=n.slice(0,e),a=s.lastIndexOf(" ");return`${(a>e*.6?s.slice(0,a):s).replace(/[,;:.\s]+$/,"")}\u2026`}var c_,yw,vu,l_,u_,d_,f_,Tu,kw=M(()=>{c_=/^This session is being continued from a previous conversation that ran out of context\./,yw=["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"],vu=new RegExp(String.raw`^[ \t]*#{0,4}[ \t]*(?:\d+[.)][ \t]*)?\*{0,2}(${yw.join("|")})[:*\t ]*$`,"gim"),l_=/\n+If you need specific details from before compaction[\s\S]*$|\n+Continue the conversation from where it left off[\s\S]*$/,u_=420,d_=[{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"]}],f_=116,Tu=168});function Sw(t){return Eu.has(String(t||"").replace(/^\//,"").toLowerCase())}function Si(t){let e=String(t||"").trim();if(!e)return null;let n=bw(e);if(n)return n;let r=e.match(g_);if(r)return{kind:"skill",name:r[1].split("/").filter(Boolean).pop()||"skill"};let o=e.match(y_);if(o)return{kind:"skill",name:o[1]};let s=e.match(b_);if(s){let i=s[1].toLowerCase();return Eu.has(i)?{kind:"suppress"}:{kind:"command",command:`/${i}`}}let a=e.match(R_);if(a&&Eu.has(a[1].toLowerCase()))return{kind:"suppress"};if(k_.test(e))return{kind:"suppress"};if(S_.test(e))return{kind:"suppress"};if(x_.test(e))return{kind:"suppress"};if(v_.test(e)){let i=l=>$_(e.match(l)?.[1].trim()||"")||null,c=i(I_);return{kind:"task",summary:i(T_)||"",taskId:i(A_),toolUseId:i(E_),status:i(__)?.toLowerCase()||null,resultHead:c?c.length>xw?`${c.slice(0,xw).trimEnd()}\u2026`:c:null}}return null}function $_(t){return t.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&amp;/g,"&")}function vw(t){return t?.kind==="skill"?`Ran the ${t.name} skill`:t?.kind==="command"?`Ran ${t.command}`:t?.kind==="task"?t.summary||"A background task finished":t?.kind==="resume-summary"?t.title?`Context resumed from summary: ${t.title}`:"Context resumed from summary":""}function Tw(t){return t?.kind==="skill"?"skill-run":t?.kind==="task"?"task-done":t?.kind==="resume-summary"?"context-resumed":"command-run"}var g_,y_,b_,k_,x_,S_,v_,T_,A_,E_,__,I_,xw,Eu,R_,_u=M(()=>{kw();g_=/^Base directory for this skill:\s*(\S+)/,y_=/^Run the "([^"]+)" workflow\./,b_=/<command-name>\s*\/?([a-z0-9:_-]+)\s*<\/command-name>/i,k_=/^<local-command-(?:stdout|caveat)>/i,x_=/^\[Image: original \d+x\d+, displayed at \d+x\d+\.\s*Multiply coordinates by [\d.]+ to map to original image\.\]$/,S_=/^Continue from where you left off\.$/,v_=/^<task-notification>/i,T_=/<summary>([\s\S]*?)<\/summary>/i,A_=/<task-id>([\s\S]*?)<\/task-id>/i,E_=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i,__=/<status>([\s\S]*?)<\/status>/i,I_=/<result>([\s\S]*?)(?:<\/result>|$)/i,xw=600,Eu=new Set(["model","clear","compact","login","exit","quit"]);R_=/^\/([a-z0-9:_-]+)$/i});import O_ from"node:crypto";function N_(t){let e=Array.isArray(t)?t:Array.isArray(t?.questions)?t.questions:null;if(!e||!e.length)return null;let n=[];for(let r of e.slice(0,Ew)){let o=As(r?.question);if(!o)return null;let s=Array.isArray(r?.options)?r.options:[],a=[];for(let i of s.slice(0,C_)){let c=As(i?.label);if(!c)return null;let l=As(i?.description);a.push(l?{label:c,description:l}:{label:c})}if(a.length<M_)return null;n.push({question:o,header:As(r?.header).slice(0,P_),multiSelect:r?.multiSelect===!0,options:a})}return n.length?n:null}function Ru(t){if(typeof t!="string"||!t.includes("```bostrat-question"))return null;Aw.lastIndex=0;let e=null;for(let o;o=Aw.exec(t);)e=o;if(!e||e.index+e[0].length<t.trimEnd().length)return null;let n;try{n=JSON.parse(e[2])}catch{return null}let r=N_(n);return r?{text:t.slice(0,e.index).trimEnd(),questions:r}:null}function $u(t,e,n){let r=O_.createHash("sha256").update(JSON.stringify(n)).digest("hex").slice(0,8);return`${t}:ask:${e||"turn"}:${r}`}function Ou(t,{leadBoxId:e,provider:n,isAnswered:r,maxQuestions:o=Ew}={}){if(!Array.isArray(t)||!e||!Iu.has(n))return null;let s=null;for(let l=t.length-1;l>=0;l--){let u=t[l];if(u?.kind==="prompt")return null;if(u?.kind==="message"){if(u.role!=="assistant")return null;s=u;break}}if(!s||s.box!==e||s.agent!==n)return null;let a=s.ask?.questions||Ru(s.text)?.questions;if(!a?.length)return null;let i=a.slice(0,Math.max(1,o)),c=$u(n,s.sourceId||s.id,a);return typeof r=="function"&&r(c)?null:{provider:n,box:e,promptId:c,groupId:c,answerMode:"say",source:"transcript",multiSelect:i[0].multiSelect,questionIndex:0,questionTotal:i.length,questions:i}}function _w(t,e,n){let r=[];(t?.questions||[]).forEach((a,i)=>{let c=(e?.[i]||[]).map(l=>a.options?.[l]?.label).filter(Boolean);c.length&&r.push({name:a.header||a.question,picks:c.join(", ")})});let o=As(n),s;return r.length?r.length===1?s=`${r[0].name}: ${r[0].picks}`:s=`Answers:
70
+ - `).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 xw,vw=M(()=>{yu();xw="Relevant prior discussion (verbatim, retrieved"});import bu from"node:fs/promises";import ro from"node:path";import u_ from"node:os";import{EventEmitter as d_}from"node:events";import{randomUUID as f_}from"node:crypto";function oo(t){return t?.cwd?ro.join(t.cwd,".bostrat","events"):ro.join(ku,"events")}async function w_(t,e){if(!Ci.has(e)){let o=(await F(t,e)).reduce((s,a)=>a.seq>s?a.seq:s,0);Ci.set(e,o)}let n=Ci.get(e)+1;return Ci.set(e,n),n}function g_(t,e){let n=Array.isArray(t?.epochs)?t.epochs:null;if(!(!n||n.length===0)){if(!Number.isFinite(e))return n.length-1;for(let r=n.length-1;r>=0;r--){let o=n[r].startedAt;if(o==null||o<=e)return r}return 0}}async function I(t,e){let n=typeof t=="string"?t:t?.id;if(!n)throw new Error("appendEvent: a track (or trackId) is required");if(!e||!p_.has(e.type))throw new Error(`appendEvent: unknown event type "${e?.type}"`);if(e.actor&&!m_.has(e.actor))throw new Error(`appendEvent: bad actor "${e.actor}"`);if(e.source&&!h_.has(e.source))throw new Error(`appendEvent: bad source "${e.source}"`);let r=typeof t=="string"?ro.join(ku,"events"):oo(t),o=e.epoch;if(o==null&&typeof t=="object"&&e.boxId&&Array.isArray(t?.boxes)){let c=t.boxes.find(l=>l.name===e.boxId);o=g_(c,Number(e.payload?.ts??e.ts)||Date.now())}let s=await w_(r,n),a=e.userId??process.env.BOSTRAT_OWNER??null,i={id:e.id||f_(),trackId:n,boxId:e.boxId??null,...o!=null?{epoch:o}:{},...a?{userId:a}:{},seq:s,ts:e.ts??Date.now(),type:e.type,actor:e.actor??"system",provider:e.provider??null,source:e.source??"orchestrator",payload:e.payload??{},...e.causationId?{causationId:e.causationId}:{},...e.correlationId?{correlationId:e.correlationId}:{}};return await bu.mkdir(r,{recursive:!0}),await bu.appendFile(Tw(r,n),JSON.stringify(i)+`
71
+ `),Zt.emit("event",i),Zt.emit(`track:${n}`,i),i}async function F(t,e){let n,r;typeof t=="string"&&e?(n=t,r=e):(r=typeof t=="string"?t:t?.id,n=typeof t=="string"?ro.join(ku,"events"):oo(t));let o;try{o=await bu.readFile(Tw(n,r),"utf8")}catch{return[]}let s=[];for(let a of o.split(`
72
+ `))if(a.trim())try{s.push(JSON.parse(a))}catch{}return s}function Aw(t,e){let n=`track:${t}`;return Zt.on(n,e),()=>Zt.off(n,e)}var p_,m_,h_,Zt,ku,Tw,Ci,at=M(()=>{p_=new Set(["session.ready","turn.user","turn.agent","turn.retracted","peer.message","turn.interrupted","tool.called","tool.result","prompt.raised","prompt.answered","prompt.autoRejected","box.fullscreen.detected","box.fullscreen.answered","context.usage","cost.recorded","memory.seed","handoff.artifact","code.pushed","handoff.started","handoff.step","handoff.done","handoff.failed","subtask.delegated","subtask.merged","job.started","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","notify.raised","usage.cap.hit","usage.cap.warning","provider.connected","track.summary.recorded","track.transferred","track.recovered","track.circuit.tagged","blueprint.item.bound","changelog.published","stall.detected","error"]),m_=new Set(["user","agent","orchestrator","system","peer"]),h_=new Set(["hook","otel","statusline","transcript","pane","orchestrator","vendor"]),Zt=new d_;Zt.setMaxListeners(0);ku=process.env.BOSTRAT_STATE_DIR||ro.join(process.env.HOME||u_.tmpdir(),".bostrat");Tw=(t,e)=>ro.join(t,`${e}.ndjson`),Ci=new Map});function y_(t){let e=[],n="",r=null;for(let o=0;o<t.length;o++){let s=t[o];if(r){n+=s,s===r&&t[o-1]!=="\\"&&(r=null);continue}if(s==="'"||s==='"'||s==="`"){r=s,n+=s;continue}if(s==="&"&&t[o+1]==="&"){e.push(n),n="",o++;continue}if(s==="|"&&t[o+1]==="|"){e.push(n),n="",o++;continue}if(s==="|"||s===";"||s===`
73
+ `){e.push(n),n="";continue}n+=s}return e.push(n),e.map(o=>o.trim()).filter(Boolean)}function $s(t){let e=[],n="",r=null,o=!1,s=()=>{if(o){if(/^\d*[<>]/.test(n)||n.startsWith(">")){n="",o=!1;return}e.push(n),n="",o=!1}};for(let a=0;a<t.length;a++){let i=t[a];if(r){i===r&&t[a-1]!=="\\"?r=null:n+=i,o=!0;continue}if(i==="'"||i==='"'){r=i,o=!0;continue}if(i==="<"&&t[a+1]==="<")return s(),e.push("<<"),e;if(/\s/.test(i)){s();continue}n+=i,o=!0}return s(),e}function Os(t){let e=t;for(;e.length&&/^[A-Za-z_][A-Za-z0-9_]*=/.test(e[0]);)e=e.slice(1);for(;e.length&&(e[0]==="sudo"||e[0]==="time"||e[0]==="env");)e=e.slice(1);return e}function gt(t,e=new Set){let n=[];for(let r=1;r<t.length;r++){let o=t[r];if(o==="<<")break;if(Iw(o)){e.has(o)&&r++;continue}n.push(o)}return n}function Rw(t){let e=t.indexOf("-n"),n=e!==-1?t[e+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 x_(t){let e=Rw(t),n=Lt(gt(t).find(r=>!/^\d+(,\d+)?p$/.test(r)));return e&&n?e.from===e.to?`Read line ${e.from} of ${Et(n)}`:`Read lines ${e.from}\u2013${e.to} of ${Et(n)}`:t.includes("-i")&&n?`Edit ${Et(n)}`:null}function xu(t){if(t.includes("--files")){let s=Lt(gt(t,Ew)[0]);return s&&s!=="."?`List files in ${so(s)}`:"List files"}let e=gt(t,Ew),n=e[0];if(!n)return null;let r=Lt(e.slice(1).find(s=>s!==".")),o=ao(n,40);return r?`Search for \u201C${o}\u201D in ${so(r)}`:`Search for \u201C${o}\u201D`}function Su(t){let e=gt(t,new Set(["--prefix"])),n=e[0];return n?n==="test"||n==="t"?"Run tests":n==="run"||n==="run-script"?e[1]?`Run ${e[1]}`:null:n==="ci"||n==="install"||n==="i"||n==="add"?"Install dependencies":null:null}function vu(t,e){if(t.includes("-e")||t.includes("--eval")||t.includes("-c")||t[1]==="-"||t.includes("<<"))return`Run an inline ${e} script`;if(t.includes("--test"))return"Run tests";let n=gt(t)[0];return n?`Run ${Et(n)}`:null}function S_(t){let e=gt(t),n=e[0],r=e.find(a=>/\.(service|timer|socket|target)$/.test(a))||e[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 _w(t){return t.find(e=>/^https?:\/\//.test(e))||null}function A_(t){let e=Os($s(t));if(!e.length)return null;if(/^(ba|z)?sh$/.test(Et(e[0]))&&(e[1]==="-lc"||e[1]==="-c")&&e[2])return Tu(e[2]);let n=Et(e[0]);if(T_.has(n))return null;if(e.includes("--version"))return`Check ${n} version`;if(n.endsWith(".sh"))return`Run ${n}`;let r=v_[n];return r?r(e.map((o,s)=>s===0?n:o)):null}function Tu(t){let e=String(t||"").trim();if(!e)return null;let n=e.indexOf("<<");if(n!==-1){let i=e.indexOf(`
74
+ `,n);i!==-1&&(e=e.slice(0,i))}let r=y_(e);for(let i=0;i<r.length-1;i++){let c=Os($s(r[i])),l=Os($s(r[i+1]));if(!(!c.length||!l.length)&&["nl","cat"].includes(Et(c[0]))&&Et(l[0])==="sed"){let u=Rw(l),f=gt(c)[0];if(u&&f)return ao(u.from===u.to?`Read line ${u.from} of ${Et(f)}`:`Read lines ${u.from}\u2013${u.to} of ${Et(f)}`,88)}}let o=[];for(let i of r){let c=A_(i);c&&o.push({d:c,head:Et(Os($s(i))[0]||""),sub:gt(Os($s(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":ao(s?s.d:o[0].d,88)}var ao,Lt,Et,so,Iw,Ew,b_,k_,v_,T_,$w=M(()=>{ao=(t,e)=>t.length>e?`${t.slice(0,e).trimEnd()}\u2026`:t,Lt=t=>t&&!/[$`]/.test(t)?t:null,Et=t=>t.replace(/\/+$/,"").split("/").pop()||t,so=t=>{let e=t.replace(/\/+$/,"").split("/").filter(Boolean);return e.length>3?e.slice(-2).join("/"):t},Iw=t=>t.startsWith("-"),Ew=new Set(["-g","--glob","-t","--type","-A","-B","-C","-m","--max-count","-e","--regexp","-f","--file"]);b_={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:t=>t[1]?`Clone ${Et(t[1])}`:"Clone repository",checkout:()=>"Switch branches",switch:()=>"Switch branches",restore:()=>"Restore files",reset:()=>"Reset git state",branch:(t,e)=>e.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"},k_={pr:t=>({create:"Create a pull request",list:"List pull requests",view:"View a pull request",merge:"Merge a pull request",checks:"Check PR status"})[t[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"};v_={git:t=>{let e=gt(t,new Set(["-C","-c"])),n=b_[e[0]];return n?n(e,t):null},gh:t=>{let e=gt(t),n=k_[e[0]];return n?n(e):null},sed:x_,rg:xu,grep:xu,egrep:xu,nl:t=>{let e=Lt(gt(t)[0]);return e?`Read ${Et(e)}`:null},cat:t=>{let e=Lt(gt(t)[0]);return e?`Read ${Et(e)}`:null},head:t=>{let e=Lt(gt(t,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return e?`Read the start of ${Et(e)}`:null},tail:t=>{let e=Lt(gt(t,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return e?`Read the end of ${Et(e)}`:null},wc:t=>{let e=Lt(gt(t)[0]);return e?`Count lines in ${Et(e)}`:"Count input lines"},ls:t=>{let e=Lt(gt(t)[0]);return e&&e!=="."?`List files in ${so(e)}`:"List files"},find:t=>Lt(t[1])&&!Iw(t[1])&&t[1]!=="."?`Find files in ${so(t[1])}`:"Find files",tree:()=>"List the directory tree",mkdir:t=>{let e=Lt(gt(t)[0]);return e?`Create directory ${so(e)}`:null},touch:t=>{let e=Lt(gt(t)[0]);return e?`Create ${Et(e)}`:null},rm:t=>{let e=Lt(gt(t)[0]);return e?`Delete ${so(e)}`:null},mv:t=>{let e=Lt(gt(t)[0]);return e?`Move ${Et(e)}`:null},cp:t=>{let e=Lt(gt(t)[0]);return e?`Copy ${Et(e)}`:null},chmod:t=>{let e=Lt(gt(t)[1]);return e?`Change permissions on ${Et(e)}`:null},diff:t=>{let e=gt(t);return e.length>=2?`Compare ${Et(e[0])} and ${Et(e[1])}`:null},curl:t=>{let e=_w(t);return e?`Fetch ${ao(e,56)}`:"Fetch a URL"},wget:t=>{let e=_w(t);return e?`Fetch ${ao(e,56)}`:"Fetch a URL"},npm:Su,pnpm:Su,yarn:Su,npx:t=>{let e=gt(t)[0];return e?`Run ${e}`:null},node:t=>vu(t,"Node"),python:t=>vu(t,"Python"),python3:t=>vu(t,"Python"),make:t=>{let e=gt(t)[0];return e?`Run make ${e}`:"Run make"},systemctl:S_,journalctl:t=>{let e=t.findIndex(r=>r==="-u"||r==="--unit"||r==="--user-unit"),n=e!==-1?t[e+1]:null;return n?`Read ${n.replace(/\.service$/,"")} logs`:"Read system logs"},tmux:t=>{let e=gt(t,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"}[e]||null},ps:()=>"List processes",which:t=>{let e=gt(t)[0];return e?`Locate ${e}`:null},command:t=>t[1]==="-v"&&t[2]?`Locate ${t[2]}`:null,fly:t=>{let e=gt(t)[0];return e==="deploy"?"Deploy to Fly":e?`Run fly ${e}`:null}},T_=new Set(["pwd","echo","cd","sleep","true","false","test","[","set","export","exit","read"])});function io(t){let e=t.split(`
75
+ `).map(n=>n.trim()).find(Boolean)||t;return e.length>88?`${e.slice(0,88).trimEnd()}\u2026`:e}function Rn(t,e=""){let n=e.trim();return n||Tu(t)||io(t)}function Au(t,e){if(t){if(Array.isArray(t)){for(let n of t)Au(n,e);return}if(typeof t=="object"){if(t.type==="tool_use"&&Eu.has(t.name)){let n=String(t.input?.command||"").trim();n&&e.push({id:t.id||null,tool:t.name,command:n,description:String(t.input?.description||"").trim()})}for(let n of Object.values(t))Au(n,e)}}}async function Ow(t,{maxBytes:e=1048576,limit:n=400}={}){let r;try{r=await Xt(t,e)}catch{return[]}let o=[];for(let s of r.split(`
76
+ `)){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(Au(c.content,l),!l.length)continue;let u=i.timestamp?Date.parse(i.timestamp):null;for(let f of l)o.push({...f,summary:Rn(f.command,f.description),ts:u})}return o.slice(-n)}function Cw(t,e){let n=e.filter(l=>l.role==="assistant"&&(l.text||"").trim()).sort((l,u)=>(l.ts||0)-(u.ts||0)),r=[...t].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((h,w)=>w>=s&&(h.ts||0)>(l.ts||0)),f=u===-1?r.length:u,d=r.slice(s,f);if(s=f,!d.length)continue;let p=d.map(h=>({...h,n:i(h)}));o.push({id:`batch-${l.ts}-${l.box}`,anchorTs:l.ts,anchorBox:l.box,agent:l.agent,boxRole:l.boxRole,commands:p,ts:Math.max(...p.map(h=>h.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 Eu,co=M(()=>{ye();$w();Eu=new Set(["Bash"])});import Mw from"node:fs";import Iu from"node:fs/promises";import _u from"node:path";import E_ from"node:os";async function Nw(t){try{return await Iu.realpath(t)}catch{return t}}function I_(t=__){let e=[],n=r=>{let o;try{o=Mw.readdirSync(r,{withFileTypes:!0})}catch{return}for(let s of o){let a=_u.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{e.push({id:i?i[1]:null,file:a,mtimeMs:Mw.statSync(a).mtimeMs})}catch{}}}};return n(t),e.sort((r,o)=>o.mtimeMs-r.mtimeMs)}async function R_(t,e=1048576){let n;try{n=await Iu.open(t,"r")}catch{return""}try{let r=Buffer.alloc(Math.min(e,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(`
77
+ `);if(i!==-1)return o.slice(0,i);if(s+=a,o.length>=e)break}return o}finally{await n.close()}}async function $_(t){let e=await R_(t);if(!e)return null;let n;try{n=JSON.parse(e)}catch{return null}return n?.type==="session_meta"&&n?.payload?.cwd||null}async function mr(t,e){if(!t&&!e)return null;let n=I_();if(e){let o=n.find(s=>s.id===e);return o||null}let r=await Nw(t);for(let o of n){let s=await $_(o.file);if(s&&(s===t||await Nw(s)===r))return o}return null}async function Pw(t,e,{limit:n=80,maxBytes:r=524288}={}){let o=await mr(t,e);if(!o)return[];let s;try{s=await Xt(o.file,r)}catch{return[]}let a=[],i=null,c=[],l=!1,u=!1,f=null;for(let d of s.split(`
78
+ `)){let p=d.trim();if(!p||p[0]!=="{")continue;let h;try{h=JSON.parse(p)}catch{continue}if((h.type==="turn_context"&&h.payload?.model||h.type==="session_meta"&&h.payload?.model)&&(i=h.payload.model),h.type==="event_msg"){let x=h.payload?.type;x==="task_started"?(l=!0,u=!1,f=h.payload?.turn_id||null):x==="task_complete"&&l&&(l=!1,!u&&h.payload?.last_agent_message==null&&a.push({role:"assistant",failed:!0,text:$u,sourceId:h.payload?.turn_id||f||void 0,ts:h.timestamp?Date.parse(h.timestamp):null,model:i}));continue}if(h.type!=="response_item")continue;let w=h.payload;if(!w)continue;if((w.type==="function_call"||w.type==="custom_tool_call")&&w.name){u=!0,Ru.has(w.name)||c.push(w.name);continue}if(w.type!=="message"||w.role!=="assistant")continue;u=!0;let y=C_(w.content),k=c.length?c.slice():null;c=[],!(!y&&!k)&&a.push({role:"assistant",text:y,tools:k||void 0,ts:h.timestamp?Date.parse(h.timestamp):null,model:i})}if(i)for(let d of a)d.model||(d.model=i);return a.slice(-n)}function M_(t){if(typeof t?.cmd=="string"&&t.cmd.trim())return t.cmd.trim();let e=t?.command;return typeof e=="string"&&e.trim()?e.trim():Array.isArray(e)&&e.length?e.length===3&&/^(ba)?sh$/.test(e[0])&&e[1]==="-lc"?String(e[2]).trim():e.map(String).join(" ").trim():null}function N_(t){let e=t[0];if(e!=='"'&&e!=="'"&&e!=="`")return null;let n="";for(let r=1;r<t.length;r++){let o=t[r];if(o==="\\"){let s=t[++r];if(s===void 0)return null;if(s==="n")n+=`
79
+ `;else if(s==="t")n+=" ";else if(s==="r")n+="\r";else if(s==="u")if(t[r+1]==="{"){let a=t.indexOf("}",r+2);if(a===-1)return null;n+=String.fromCodePoint(parseInt(t.slice(r+2,a),16)),r=a}else n+=String.fromCharCode(parseInt(t.slice(r+1,r+5),16)),r+=4;else n+=s}else{if(o===e)return n;if(e==="`"&&o==="$"&&t[r+1]==="{")return null;n+=o}}return null}function P_(t){let e=String(t||""),n=[],r=/exec_command\s*\(/g;for(let s;s=r.exec(e);)n.push(s.index+s[0].length);let o=[];return n.forEach((s,a)=>{let i=e.slice(s,a+1<n.length?n[a+1]:e.length),c=/(?:^|[{,\s])["'`]?cmd["'`]?\s*:\s*/.exec(i);if(!c)return;let l=N_(i.slice(c.index+c[0].length).trimStart());l&&l.trim()&&o.push(l.trim())}),o}async function Dw(t,e,{limit:n=400,maxBytes:r=524288}={}){let o=await mr(t,e);if(!o)return[];let s;try{s=await Xt(o.file,r)}catch{return[]}let a=[];for(let i of s.split(`
80
+ `)){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 f=[];if(u.type==="function_call"&&Cs.has(u.name)){let p;try{p=JSON.parse(u.arguments||"{}")}catch{continue}let h=M_(p);h&&(f=[h])}else u.type==="custom_tool_call"&&u.name==="exec"&&(f=P_(u.input));if(!f.length)continue;let d=u.call_id||u.id||null;f.forEach((p,h)=>{a.push({id:d?h?`${d}:${h}`:d:null,tool:u.name,command:p,description:"",summary:Rn(p),ts:l.timestamp?Date.parse(l.timestamp):null})})}return a.slice(-n)}async function Bw(t,e){let n=await mr(t,e);if(!n)return null;try{return Math.round((await Iu.stat(n.file)).mtimeMs)}catch{return n.mtimeMs||null}}var __,O_,C_,Cs,Ru,$u,lo=M(()=>{ye();co();__=process.env.BOSTRAT_CODEX_SESSIONS||_u.join(process.env.CODEX_HOME||_u.join(E_.homedir(),".codex"),"sessions");O_=new Set(["output_text","text"]),C_=t=>typeof t=="string"?t.trim():Array.isArray(t)?t.filter(e=>e&&typeof e.text=="string"&&O_.has(e.type)).map(e=>e.text).join(`
81
+ `).trim():"";Cs=new Set(["exec_command","shell","exec"]),Ru=new Set(["wait","write_stdin"]),$u="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 Ms(t,e){if(t!=="claude")return null;let n=String(e).replace(/\r/g,"").split(`
82
+ `).map(c=>c.replace(/\s+$/,"")),r=-1;for(let c=n.length-1;c>=0;c--)if(jw.test(n[c])){r=c;break}if(r<=0)return null;let o=-1;for(let c=r-1;c>=0;c--)if(jw.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(D_);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 Ot(t){return String(t||"").replace(/\s+/g," ").trim()}function Lw(t,e,{slackMs:n=2e4}={}){let r=Ot(e?.text);return!r||typeof e?.at!="number"?!1:(Array.isArray(t)?t:[]).some(o=>o?.role==="user"&&typeof o.ts=="number"&&o.ts>=e.at-n&&Ot(o.text).includes(r))}function Fw(t,e,n,{busy:r=!1}={}){let o=Ms(t,n);return o&&Ou(e,o)?"stuck":r||o?"submitted":"unknown"}function Ou(t,e){let n=Ot(t),r=Ot(e).replace(/^…\s*/,"").replace(/\s*…$/,"");return!n||!r||r.length<Math.min(n.length,12)?!1:n===r||n.includes(r)}var jw,D_,Cu=M(()=>{jw=/^\s*─{8,}\s*$/,D_=/^❯[  ]?(.*)$/});function H_(t){return B_.test(String(t||"").trimStart())}function Ww(t){let e=String(t||"");if(!H_(e.trimStart()))return null;let n=e.replace(j_,"").trim(),r=W_(n),o=[];for(let u of F_){let f=u.from.map(d=>uo(r.get(d))).find(d=>d&&!Uw(d));f&&o.push({h:u.h,text:Ns(f,L_)})}let s=uo(r.get("Current Work"))||uo(r.get("Primary Request and Intent"))||K_(n),a=Ni(s),i=Ns(Mi(Pu(a[0]||"")),U_)||"Context resumed from summary",c=[],l=a.slice(1).join(" ").trim();l&&c.push(Ns(Mi(Pu(l)),Nu));for(let u of["Pending Tasks","Optional Next Step"]){let f=Ni(uo(r.get(u)))[0]||"";if(!(!f||Uw(f))){c.push(Ns(`Left to do: ${Mi(Pu(f))}`,Nu));break}}if(!c.length){let u=Ni(uo(r.get("Problem Solving"))||"")[0];u&&c.push(Ns(Mi(u),Nu))}return{kind:"resume-summary",title:i,bullets:c.slice(0,2),sections:o,rawChars:e.length}}function W_(t){let e=new Map,n=[];Mu.lastIndex=0;for(let r=Mu.exec(t);r;r=Mu.exec(t))n.push({name:q_(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??t.length;e.has(n[r].name)||e.set(n[r].name,t.slice(n[r].end,o).trim())}return e}function q_(t){return Hw.find(n=>n.toLowerCase()===t.toLowerCase())||t}function uo(t){return t?String(t).replace(/```[\s\S]*?(?:```|$)/g," ").split(`
83
+ `).map(e=>e.replace(/^[ \t]*(?:[-*•]|\d+[.)]|[a-z][.)])[ \t]+/i,"").trim()).filter(e=>e&&!/^#{1,6}[ \t]/.test(e)).join(" ").replace(/\*\*(.+?)\*\*/g,"$1").replace(/`([^`]+)`/g,"$1").replace(/\s+/g," ").trim():""}function K_(t){let e=t.replace(/^[\s\S]*?\bSummary:\s*/i,"");return uo(e.split(/\n{2,}/).slice(0,2).join(" "))}function Ni(t){let e=String(t||"").trim();if(!e)return[];let r=e.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 Pu(t){return String(t||"").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)/,e=>e.toUpperCase()).trim()}function Mi(t){return String(t||"").replace(/(?<![:\w/])(?:\/[\w.@+-]+){4,}/g,e=>`\u2026/${e.split("/").slice(-2).join("/")}`)}function Uw(t){return/^(none|nothing|n\/a|no pending|there are no)\b/i.test(String(t||"").trim())}function Ns(t,e){let n=String(t||"").trim();if(n.length<=e)return n;let r=Ni(n),o="";for(let i of r){let c=o?`${o} ${i}`:i;if(c.length>e)break;o=c}if(o.length>=Math.min(60,e*.4))return o;let s=n.slice(0,e),a=s.lastIndexOf(" ");return`${(a>e*.6?s.slice(0,a):s).replace(/[,;:.\s]+$/,"")}\u2026`}var B_,Hw,Mu,j_,L_,F_,U_,Nu,qw=M(()=>{B_=/^This session is being continued from a previous conversation that ran out of context\./,Hw=["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"],Mu=new RegExp(String.raw`^[ \t]*#{0,4}[ \t]*(?:\d+[.)][ \t]*)?\*{0,2}(${Hw.join("|")})[:*\t ]*$`,"gim"),j_=/\n+If you need specific details from before compaction[\s\S]*$|\n+Continue the conversation from where it left off[\s\S]*$/,L_=420,F_=[{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"]}],U_=116,Nu=168});function Gw(t){return Du.has(String(t||"").replace(/^\//,"").toLowerCase())}function Pi(t){let e=String(t||"").trim();if(!e)return null;let n=Ww(e);if(n)return n;let r=e.match(G_);if(r)return{kind:"skill",name:r[1].split("/").filter(Boolean).pop()||"skill"};let o=e.match(V_);if(o)return{kind:"skill",name:o[1]};let s=e.match(z_);if(s){let i=s[1].toLowerCase();return Du.has(i)?{kind:"suppress"}:{kind:"command",command:`/${i}`}}let a=e.match(oI);if(a&&Du.has(a[1].toLowerCase()))return{kind:"suppress"};if(J_.test(e))return{kind:"suppress"};if(X_.test(e))return{kind:"suppress"};if(Y_.test(e))return{kind:"suppress"};if(Z_.test(e)){let i=l=>sI(e.match(l)?.[1].trim()||"")||null,c=i(rI);return{kind:"task",summary:i(Q_)||"",taskId:i(tI),toolUseId:i(eI),status:i(nI)?.toLowerCase()||null,resultHead:c?c.length>Kw?`${c.slice(0,Kw).trimEnd()}\u2026`:c:null}}return null}function sI(t){return t.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&amp;/g,"&")}function Vw(t){return t?.kind==="skill"?`Ran the ${t.name} skill`:t?.kind==="command"?`Ran ${t.command}`:t?.kind==="task"?t.summary||"A background task finished":t?.kind==="resume-summary"?t.title?`Context resumed from summary: ${t.title}`:"Context resumed from summary":""}function zw(t){return t?.kind==="skill"?"skill-run":t?.kind==="task"?"task-done":t?.kind==="resume-summary"?"context-resumed":"command-run"}var G_,V_,z_,J_,Y_,X_,Z_,Q_,tI,eI,nI,rI,Kw,Du,oI,Bu=M(()=>{qw();G_=/^Base directory for this skill:\s*(\S+)/,V_=/^Run the "([^"]+)" workflow\./,z_=/<command-name>\s*\/?([a-z0-9:_-]+)\s*<\/command-name>/i,J_=/^<local-command-(?:stdout|caveat)>/i,Y_=/^\[Image: original \d+x\d+, displayed at \d+x\d+\.\s*Multiply coordinates by [\d.]+ to map to original image\.\]$/,X_=/^Continue from where you left off\.$/,Z_=/^<task-notification>/i,Q_=/<summary>([\s\S]*?)<\/summary>/i,tI=/<task-id>([\s\S]*?)<\/task-id>/i,eI=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i,nI=/<status>([\s\S]*?)<\/status>/i,rI=/<result>([\s\S]*?)(?:<\/result>|$)/i,Kw=600,Du=new Set(["model","clear","compact","login","exit","quit"]);oI=/^\/([a-z0-9:_-]+)$/i});import aI from"node:crypto";function uI(t){let e=Array.isArray(t)?t:Array.isArray(t?.questions)?t.questions:null;if(!e||!e.length)return null;let n=[];for(let r of e.slice(0,Yw)){let o=Ps(r?.question);if(!o)return null;let s=Array.isArray(r?.options)?r.options:[],a=[];for(let i of s.slice(0,iI)){let c=Ps(i?.label);if(!c)return null;let l=Ps(i?.description);a.push(l?{label:c,description:l}:{label:c})}if(a.length<cI)return null;n.push({question:o,header:Ps(r?.header).slice(0,lI),multiSelect:r?.multiSelect===!0,options:a})}return n.length?n:null}function Lu(t){if(typeof t!="string"||!t.includes("```bostrat-question"))return null;Jw.lastIndex=0;let e=null;for(let o;o=Jw.exec(t);)e=o;if(!e||e.index+e[0].length<t.trimEnd().length)return null;let n;try{n=JSON.parse(e[2])}catch{return null}let r=uI(n);return r?{text:t.slice(0,e.index).trimEnd(),questions:r}:null}function Fu(t,e,n){let r=aI.createHash("sha256").update(JSON.stringify(n)).digest("hex").slice(0,8);return`${t}:ask:${e||"turn"}:${r}`}function Uu(t,{leadBoxId:e,provider:n,isAnswered:r,maxQuestions:o=Yw}={}){if(!Array.isArray(t)||!e||!ju.has(n))return null;let s=null;for(let l=t.length-1;l>=0;l--){let u=t[l];if(u?.kind==="prompt")return null;if(u?.kind==="message"){if(u.role!=="assistant")return null;s=u;break}}if(!s||s.box!==e||s.agent!==n)return null;let a=s.ask?.questions||Lu(s.text)?.questions;if(!a?.length)return null;let i=a.slice(0,Math.max(1,o)),c=Fu(n,s.sourceId||s.id,a);return typeof r=="function"&&r(c)?null:{provider:n,box:e,promptId:c,groupId:c,answerMode:"say",source:"transcript",multiSelect:i[0].multiSelect,questionIndex:0,questionTotal:i.length,questions:i}}function Xw(t,e,n){let r=[];(t?.questions||[]).forEach((a,i)=>{let c=(e?.[i]||[]).map(l=>a.options?.[l]?.label).filter(Boolean);c.length&&r.push({name:a.header||a.question,picks:c.join(", ")})});let o=Ps(n),s;return r.length?r.length===1?s=`${r[0].name}: ${r[0].picks}`:s=`Answers:
84
84
  ${r.map(a=>`- ${a.name}: ${a.picks}`).join(`
85
85
  `)}`:s=o,r.length&&o&&(s+=`
86
- ${o}`),s||""}var Iu,Ew,C_,M_,P_,Aw,As,Iw,Cu=M(()=>{Iu=new Set(["cursor","codex"]),Ew=4,C_=4,M_=2,P_=24,Aw=/^[ \t]{0,3}(`{3,})bostrat-question[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]{0,3}\1`*[ \t]*$/gm,As=t=>typeof t=="string"?t.trim():"";Iw=`
86
+ ${o}`),s||""}var ju,Yw,iI,cI,lI,Jw,Ps,Zw,Hu=M(()=>{ju=new Set(["cursor","codex"]),Yw=4,iI=4,cI=2,lI=24,Jw=/^[ \t]{0,3}(`{3,})bostrat-question[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]{0,3}\1`*[ \t]*$/gm,Ps=t=>typeof t=="string"?t.trim():"";Zw=`
87
87
  When you are BLOCKED on a decision only the operator can make \u2014 an ambiguous
88
88
  requirement, an irreversible choice, several valid approaches \u2014 do not bury the
89
89
  question in prose. End your message with exactly ONE fenced code block tagged
@@ -103,62 +103,66 @@ your turn. The operator sees the questions as an interactive card in their chat
103
103
  answer. Never use the block for rhetorical questions, progress updates, or
104
104
  anything you can decide yourself; keep asking in prose for questions without
105
105
  enumerable options.
106
- `});function B_(t){return{id:t.id,kind:"prompt",groupId:t.groupId,provider:t.provider,box:t.box,agent:t.provider,questionTotal:t.questions.length,answeredVia:"chat",questions:t.questions.map((e,n)=>({index:n,header:e.header||"",question:e.question,multiSelect:!!e.multiSelect,chosen:[]})),ts:t.ts}}function j_(t,e,n){let r=Rw(n),o=t.has(r)?r:null;if(!o&&n.number!=null)for(let[i,c]of t){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?t.get(o):t.get(s);if(o&&o!==s){t.delete(o);let i=e.get(o);if(e.delete(o),i?.length){let c=e.get(s)??[];e.set(s,c.concat(i))}}return t.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 lr(t){let e=[],n=new Set,r=new Set,o=new Map,s=new Map,a=new Set,i=new Map,c=new Set,l=new Map,u=/^Agent "([\s\S]+)" finished$/,d=new Map;for(let g of t||[]){if(g.type!=="tool.called"||g.source!=="transcript")continue;let h=String(g.payload?.command||"");if(/\bbostrat-mock\s+(?:add|update)\b/.test(h))for(let T of h.matchAll(/[\w./~-]+\.(?:png|jpe?g|gif|webp|bmp|svg)\b/gi)){let _=T[0].split("/").pop().toLowerCase();d.has(_)||d.set(_,[]),d.get(_).push(g.payload?.ts??g.ts)}}let f=3*6e4,p=20*6e4,m=(g,h)=>!!(g?.name&&d.get(String(g.name).toLowerCase()))?.some(_=>_>=h-f&&_<=h+p);for(let g of t||[])if(g.type==="turn.retracted"){r.add(`${g.boxId}|${g.payload?.saidTs}`);let h=It(g.payload?.text);h&&(o.has(g.boxId)||o.set(g.boxId,[]),o.get(g.boxId).push(h))}else if(g.type==="turn.user"&&g.source==="orchestrator"){let h=It(g.payload?.text);h&&(s.has(g.boxId)||s.set(g.boxId,new Set),s.get(g.boxId).add(h))}else if(g.type==="job.started"&&g.payload?.id)a.add(g.payload.id),(g.payload.kind||"agent")==="agent"&&g.payload.name&&c.add(g.payload.name);else if(g.type==="turn.user"&&g.payload?.note?.kind==="task"){let h=g.payload.note,T={status:h.status||null,summary:h.summary||null,resultHead:h.resultHead??null,ts:ot(g)};h.toolUseId&&i.set(h.toolUseId,T);let _=String(h.summary||"").match(u);_&&l.set(_[1],T)}let w=new Map,y=new Map,k=null,S=new Map,$=new Map,R=new Map,J=new Map,C=new Map,D=new Map,A=new Map,N=new Map,W=new Map,at=new Map,it=new Map,E=()=>{for(let g of it.values())g.questions.length&&e.push(g);it.clear()},O=null,At=6e4,Gt=new Map,gt=(g,h)=>{let T=o.get(g);if(!T?.length)return!1;let _=It(h),St=s.get(g);return T.some(nt=>{if(!_.startsWith(nt))return!1;let dt=It(_.slice(nt.length));return!!dt&&!!St?.has(dt)})};for(let g of t||[]){let h=g.payload||{};switch(g.type){case"turn.user":{if(g.source==="hook"||!String(h.text||"").trim()&&!h.images?.length)break;{let T=h.note||Si(h.text);if(T){if(T.kind==="task"){if(T.toolUseId&&a.has(T.toolUseId))break;let _=String(T.summary||"").match(u);if(!T.toolUseId&&_&&c.has(_[1]))break}if(T.kind==="command"&&Sw(T.command))break;if(T.kind==="resume-summary"){e.push({id:g.id,kind:"resume-summary",title:T.title||"Context resumed from summary",bullets:T.bullets||[],sections:T.sections||[],rawChars:T.rawChars??null,ts:ot(g),box:g.boxId,agent:g.provider});break}T.kind!=="suppress"&&e.push({id:g.id,kind:"event",type:Tw(T),name:T.name??null,command:T.command??null,summary:T.summary??null,status:T.status??null,ts:ot(g),box:g.boxId,agent:g.provider});break}}if(r.has(`${g.boxId}|${ot(g)}`)||g.source==="transcript"&&gt(g.boxId,h.text))break;if(h.kind==="merge-notify"||h.kind==="ship-notify"){e.push({id:g.id,kind:"event",type:h.kind==="ship-notify"?"ship-notified":"merge-notified",text:h.text,ts:ot(g),box:g.boxId,agent:g.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==="prompt-answer"&&(O=null);break}for(let T of S.values())T.status="stale";S.clear();for(let T of R.values())T.status="stale";R.clear(),O&&O.box===g.boxId&&(e.push(B_(O)),O=null),e.push({id:g.id,kind:"message",role:"user",text:h.text,ts:ot(g),box:g.boxId,agent:g.provider,boxRole:h.boxRole,...g.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 T=h.from||{};e.push({id:g.id,kind:"event",type:"peer-message",text:h.text,from:T.trackName||T.boxId||T.name||null,fromTrackId:T.trackId||null,ts:ot(g),box:g.boxId,agent:g.provider});break}case"turn.agent":{if(h.model==="<synthetic>"&&/^No response requested\.$/.test(String(h.text||"").trim()))break;E();let T=(h.images||[]).filter(dt=>!m(dt,ot(g)));if(!String(h.text||"").trim()&&!T.length)break;if(g.provider==="cursor"){let dt=`${g.boxId}|${h.text}`;if(n.has(dt))break;n.add(dt)}(!O||O.box===g.boxId)&&(O=null);let _=g.provider==="codex"?(h.tools||[]).filter(dt=>!bu.has(dt)&&!Ss.has(dt)):h.tools||[],St=h.text,nt=null;if(Iu.has(g.provider)){let dt=Ru(String(h.text||""));dt&&(St=dt.text,nt={questions:dt.questions})}e.push({id:g.id,kind:"message",role:"assistant",text:St,ts:ot(g),box:g.boxId,agent:g.provider,boxRole:h.boxRole,...nt?{ask:nt}:{},..._.length?{tools:_}:{},...h.model?{model:h.model}:{},...h.sourceId?{sourceId:h.sourceId}:{},...T.length?{images:T}:{}}),nt&&(O={id:g.id,groupId:$u(g.provider,h.sourceId||g.id,nt.questions),provider:g.provider,box:g.boxId,questions:nt.questions,ts:ot(g)});break}case"job.started":{if(!h.id)break;let T=ot(g),_=i.get(h.id);if(!_&&(h.kind||"agent")==="agent"&&h.name){let Bt=l.get(h.name);Bt&&Bt.ts>=T&&(_=Bt)}let St={jobId:h.id,jobKind:h.kind||"agent",name:h.name||null,detail:h.detail||null,status:_?_.status==="killed"?"stopped":_.status&&_.status!=="completed"?"failed":"done":"running",startedTs:T,finishedTs:_?.ts??null,summary:_?.summary??null,resultHead:_?.resultHead??null},nt=Gt.get(g.boxId),dt=nt?.jobs[nt.jobs.length-1]?.startedTs;if(nt&&dt!=null&&T-dt<=At)nt.jobs.push(St);else{let Bt={id:g.id,kind:"job-dock",dockId:h.id,ts:T,box:g.boxId,agent:g.provider,jobs:[St]};Gt.set(g.boxId,Bt),e.push(Bt)}break}case"handoff.done":e.push(Re(g,"lead-handoff"));break;case"subtask.delegated":e.push({...Re(g,"subtask-delegated"),to:g.boxId,toAgent:g.provider});break;case"subtask.merged":e.push(Re(g,"subtask-merged"));break;case"pr.state.changed":{if(!h.change)break;if(h.change==="opened"){for(let _ of S.values())_.status="stale";S.clear();for(let _ of R.values())_.status="stale";R.clear()}let T=Re(g,`pr-${h.change}`);if(T.box=g.boxId??null,D_.has(h.change)&&h.number!=null){let _=j_(w,y,h);if(w.size>=2){for(let nt of y.values())for(let dt of nt)dt.grouped=!0;T.groupPrs=[...w.values()];let St=[T];for(let nt of w.keys())y.set(nt,St)}else{let St=y.get(_)??[];St.push(T),y.set(_,St)}}else if(h.change==="merged"||h.change==="closed"||h.change==="lost"){let _=Rw(h),St=k&&!k.complete||w.size>=2;if(w.has(_))w.delete(_),y.delete(_);else if(h.number!=null)for(let nt of[...w.keys()])nt.endsWith(`#${h.number}`)&&(w.delete(nt),y.delete(nt));if(St&&h.number!=null){(!k||k.complete)&&(k={id:g.id,kind:"event",type:"pr-group-settled",prs:[],remaining:[],complete:!1,at:ot(g),ts:ot(g),box:g.boxId,agent:g.provider},e.push(k)),k.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:ot(g)}),k.remaining=[...w.values()],k.complete=w.size===0;break}}e.push(T);break}case"pr.offered":{if(!h.offerId)break;for(let _ of S.values())_.status="stale";S.clear();for(let _ of R.values())_.status="stale";R.clear();let T={id:g.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,repos:Array.isArray(h.repos)&&h.repos.length?h.repos:null,status:"open",ts:ot(g),box:g.boxId,agent:g.provider};S.set(h.offerId,T),$.set(h.offerId,T),e.push(T);break}case"pr.offer.answered":{let T=$.get(h.offerId);T&&(T.status=h.action||"dismiss",T.actions=Array.isArray(h.actions)?h.actions:null,T.notify=h.notify===!0,h.existingPr&&typeof h.existingPr=="object"&&(T.existingPr={number:h.existingPr.number??null}),S.delete(h.offerId));break}case"pr.exists.offered":{if(!h.offerId)break;for(let _ of R.values())_.status="stale";R.clear();let T={id:g.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:ot(g),box:g.boxId,agent:g.provider};R.set(h.offerId,T),J.set(h.offerId,T),e.push(T);break}case"pr.exists.answered":{let T=J.get(h.offerId);T&&(T.status=h.choice||"dismiss",R.delete(h.offerId));break}case"box.state.changed":{let T=h.change==="model"?"model-change":h.change;if(!T)break;let _=Re(g,T);T==="model-change"&&(_.to=h.model),e.push(_);break}case"view.state.changed":{if(h.change!=="created"||h.restarted)break;e.push({id:g.id,kind:"view-card",viewId:h.viewId,name:h.name,slug:h.slug,port:h.port,origin:h.origin,ts:ot(g),box:g.boxId,agent:g.provider});break}case"view.spinup.failed":{e.push({id:g.id,kind:"view-spinup-failed",name:h.name||null,reason:h.reason||"no-view",ts:ot(g),box:g.boxId,agent:g.provider});break}case"mock.state.changed":{if(h.change==="picked"){e.push({id:g.id,kind:"mock-picked",mockId:h.mockId,name:h.name,group:h.group??null,version:h.version??null,siblings:h.siblings??[],ts:ot(g),box:g.boxId,agent:g.provider});break}if(h.change!=="created")break;e.push({id:g.id,kind:"mock-card",mockId:h.mockId,name:h.name,group:h.group??null,ts:ot(g),box:g.boxId,agent:g.provider});break}case"flow.state.changed":{if(h.change!=="created")break;e.push({id:g.id,kind:"flow-card",flowId:h.flowId,name:h.name,stepCount:h.stepCount??null,mockIds:h.mockIds??[],ts:ot(g),box:g.boxId,agent:g.provider});break}case"runbook.state.changed":{if(h.change!=="created")break;e.push({id:g.id,kind:"runbook-card",runbookId:h.runbookId,name:h.name,ts:ot(g),box:g.boxId,agent:g.provider});break}case"ticket.linked":{e.push({id:g.id,kind:"ticket-card",provider:h.provider||"linear",key:h.key,url:h.url,title:h.title??null,linkSource:h.linkSource??null,ts:ot(g),box:g.boxId,agent:g.provider});break}case"box.fullscreen.detected":{if(!h.offerId)break;for(let _ of A.values())_.box===(h.box||g.boxId)&&(_.status="stale",A.delete(_.offerId));let T={id:g.id,kind:"fullscreen-offer",offerId:h.offerId,status:"open",ts:ot(g),box:h.box||g.boxId,agent:h.agent||g.provider};A.set(h.offerId,T),N.set(h.offerId,T),e.push(T);break}case"box.fullscreen.answered":{let T=N.get(h.offerId);T&&(T.status=h.action==="restarted"?"restarted":h.action==="cleared"?"cleared":"dismiss",A.delete(h.offerId));break}case"ticket.move.offered":{if(!h.offerId)break;for(let _ of C.values())_.key===h.key&&(_.status="stale",C.delete(_.offerId));let T={id:g.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:ot(g),box:g.boxId,agent:g.provider};C.set(h.offerId,T),D.set(h.offerId,T),e.push(T);break}case"ticket.move.answered":{let T=D.get(h.offerId);T&&(T.status=h.action==="moved"?"moved":"dismiss",C.delete(h.offerId));break}case"ticket.state.changed":{for(let T of C.values())T.key===h.key&&T.to===h.to&&(T.status="stale",C.delete(T.offerId));if(h.mode==="offer")break;e.push(Re(g,"ticket-state"));break}case"ticket.commented":{e.push({id:g.id,kind:"ticket-comment",key:h.key,url:h.url??null,excerpt:h.excerpt??null,ts:ot(g),box:g.boxId,agent:g.provider});break}case"ticket.flow.changed":e.push(Re(g,"ticket-flow"));break;case"ticket.create.offered":{if(!h.proposalId)break;for(let _ of W.values())_.status="stale";W.clear();let T={id:g.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:ot(g),box:g.boxId,agent:g.provider};W.set(h.proposalId,T),at.set(h.proposalId,T),e.push(T);break}case"ticket.create.answered":{let T=at.get(h.proposalId);T&&(T.status=h.action==="created"?"created":"dismiss",T.createdCount=h.createdCount??null,T.failedCount=h.failedCount??null,W.delete(h.proposalId));break}case"ticket.created":{let T={items:Array.isArray(h.items)?h.items:[],failed:Array.isArray(h.failed)?h.failed:[],team:h.team??null},_=h.proposalId?at.get(h.proposalId):null;if(_){_.created=T;break}e.push({id:g.id,kind:"ticket-created",...T,ts:ot(g),box:g.boxId,agent:g.provider});break}case"error":{if(!h.kind)break;e.push(Re(g,h.kind));break}case"usage.cap.hit":e.push(Re(g,"usage-cap-hit"));break;case"usage.cap.warning":e.push(Re(g,"usage-cap-warning"));break;case"provider.connected":{e.push({id:g.id,kind:"event",type:"provider-connected",provider:h.provider||g.provider,ts:ot(g),at:ot(g),box:g.boxId,agent:g.provider});break}case"prompt.answered":{if(O=null,h.control||!h.question)break;let T=h.groupId||h.promptId;if(!T)break;let _=it.get(T);_||(_={id:g.id,kind:"prompt",groupId:T,provider:g.provider,box:g.boxId,agent:g.provider,questionTotal:h.questionTotal??1,questions:[],ts:ot(g)},it.set(T,_));let St=h.questionIndex??0,nt={index:St,header:h.header||"",question:h.question,multiSelect:!!h.multiSelect,chosen:Array.isArray(h.chosen)?h.chosen:[]},dt=_.questions.findIndex(Bt=>Bt.index===St&&It(Bt.question)===It(nt.question));dt>=0?_.questions[dt]=nt:_.questions.push(nt),_.questions.sort((Bt,K)=>Bt.index-K.index),_.questionTotal=Math.max(_.questionTotal,h.questionTotal??1),_.questions.length>=_.questionTotal&&(e.push(_),it.delete(T));break}default:break}}return F_(e.sort((g,h)=>(g.ts??0)-(h.ts??0)))}function F_(t){let e=new Map,n=[];for(let r of t){if(r.kind!=="message"||!r.box){n.push(r);continue}let o=r.role==="assistant"&&!String(r.text||"").trim()&&r.images?.length,s=e.get(r.box);if(o&&s&&(r.ts??0)-s.lastTs<=L_){s.item.images.push(...r.images),s.lastTs=r.ts??s.lastTs;continue}if(o){let a={...r,images:[...r.images]};e.set(r.box,{item:a,lastTs:r.ts??0}),n.push(a)}else e.delete(r.box),n.push(r)}return n}function Mu(t,e=null){let n=[];for(let o of t||[]){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:U_(s),ts:s.ts??o.ts,n:s.n,box:o.boxId,agent:o.provider,boxRole:s.boxRole})}if(!n.length)return[];let r=(e??lr(t)).filter(o=>o.kind==="message");return cw(n,r)}function U_(t){let e=String(t.summary||"").trim();return e&&e!==t.command&&e!==Xr(t.command)?e:An(t.command,t.description||"")}function Re(t,e){let{ts:n,change:r,...o}=t.payload||{};return{id:t.id,kind:"event",type:e,...o,at:ot(t),ts:ot(t)}}function $w(t){let e=[...t];for(let n=0;n<e.length;n++){let r=e[n];if(r?.kind!=="event"||r.type!=="archived")continue;let o=(r.ts??0)+H_,s=n;for(;s+1<e.length;){let a=e[s+1];if((a?.ts??0)>o||a?.kind==="event"&&W_.has(a.type))break;s++}s>n&&e.splice(s,0,...e.splice(n,1)),n=s}return e}function Ow(t){let e=[...t];for(let n=0;n<e.length;n++){let r=e[n];if(r?.kind!=="event"||!K_.has(r.type)||!r.box)continue;let o=(r.ts??0)+q_,s=n;for(;s+1<e.length;){let a=e[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&&e.splice(s,0,...e.splice(n,1)),n=s}return e}var ot,D_,Rw,L_,H_,W_,q_,K_,Pu=M(()=>{Zr();Qr();Su();_u();Cu();ot=t=>t.payload?.ts??t.ts;D_=new Set(["opened","ci-fixed","reconciled","pushed"]),Rw=t=>`${t.repo??""}#${t.number}`;L_=2*6e4;H_=12e4,W_=new Set(["archived","unarchived","opened"]);q_=2500,K_=new Set(["pr-opened","pr-merged","pr-auto-armed"])});function Y_(t){let e=null,n=null,r=null;for(let o of t??[]){let s=o?.ts??null;s&&(r=Math.max(r??0,s)),o?.type==="handoff.artifact"&&(e={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:e,lastPush:n,lastEventAt:r}}function Z_(t){for(let e=(t?.length??0)-1;e>=0;e--){let n=t[e];if(n?.type==="handoff.artifact"&&!n.payload?.reconstructed)return n}return null}function Q_(t,e){let n=[],r=[],o=new Set,s=new Set;for(let a=(t?.length??0)-1;a>=0;a--){let i=t[a];if(i?.type!=="tool.called")continue;if(e!=null&&(i.ts??0)<=e)break;let c=i.payload||{};c.path&&!o.has(c.path)&&n.length<z_&&(o.add(c.path),n.push(c.path)),c.head&&!s.has(c.head)&&r.length<J_&&(s.add(c.head),r.push(c.head))}return{files:n,heads:r}}function Nw(t,{trackName:e="this Track",now:n=null,mode:r="failover"}={}){let o=Y_(t),s=Z_(t),a=s?.payload?.content??null,i=s?s.payload?.ts??s.ts??null:null,c=lr(t??[]).filter(f=>f?.kind==="message"&&typeof f.text=="string"&&f.text.trim()).slice(-G_);if(!a&&!c.length)return null;let l=[];if(l.push(`# Reconstructed resume brief \u2014 ${e}`),l.push(""),l.push(Pw[r]??Pw.failover),l.push(""),o.lastPush?.sha){let f=Mw(n,o.lastPush.ts),p=f?` (~${f} min before the loss)`:"";l.push(`**Code state:** last pushed ref \`${o.lastPush.ref}\` @ \`${o.lastPush.sha.slice(0,12)}\`${p}`+(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 f=Mw(n,i);l.push(`## Last real checkpoint (written by the previous agent${f?`, ~${f} min before this reconstruction`:""})`),l.push(""),l.push(a.trim()),l.push("")}let u=Q_(t??[],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(f=>`\`${f}\``).join(", ")}`),u.heads.length&&(u.files.length&&l.push(""),l.push(`Commands run (most recent first): ${u.heads.map(f=>`\`${f}\``).join(" \xB7 ")}`)),l.push("")),c.length){l.push(`## Recent conversation (last ${c.length} message${c.length===1?"":"s"})`),l.push("");for(let f of c)l.push(`**${f.role==="user"?"operator":"agent"}:** ${X_(f.text,V_)}`),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(`
107
- `);return d.length<=Cw?d:`${d.slice(0,Cw)}
108
-
109
- [\u2026 brief truncated]`}var G_,V_,Cw,z_,J_,X_,Mw,Pw,Bw=M(()=>{Pu();G_=12,V_=2e3,Cw=48e3,z_=30,J_=10;X_=(t,e)=>{let n=String(t??"").trim();return n.length<=e?n:`${n.slice(0,e-1)}\u2026`},Mw=(t,e)=>t&&e?Math.max(1,Math.round((t-e)/6e4)):null;Pw={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."}});import tI from"node:fs";import En from"node:fs/promises";import _n from"node:path";function Ww(t){let e=nr(String(t??"")),n=Buffer.byteLength(e,"utf8");return n<=Dw?{content:e,bytes:n,truncated:!1}:{content:`${Buffer.from(e,"utf8").subarray(0,Dw).toString("utf8").replace(/�+$/,"")}
110
-
111
- [\u2026 truncated by bostrat at 32 KiB \u2014 full artifact in the workspace]`,bytes:n,truncated:!0}}function lI(t){let e=String(t||"").split(/\r?\n/).map(s=>s.trim()).filter(Boolean),n=[],r=[];for(let s of e)if(Lw.test(s)){if(r.length>=Jw)continue;let a=cI(s.replace(Lw,"").replace(/[.;,:]+$/,""),Yw,aI);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>jw&&(o=`${o.slice(0,jw-1).trimEnd()}\u2026`),{text:o,items:r.length>1?r:[]}}async function Xw(t,e,{timeoutMs:n=9e4}={}){let r=_n.join(e,oI),o=_n.join(r,sI);await En.mkdir(r,{recursive:!0});let s=await vi(o),a=await tt(t);if(!a)throw new Error(`session "${t}" not found`);return await Ti(t,a,iI(o)),await ag(o,s,n),lI(await En.readFile(o,"utf8"))}function Zw(t,e){let n=(e||"").trim();if(!n)return!1;if(t==="assistant")return n===Kw||n===zw;let r=n.replace(/^\/[a-z0-9:_-]+\s+/i,"");return r.startsWith(qw)||n===eI||r.startsWith(Gw)||r.startsWith(Vw)}function Qw(t){let e=[];for(let r of t?.events||[]){if(r.type!=="lead-handoff"||!r.from)continue;let o=r.at??Date.now(),s=r.handoffStartedAt??o-uI;e.push({box:r.from,from:s,to:o}),r.to&&r.to!==r.from&&e.push({box:r.to,from:s,to:o})}let n=t?.handoff;return n?.fromBox&&n.startedAt&&n.finishedAt&&e.push({box:n.fromBox,from:n.startedAt,to:n.finishedAt}),n?.toBox&&n.startedAt&&n.finishedAt&&e.push({box:n.toBox,from:n.startedAt,to:n.finishedAt}),e}function tg(t,e){let n=[];for(let r of t?.boxes||[]){let o=e?.(r.name);o?.startedAt&&n.push({box:r.name,from:o.startedAt,to:o.finishedAt||Date.now()+1e12})}return n}function eg(t,{windows:e=[]}={}){if(Zw(t.role,t.text))return!0;if(t.role!=="assistant"||!t.ts)return!1;for(let n of e)if(t.box===n.box&&t.ts>=n.from&&t.ts<=n.to)return!0;return!1}function Ai(t){return Nu.get(t)||null}async function ng(t){let e=Nu.get(t);if(e&&!e.finishedAt)throw new Error("a handoff is already running for this session");let n=await tt(t);if(!n)throw new Error(`session "${t}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${t}"`);let r={name:t,step:"summarize",startedAt:Date.now(),finishedAt:null,error:null,file:_n.join(n.cwd,Uw,Hw)};return Nu.set(t,r),pI(r,n.cwd).catch(o=>{r.error=o?.message||String(o),r.finishedAt=Date.now()}),r}async function pI(t,e){t.step="summarize",await rg(t.name,e),t.step="clear";let n=await tt(t.name);await Ti(t.name,n,"/clear"),await Bu(dI),t.step="resume",await Ti(t.name,n,rI),t.step="done",t.finishedAt=Date.now()}async function rg(t,e,{timeoutMs:n=fI}={}){let r=_n.join(e,Uw),o=_n.join(r,Hw);await En.mkdir(r,{recursive:!0});let s=await vi(o),a=await tt(t);await G({flow:"checkpoint",phase:"summarize-start",sessionName:t,cwd:e,file:o,beforeMtime:s}),await Ti(t,a,nI(o)),await ag(o,s,n),await G({flow:"checkpoint",phase:"summarize-done",sessionName:t,file:o,afterMtime:await vi(o)});let i=await Zh(e,o,{exclude:u=>Zw(u.role,u.text)});await G({flow:"checkpoint",phase:"seed-enriched",sessionName:t,file:o,...i});let c=/workspaces[/\\]([0-9a-f]{8})$/.exec(e||"")?.[1];if(c){await I({id:c,cwd:e},{type:"memory.seed",actor:"orchestrator",payload:{...i,tokensEst:i.chars?Math.round(i.chars/4):0,ts:Date.now()}}).catch(()=>{});try{let u=await En.readFile(o,"utf8");await I({id:c,cwd:e},{type:"handoff.artifact",actor:"orchestrator",payload:{...Ww(u),ts:Date.now()}})}catch{}}await Ym(e);let l=await mI(r,o);return c&&await ih(c,l||o,{box:t,agent:a?.agent??null}),o}async function og(t,{timeoutMs:e}={}){let n=await tt(t);if(!n)throw new Error(`session "${t}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${t}"`);return rg(t,n.cwd,e?{timeoutMs:e}:void 0)}async function sg(t,e,{trackName:n="this Track"}={}){let r=await L({id:t,cwd:e}),o=Nw(r,{trackName:n,now:Date.now(),mode:"in-place"});if(!o)return null;let s=_n.join(e,Fw);return await En.mkdir(_n.dirname(s),{recursive:!0}),await En.writeFile(s,o,"utf8"),await I({id:t,cwd:e},{type:"handoff.artifact",actor:"orchestrator",payload:{...Ww(o),reconstructed:!0,ts:Date.now()}}).catch(()=>{}),Fw}async function vi(t){try{return(await En.stat(t)).mtimeMs}catch{return 0}}async function ag(t,e,n){let r=Date.now()+n;for(;;){if(await vi(t)>e)return;if(Date.now()>r)throw new Error(`timed out waiting for the handoff file to be written (${t})`);await Bu(2e3)}}async function mI(t,e){try{if(!tI.existsSync(e))return null;let n=new Date().toISOString().replace(/[:.]/g,"-"),r=_n.join(t,`${n}.md`);return await En.copyFile(e,r),r}catch{return null}}function Bu(t){return new Promise(e=>setTimeout(e,t))}async function Ti(t,e,n){if(e){let o=e.agent==="claude"?process.env.BOSTRAT_AGENT_CMD||"claude":e.agent==="cursor"?process.env.BOSTRAT_CURSOR_CMD||"cursor-agent":e.agent==="codex"?process.env.BOSTRAT_CODEX_CMD||"codex":"";await Tn({cwd:e.cwd,sessionId:e.sessionId,sessionName:t,agent:e.agent,agentCmd:o})}let r=await tt(t);if(!r)throw new Error(`session "${t}" disappeared before the orchestration prompt could be sent`);await Tt(t,["Escape"],{kind:"drive-wipe"}),await Bu(150),await Gr(t,ai,{kind:"drive-wipe"}),await Mt(t,n,{kind:"orchestration-drive",...Ie(r.agent)})}var Uw,Hw,Dw,qw,Kw,Gw,eI,nI,rI,Vw,zw,oI,sI,jw,Jw,Yw,aI,iI,Lw,cI,uI,dI,fI,Nu,Fw,Du=M(()=>{Ht();hi();We();gs();Qh();Ya();ct();jl();Bw();Uw=".bostrat/handoff",Hw="latest.md",Dw=32*1024;qw="Checkpoint: write a work-in-progress handoff",Kw="HANDOFF WRITTEN",Gw="Resume from .bostrat/handoff/latest.md",eI="/clear",nI=t=>`${qw} to the EXACT absolute path ${t} (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 ${Kw} and take no further action.`,rI=`${Gw}: read it, restate the Objective and the single next step in one line, then continue the work from 'Next steps'.`,Vw="Beat: write a",zw="BEAT WRITTEN",oI=".bostrat/arc",sI="beat.txt",jw=200,Jw=4,Yw=5,aI=36,iI=t=>`${Vw} short summary of what this workstream accomplished, to the EXACT absolute path ${t} (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 ${Jw} further lines, each starting with "- " and naming ONE piece in at most ${Yw} 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 ${zw} and take no further action.`,Lw=/^(?:[-–—*•·]|\d+[.)])\s+/,cI=(t,e,n)=>{let r=t.split(/\s+/).filter(Boolean).slice(0,e).join(" ");return r.length>n?`${r.slice(0,n-1).trimEnd()}\u2026`:r};uI=6e5;dI=3500,fI=3e5,Nu=new Map;Fw=".bostrat/handoff/status-latest.md"});function cg(t,e,n){if(t==null)return e==="from"?-1/0:1/0;if(!hI.test(String(t)))throw new Error(`pricing.js: ${n} window ${e} must be YYYY-MM-DD, got ${JSON.stringify(t)}`);let r=Date.parse(`${t}T${e==="from"?"00:00:00.000":"23:59:59.999"}Z`);if(!Number.isFinite(r))throw new Error(`pricing.js: ${n} window ${e} is not a real date: ${t}`);return r}function wI(t){let e={};for(let[n,r]of Object.entries(t)){if(!Array.isArray(r)||r.length===0)throw new Error(`pricing.js: ${n} must be a non-empty array of rate windows`);e[n]=r.map(o=>({...o,fromMs:cg(o.from,"from",n),toMs:cg(o.to,"to",n)}))}return e}function yI(t){if(t==null)return Date.now();if(typeof t=="number")return Number.isFinite(t)?t:null;if(t instanceof Date){let n=t.getTime();return Number.isFinite(n)?n:null}let e=Date.parse(String(t));return Number.isFinite(e)?e:null}function bI(t){if(!t)return null;let e=String(t).trim();return ju[e]?e:ig[e]?ig[e]:Object.keys(ju).find(r=>e.startsWith(r))||null}function lg(t,e){let n=bI(t);if(!n)return null;let r=yI(e);return r===null?null:gI[n].find(o=>r>=o.fromMs&&r<=o.toMs)||null}function In(t,e={},n){let r=lg(t,n);return r?((e.input||0)*r.input+(e.output||0)*r.output+(e.cacheWrite||0)*r.cacheWrite+(e.cacheRead||0)*r.cacheRead)/1e6:0}var ju,ig,hI,gI,ug,Es=M(()=>{ju={"claude-opus-5":[{from:null,to:null,input:5,output:25,cacheWrite:10,cacheRead:.5,note:"GA rates; verified 2026-08-06 via the claude-api skill."}],"claude-opus-4-8":[{from:null,to:null,input:5,output:25,cacheWrite:10,cacheRead:.5,note:"verified 2026-08-06 via the claude-api skill."}],"claude-sonnet-5":[{from:null,to:"2026-08-31",input:2,output:10,cacheWrite:4,cacheRead:.2,note:"GA introductory pricing ($2/$10); verified 2026-08-06 via the claude-api skill."},{from:"2026-09-01",to:null,input:3,output:15,cacheWrite:6,cacheRead:.3,note:"standard rates resume after the intro window; verified 2026-08-06."}],"claude-sonnet-4-6":[{from:null,to:null,input:3,output:15,cacheWrite:6,cacheRead:.3,note:"verified 2026-08-06 via the claude-api skill."}],"claude-haiku-4-5":[{from:null,to:null,input:1,output:5,cacheWrite:2,cacheRead:.1,note:"verified 2026-08-06 via the claude-api skill."}],"claude-fable-5":[{from:null,to:null,input:10,output:50,cacheWrite:20,cacheRead:1,note:"verified 2026-08-06 via the claude-api skill; 83% of fleet spend."}],"gpt-5.5":[{from:null,to:null,input:5,output:30,cacheWrite:5,cacheRead:.5,note:"verified 2026-07-03; no cache-write premium on 5.5-and-earlier."}],"gpt-5.6-sol":[{from:null,to:null,input:5,output:30,cacheWrite:6.25,cacheRead:.5,note:"verified 2026-07-18; cacheWrite = 1.25\xD7 input (30-min TTL)."}],"gpt-5.6-terra":[{from:null,to:null,input:2.5,output:15,cacheWrite:3.125,cacheRead:.25,note:"verified 2026-07-18; cacheWrite = 1.25\xD7 input (30-min TTL)."}],"gpt-5.6-luna":[{from:null,to:null,input:1,output:6,cacheWrite:1.25,cacheRead:.1,note:"verified 2026-07-18; cacheWrite = 1.25\xD7 input (30-min TTL)."}]},ig={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"},hI=/^\d{4}-\d{2}-\d{2}$/;gI=wI(ju);ug=(t,e)=>lg(t,e)!==null});function kI(t){return t?{input:t.input||0,output:t.output||0,cacheRead:t.cacheRead||0,cacheWrite:t.cacheWrite??t.cacheCreation??0}:null}function fg(t,e){e&&(t.input+=e.input,t.output+=e.output,t.cacheRead+=e.cacheRead,t.cacheCreation+=e.cacheWrite)}function Ke(t){let e=t.payload?.model||"unknown",n=kI(t.payload?.tokens),r=Number(t.payload?.usd)||0,o=t.source==="vendor",s=r,a=!1;if(n&&!o){let l=In(e,n,t.ts);l>0&&(s=l,a=Math.abs(l-r)>1e-9)}let i=n?n.input+n.output+n.cacheRead+n.cacheWrite:0,c=!s&&i>0&&!ug(e,t.ts);return{usd:s,model:e,tokens:n,repriced:a,unpriced:c,asRecorded:r}}function Rn(t,{boxLabels:e={}}={}){let n=(t||[]).filter(f=>f.type==="cost.recorded"),r={},o={},s={},a=0,i=0,c=0,l=0,u=new Set,d=dg();for(let f of n){let{usd:p,model:m,tokens:w,repriced:y,unpriced:k,asRecorded:S}=Ke(f);i+=S;let $=f.provider||"unknown",R=f.boxId||"unattributed";if(y&&c++,k&&(l++,u.add(m)),a+=p,fg(d,w),r[m]||={usd:0,tokens:dg(),events:0},r[m].usd+=p,r[m].events+=1,fg(r[m].tokens,w),o[$]||={usd:0,events:0},o[$].usd+=p,o[$].events+=1,s[R]||={usd:0,events:0,provider:$,models:new Set,label:e[R]||R},s[R].usd+=p,s[R].events+=1,m!=="unknown"&&s[R].models.add(m),f.epoch!=null){let J=(s[R].epochs||={})[f.epoch]||={usd:0,events:0,provider:$,models:new Set};J.usd+=p,J.events+=1,J.provider=$,m!=="unknown"&&J.models.add(m)}}return{totalUsd:eo(a),asRecordedUsd:eo(i),totalTokens:d,turns:n.length,repricedTurns:c,unpricedTurns:l,unpricedModels:[...u],byModel:Ei(r,f=>({...f,usd:eo(f.usd)})),byProvider:Ei(o,f=>({...f,usd:eo(f.usd)})),byBox:Ei(s,f=>({usd:eo(f.usd),events:f.events,provider:f.provider,label:f.label,models:[...f.models],...f.epochs?{epochs:Ei(f.epochs,p=>({usd:eo(p.usd),events:p.events,provider:p.provider,models:[...p.models]}))}:{}}))}}var dg,eo,Ei,ur=M(()=>{Es();dg=()=>({input:0,output:0,cacheRead:0,cacheCreation:0});eo=t=>Math.round(t*1e4)/1e4,Ei=(t,e)=>Object.fromEntries(Object.entries(t).map(([n,r])=>[n,e(r)]))});function xI(t){if(!Number.isFinite(t)||t<=0)return null;let e=t/864e5;if(e>=1)return`${Math.round(e)}d`;let n=t/36e5;return n>=1?`${Math.round(n)}h`:`${Math.max(1,Math.round(t/6e4))}m`}function pg(t,e=[]){let n=[],r=t?.events||[],o=new Map,s=0;for(let u of e){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[f,p]=d.split("#");return`${f.split("/").pop()}#${p}`});n.push(`Merged ${u.slice(0,4).join(", ")}${u.length>4?` +${u.length-4}`:""}`)}else s&&n.push(Lu(s,"PR")+" opened");let a=Object.keys(t?.subtasks||{}).length||r.filter(u=>u.type==="subtask-delegated").length;a&&n.push(Lu(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(`${Lu(i.length,"handoff")} ${u}${i.length>3?"\u2026":""}`)}let c=Rn(e);c.totalUsd>=.01&&n.push(`$${c.totalUsd.toFixed(2)}`);let l=Number.isFinite(t?.archivedAt)&&Number.isFinite(t?.createdAt)?xI(t.archivedAt-t.createdAt):null;return n.length&&l&&n.push(l),n.length?n.join(" \xB7 "):null}var Lu,mg=M(()=>{ur();Lu=(t,e)=>`${t} ${e}${t===1?"":"s"}`});import{execFile as SI}from"node:child_process";import{promisify as vI}from"node:util";import{randomUUID as TI}from"node:crypto";async function Fu(t,e){let n=Date.now()+e;for(;;){if(await Kr(t))return!0;if(Date.now()>n)return!1;await _i(EI)}}async function II(t,e){let n=wg[e]||wg.default;n.escape&&(await Tt(t,["Escape"],{kind:"swap-exit"}),await _i(150)),n.wipe&&await Gr(t,ai,{kind:"swap-exit"}),await ii(t,n.text,{perCharDelayMs:90,kind:"swap-exit"});let r=Ie(e).submitDelayMs||0;await _i(Math.max(r,250)),await Tt(t,["Enter"],{kind:"swap-exit"})}async function RI(t,e){try{let{stdout:n}=await no(B,j("show-environment","-t",t,e));return!String(n||"").trimStart().startsWith("-")}catch{return!1}}async function gg(t){await no(B,j("respawn-pane","-k","-t",t))}async function Uu(t,e={}){if(!bt(t))throw new Error("invalid session name");let n=String(e.agentCmd||"").trim();if(!n)throw new Error("agentCmd is required");let r=await tt(t);if(!r)throw new Error(`session "${t}" not found`);if(!r.cwd)throw new Error(`can't resolve cwd for "${t}"`);let o=r.agent||"agent",s=e.agent||kn(n),a=Number(e.exitTimeoutMs)||AI;await G({flow:"swap",phase:"start",sessionName:t,from:o,to:s,cwd:r.cwd});let i=!1;if(!await Kr(t)&&(await II(t,o),!await Fu(t,a)&&(i=!0,await G({flow:"swap",phase:"respawn-forced",sessionName:t,from:o}),await gg(t),!await Fu(t,hg))))throw new Error(`pane shell did not come back after respawn-pane in "${t}"`);let c=s==="claude"&&rr(n),l=c?Ua():null,u=await RI(t,"ANTHROPIC_API_KEY"),d=!1;try{l?(await no(B,j("set-environment","-t",t,"ANTHROPIC_API_KEY",l)),d=!0):u&&(await no(B,j("set-environment","-u","-t",t,"ANTHROPIC_API_KEY")),d=!0)}catch(y){throw l?ei(y,l):y}if(d&&!i&&(await gg(t),!await Fu(t,hg)))throw new Error(`pane shell did not come back after env respawn in "${t}"`);let f=!!e.resumeSessionId,p=e.resumeSessionId||TI(),m=f?n:ql(n,p,t),w=f?e.pinned===!0:/(^|\s)--session-id(\s|=)/.test(m);return c&&await mn(r.cwd),s==="codex"&&await Br(r.cwd),s==="cursor"&&await Dr(r.cwd),await sr(t),await no(B,j("set-option","-t",t,"@bostrat-sid",p)),await no(B,j("set-option","-t",t,"@bostrat-agent",s)),await _i(_I),await Mt(t,m,{kind:"swap-launch"}),await G({flow:"swap",phase:"done",sessionName:t,from:o,to:s,sid:p,forced:i,envRespawned:d}),{name:t,cwd:r.cwd,sessionId:p,agent:s,pinned:w,forced:i,envRespawned:d}}var no,_i,AI,hg,EI,_I,wg,yg=M(()=>{Ht();Qo();Wa();qa();gs();We();no=vI(SI),_i=t=>new Promise(e=>setTimeout(e,t)),AI=Number(process.env.BOSTRAT_SWAP_EXIT_TIMEOUT_MS)||15e3,hg=Number(process.env.BOSTRAT_SWAP_SHELL_TIMEOUT_MS)||8e3,EI=250,_I=400,wg={claude:{escape:!0,wipe:!0,text:"/exit"},codex:{escape:!0,wipe:!0,text:"/quit"},cursor:{escape:!0,wipe:!0,text:"/quit"},default:{escape:!1,wipe:!1,text:"exit"}}});async function bg(t,{maxBytes:e=2097152,limit:n=100}={}){let r;try{r=await Jt(t,e)}catch{return[]}let o=new Map,s=new Set;for(let i of r.split(`
112
- `)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.isSidechain)continue;let u=l.message?.content;if(!Array.isArray(u))continue;let d=l.timestamp?Date.parse(l.timestamp):null;for(let f of u)if(!(!f||typeof f!="object"))if(f.type==="tool_use"&&f.id){if(f.name==="Agent"){let p=f.input||{};o.set(f.id,{id:f.id,kind:"agent",name:String(p.description||"").trim()||null,detail:String(p.subagent_type||"").trim()||null,ts:d,proven:!1})}else if(f.name==="Bash"&&f.input?.run_in_background===!0){let p=String(f.input.command||"").trim();o.set(f.id,{id:f.id,kind:"command",name:String(f.input.description||"").trim()||(p?Xr(p):null),detail:p?Xr(p):null,ts:d,proven:!0})}}else f.type==="tool_result"&&f.tool_use_id&&$I.test(OI(f.content))&&s.add(f.tool_use_id)}let a=[];for(let i of o.values()){if(!i.proven&&!s.has(i.id))continue;let{proven:c,...l}=i;a.push(l)}return a.slice(-n)}var $I,OI,kg=M(()=>{we();Zr();$I=/^Async (?:agent|task) launched/i,OI=t=>{if(typeof t=="string")return t.trim();if(!Array.isArray(t))return"";let e=t.find(n=>n&&n.type==="text"&&typeof n.text=="string");return e?e.text.trim():""}});function $n(t,e){if(!t)return null;let n=String(t);if(e){let o=e.endsWith("/")?e:`${e}/`;if(n===e)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 CI(t){let e=typeof t=="string"?t:String(t?.patch??t?.input??""),n=[];for(let r of e.matchAll(/^\*{3} (?:Update|Add|Delete) File: (.+)$/gm))n.push(r[1].trim());return n}function xg(t,e,n){switch(t){case"Shell":{let r=String(e?.command||"").trim();return r?{command:r,description:String(e?.description||"").trim()}:null}case"Read":{let r=e?.path;if(!r)return null;let o=Number(e?.offset)||null,s=o&&Number(e?.limit)?o+Number(e.limit)-1:null;return{command:ge(`read ${$n(r,n)}${o?` (lines ${o}\u2013${s??"end"})`:""}`,140),description:o?`Read lines ${o}\u2013${s??"end"} of ${ro(r)}`:`Read ${ro(r)}`}}case"Grep":{let r=e?.pattern;if(!r)return null;let o=e?.path?$n(e.path,n):null,s=e?.glob?` --glob ${Hu(e.glob)}`:"",a=ge(String(r),40);return{command:ge(`grep ${Hu(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=e?.glob_pattern;if(!r)return null;let o=e?.target_directory?$n(e.target_directory,n):null;return{command:ge(`glob ${Hu(r)}${o&&o!=="."?` ${o}`:""}`,140),description:`Find files matching \u201C${ge(String(r),40)}\u201D`}}case"StrReplace":return e?.path?{command:ge(`edit ${$n(e.path,n)}`,140),description:`Edit ${ro(e.path)}`}:null;case"Write":return e?.path?{command:ge(`write ${$n(e.path,n)}`,140),description:`Write ${ro(e.path)}`}:null;case"Delete":return e?.path?{command:ge(`delete ${$n(e.path,n)}`,140),description:`Delete ${ro(e.path)}`}:null;case"ReadLints":{let o=(Array.isArray(e?.paths)?e.paths:[]).map(s=>$n(s,n)).filter(Boolean);return{command:ge(o.length?`lints ${o.join(" ")}`:"lints",140),description:"Check lints"}}case"ApplyPatch":{let r=CI(e);if(!r.length)return null;let o=r.length>1?` (+${r.length-1} more)`:"";return{command:ge(`apply_patch ${$n(r[0],n)}${o}`,140),description:r.length>1?`Patch ${r.length} files`:`Patch ${ro(r[0])}`}}case"Await":{let r=e?.shell_id??e?.task_id;return{command:ge(`await ${r??"background output"}`,140),description:"Wait for a background command"}}default:return null}}var Ii,ge,ro,Hu,Sg=M(()=>{Ii=new Set(["Shell","Read","Grep","Glob","StrReplace","Write","ReadLints","Delete","ApplyPatch","Await"]),ge=(t,e=88)=>t.length>e?`${t.slice(0,e).trimEnd()}\u2026`:t,ro=t=>String(t).replace(/\/+$/,"").split("/").pop()||String(t);Hu=t=>`"${String(t).replace(/"/g,'\\"')}"`});import _s from"node:fs";import MI from"node:fs/promises";import dr from"node:path";import PI from"node:os";import NI from"node:crypto";import BI from"node:zlib";function Ag(t){let e=NI.createHash("md5").update(String(t)).digest("hex");return dr.join(DI,e)}function Eg(t){try{let e=JSON.parse(_s.readFileSync(dr.join(t,"meta.json"),"utf8"));return{createdAtMs:Number(e.createdAtMs)||null,updatedAtMs:Number(e.updatedAtMs)||Number(e.createdAtMs)||null,hasConversation:e.hasConversation===!0}}catch{return null}}function jI(t){let e=Ag(t),n;try{n=_s.readdirSync(e,{withFileTypes:!0}).filter(o=>o.isDirectory())}catch{return null}let r=null;for(let o of n){let s=dr.join(e,o.name),a=dr.join(s,"store.db");if(!_s.existsSync(a))continue;let i=Eg(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 Ri(t,e){if(!t)return null;if(e){let n=dr.join(Ag(t),e),r=dr.join(n,"store.db");if(_s.existsSync(r))return{id:e,dir:n,store:r,...Eg(n)||{createdAtMs:null,updatedAtMs:null}}}return jI(t)}function vg(t,e){let n=t.prepare("SELECT data FROM blobs WHERE id = ?").get(e);return n?Buffer.from(n.data):null}function LI(t){if(!t)return null;let e=t;if(e.length>1&&e[0]===31&&e[1]===139)try{e=BI.gunzipSync(e)}catch{}try{return JSON.parse(e.toString("utf8"))}catch{return null}}function FI(t){let e=[],n=0,r=t.length,o=()=>{let s=0,a=0;for(;n<r;){let i=t[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=t.subarray(n,n+c);n+=c,a===1&&c===32&&e.push(l.toString("hex"))}else if(i===0)o();else if(i===5)n+=4;else if(i===1)n+=8;else break}return e}function UI(t,e){if(!Array.isArray(t))return[];let n=[];for(let r of t){if(!r||r.type!=="tool-call"||!Ii.has(r.toolName))continue;let o=xg(r.toolName,r.args,e);!o||!o.command||n.push({id:r.toolCallId||null,tool:r.toolName,command:o.command,description:o.description||""})}return n}async function Wu(t,e){if(!Tg)return oo;let{DatabaseSync:n}=Tg,r;try{r=new n(t,{readOnly:!0})}catch{return oo}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 oo;let s;try{s=JSON.parse(Buffer.from(String(o.value),"hex").toString("utf8"))}catch{return oo}let a=s.lastUsedModel||null,i=s.latestRootBlobId?vg(r,s.latestRootBlobId):null;if(!i)return{...oo,model:a};let c=[],l=[],u=[],d=null,f=[];for(let p of FI(i)){let m=LI(vg(r,p));if(!m)continue;let w=m.providerOptions?.cursor;if(w?.requestId&&f.push(w.requestId),w?.modelProviderMessageId&&f.push(w.modelProviderMessageId),m.role!=="assistant")continue;if(Array.isArray(m.content))for(let S of m.content){let $=S?.providerOptions?.cursor?.modelName;$&&(d=$)}l.push(...UI(m.content,e).map((S,$)=>({...S,id:S.id||`${p}:${$}`}))),u.push(...WI(m.content));let y=HI(m.content);if(!y)continue;let k=[...new Set(u)];u=[],c.push({id:p,text:y,tools:k.length?k:void 0,commands:l,model:d}),l=[]}return{turns:c,trailingCommands:l,model:a,requestIds:f}}catch{return oo}finally{try{r.close()}catch{}}}function _g(t,e){let n=t.updatedAtMs;if(!n)try{n=Math.round(_s.statSync(t.store).mtimeMs)}catch{n=Date.now()}let r=t.createdAtMs;(!r||r>n)&&(r=n-e*1e3);let o=Math.max(0,n-r);return{end:n,tsAt:s=>Math.round(r+o*(s+1)/e)}}async function Ig(t,e,{limit:n=80}={}){let r=Ri(t,e);if(!r)return[];let{turns:o,model:s}=await Wu(r.store,t);if(!o.length)return[];let a=o.slice(-n),{tsAt:i}=_g(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 Rg(t,e){let n=Ri(t,e);if(!n)return null;let{turns:r,requestIds:o,model:s}=await Wu(n.store,t);return{chatId:n.id,requestIds:o,models:[...new Set(r.map(a=>a.model).filter(Boolean))],configuredModel:s,updatedAtMs:n.updatedAtMs||null}}async function $g(t,e,{limit:n=80}={}){let r=Ri(t,e);if(!r)return[];let{turns:o,trailingCommands:s}=await Wu(r.store,t);if(!o.length&&!s.length)return[];let a=o.slice(-n),{end:i,tsAt:c}=_g(r,a.length||1),l=[];a.forEach((u,d)=>{for(let f of u.commands)l.push({...f,summary:An(f.command,f.description),ts:c(d)})});for(let u of s)l.push({...u,summary:An(u.command,u.description),ts:i+1});return l}async function Og(t,e){let n=Ri(t,e);if(!n)return null;if(n.updatedAtMs)return n.updatedAtMs;try{return Math.round((await MI.stat(n.store)).mtimeMs)}catch{return null}}var DI,HI,WI,Tg,oo,qu=M(()=>{Zr();Sg();DI=process.env.BOSTRAT_CURSOR_CHATS||dr.join(PI.homedir(),".cursor","chats");HI=t=>typeof t=="string"?t.trim():Array.isArray(t)?t.filter(e=>e&&e.type==="text"&&typeof e.text=="string").map(e=>e.text).join(`
113
- `).trim():"",WI=t=>Array.isArray(t)?t.filter(e=>e&&e.type==="tool-call"&&e.toolName).map(e=>e.toolName):[],Tg=process.getBuiltinModule?.("node:sqlite"),oo={turns:[],trailingCommands:[],model:null,requestIds:[]}});import qI from"node:fs/promises";function zu(t){return Cg.set(t.agent,t),t}function Is(t){return Cg.get(t)||KI}async function Yu(t,e={}){return(await Is(t.agent).readMessages(t,e)).map(Ju(t))}async function Mg(t,e={}){return(await Is(t.agent).readCommands(t,e)).map(Ju(t))}async function Pg(t,e={}){return(await Is(t.agent).readJobs(t,e)).map(Ju(t))}var so,Ku,Gu,Vu,KI,Cg,Ju,Ng=M(()=>{we();li();Zr();kg();qu();Qr();so=class{constructor(e,n=new Set){this.agent=e,this.cliTools=n}async readMessages(){return[]}async readCommands(){return[]}async readJobs(){return[]}async updatedAt(){return null}},Ku=class extends so{transcript(e){return!e?.cwd||!e?.sessionId?null:qe(e.cwd,e.sessionId)}async readMessages(e,n){let r=this.transcript(e);return r?Zl(r,n):[]}async readCommands(e,n){let r=this.transcript(e);return r?iw(r,n):[]}async readJobs(e,n){let r=this.transcript(e);return r?bg(r,n):[]}async updatedAt(e){let n=this.transcript(e);if(!n)return null;try{return Math.round((await qI.stat(n)).mtimeMs)}catch{return null}}},Gu=class extends so{async readMessages(e,n){return Ig(e.cwd,e.sessionId,n)}async readCommands(e,n){return $g(e.cwd,e.sessionId,n)}async updatedAt(e){return Og(e.cwd,e.sessionId)}},Vu=class extends so{sessionId(e){return e?.pinned?e.sessionId:null}async readMessages(e,n){return dw(e.cwd,this.sessionId(e),n)}async readCommands(e,n){return fw(e.cwd,this.sessionId(e),n)}async updatedAt(e){return pw(e.cwd,this.sessionId(e))}},KI=new so("unknown"),Cg=new Map;zu(new Ku("claude",wu));zu(new Gu("cursor",Ii));zu(new Vu("codex",Ss));Ju=t=>e=>({...e,box:t.name,agent:t.agent,boxRole:t.role})});function mr(t){let e=t.search(td);return(e>=0?t.slice(0,e):t).trim()}function GI(t){if(!t)return"";let e=t.replace(/[│┌└├─┘┤┬┴┼─✂].*$/,"").trim();return!e||/hidden|\d+\s+lines?/i.test(e)?"":e}function VI(t){let e=String(t).trim();return!!(!e||pr.test(t)||td.test(e)||/hidden|\d+\s+lines?/i.test(e)||/notespress|press n to add/i.test(e)||/^\s*notes?\s*$/i.test(e))}function zI(t,e=""){let n=[],r=/([☐☒])\s+([^☐☒←→✔]+)/g,o;for(;(o=r.exec(t))!==null;)n.push({label:o[2].trim(),answered:o[1]==="\u2612",current:!1});if(!n.length)return null;let s=JI(n,e);return n.forEach((a,i)=>{a.current=i===s}),{tabs:n,questionIndex:s,questionTotal:n.length,currentTabLabel:n[s].label}}function JI(t,e){let n=String(e).toLowerCase(),r=t.findIndex(c=>!c.answered),o=r>=0?r:t.length-1;if(!n)return o;let s=t.map(c=>{let l=c.label.toLowerCase(),u=l.split(/\s+/).filter(f=>f.length>3&&n.includes(f)).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 Dg(t){return t.replace(/[←→✔☐☒●▶]/g," ").replace(/\bSubmit\b/g," ").replace(/\s+/g," ").trim()}function YI(t,e=""){let n=String(t);if(!Lg.test(n))return null;let r=n.replace(/\r/g,"").split(`
114
- `),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(fr);if(d)s.push({cursor:!!d[1],label:d[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let f=r[u].trim();f&&!pr.test(r[u])&&a.push(f)}}if(s.length<2)return null;let i=s.map(u=>({label:mr(u.label),description:""})),c=Math.max(0,s.findIndex(u=>u.cursor)),l=["Switch model?",...a].join(" ");return{provider:"claude",box:e,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 ZI(t,e=""){let n=String(t).replace(/\r/g,"").split(`
115
- `),r=n.length-1;for(;r>=0&&n[r].trim()==="";)r--;if(r<0||!Fg.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(fr);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&&!(XI.test(n[c])||pr.test(n[c]));c--){let l=n[c].trim();l&&a.unshift(l)}let i=s.map(c=>({label:mr(c.label),description:""}));return{provider:"claude",box:e,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 QI(t,e=""){let n=String(t);if(!/ready to submit your answers/i.test(n))return null;let r=n.replace(/\r/g,"").split(`
116
- `),o=[];for(let c=0;c<r.length;c++){let l=r[c].match(fr);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:e,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 eR(t,e=""){let n=String(t);if(!Xu.test(n))return null;let r=n.replace(/\r/g,"").split(`
117
- `),o=-1;for(let u=r.length-1;u>=0;u--)if(tR.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(fr);if(d)s.push({cursor:!!d[1],label:d[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let f=r[u].trim();f&&!pr.test(r[u])&&a.push(f)}}if(s.length<2||!s.some(u=>Xu.test(u.label)))return null;let i=s.map(u=>({label:mr(u.label),description:""})),c=Math.max(0,s.findIndex(u=>u.cursor)),l=a.join(" ");return{provider:"claude",box:e,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 ed(t){let e=[];for(let r=0;r<t.length;r++){let o=t[r].match(fr);o&&e.push({line:r,cursor:!!o[1],n:Number(o[2]),label:o[4].trim()})}let n=e.sort((r,o)=>r.n-o.n);return n.length<2||n.some((r,o)=>r.n!==o+1)?null:n}function nR(t,e=""){let n=String(t);if(!Ug.test(n)||!Hg.test(n)||hr.test(n))return null;let r=n.replace(/\r/g,"").split(`
118
- `),o=ed(r);return o?{provider:"claude",box:e,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:mr(s.label),description:""}))}]}:null}function rR(t,e=""){let n=String(t);if(!Wg.test(n)||hr.test(n))return null;let r=n.replace(/\r/g,"").split(`
119
- `),o=ed(r);if(!o)return null;let s=o.map(a=>{let[i,...c]=a.label.split("\xB7");return{label:mr(i),description:c.join("\xB7").trim()}});return{provider:"claude",box:e,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 sR(t,e){let n=t[e].trim();for(let r=e+1;r<t.length;r++){let o=t[r].trim();if(!o||!oR.test(o)||nd.test(t[r]))break;n+=o}return n}function aR(t,e=""){let n=String(t);if(!nd.test(n)||hr.test(n))return null;let r=n.replace(/\r/g,"").split(`
120
- `),o="";for(let s=0;s<r.length;s++)if(/^\s*https:\/\//.test(r[s])){o=sR(r,s);break}return o?{provider:"claude",box:e,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 cR(t,e=""){let n=String(t);if(!Zu.test(n)||!iR.test(n)||hr.test(n))return null;let s=([...n.replace(/\r/g,"").split(`
121
- `)].reverse().find(a=>Zu.test(a))||"OAuth error").trim();return{provider:"claude",box:e,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 lR(t,e=""){let n=String(t);if(!qg.test(n)||hr.test(n))return null;let r=n.replace(/\r/g,"").split(`
122
- `),o=ed(r);return o?{provider:"claude",box:e,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:mr(s.label),description:""}))}]}:null}function uR(t,e=""){let n=String(t);if(hr.test(n))return null;let r=n.replace(/\r/g,"").split(`
123
- `),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(Kg);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(pr.test(r[l])||td.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:e,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 dR(t){let e=-1;for(let r=t.length-1;r>=0;r--)if(Qu.test(t[r])){e=r;break}if(e<0)return null;let n=-1;for(let r=e-1;r>=0;r--)if(/[☐☒]/.test(t[r])){n=r;break}return n<0?null:{headerLine:n,chatLine:e,optStart:n+1,optEnd:e}}function fR(t,e=""){let n=String(t);if(!jg.test(n)||!Qu.test(n))return null;let r=n.replace(/\r/g,"").split(`
124
- `),o=dR(r);if(!o)return null;let{headerLine:s,chatLine:a,optStart:i,optEnd:c}=o,l=[],u=-1;for(let A=i;A<c;A++){let N=r[A].match(fr);N&&(u<0&&(u=A),l.push({line:A,cursor:!!N[1],checked:N[3]!=null&&N[3]!==" ",hasCheckbox:N[3]!=null,label:N[4].trim(),desc:""}))}if(!l.length)return null;for(let A of l)for(let N=A.line+1;N<Math.min(r.length,A.line+4)&&!(fr.test(r[N])||pr.test(r[N]));N++){let W=r[N].trim();if(!(!W||VI(r[N])||Bg.test(W))){A.desc=GI(W);break}}let d=l.filter(A=>!Bg.test(A.label));if(!d.length)return null;let f=d.some(A=>A.hasCheckbox),p=Math.max(0,d.findIndex(A=>A.cursor)),m=s>=0?s+1:0,w=[];for(let A=m;A<u;A++){let N=r[A].trim();N&&!pr.test(r[A])&&!/[☐☒]/.test(r[A])&&w.push(N)}let y=w.join(" ")||(s>=0?Dg(r[s]):"")||"The agent is asking a question",k=s>=0?zI(r[s],y):null,S=k?.currentTabLabel||(s>=0?Dg(r[s]):""),$=d.map(A=>({label:mr(A.label),description:A.desc})),R=$.map(A=>A.label).join("|"),C=`claude:${k?`q${k.questionIndex+1}/${k.questionTotal}`:"q1/1"}:${S}:${y}:${R}`.slice(0,240),D=k?`claude:ask:${k.tabs.map(A=>A.label).join("|")}`.slice(0,240):C;return{provider:"claude",box:e,multiSelect:f,cursorIndex:p,promptId:C,groupId:D,...k?{questionIndex:k.questionIndex,questionTotal:k.questionTotal,currentTabLabel:k.currentTabLabel,tabs:k.tabs}:{},questions:[{question:y,header:S,multiSelect:f,options:$}]}}function ao(t,e){let n=String(e||"");return n?t==="claude"?jg.test(n)&&Qu.test(n)||Lg.test(n)||Xu.test(n)||Fg.test(n.trimEnd().split(`
125
- `).pop()||"")?!0:hr.test(n)?!1:Ug.test(n)&&Hg.test(n)||Wg.test(n)||nd.test(n)||Zu.test(n)||qg.test(n)||Kg.test(n.trimEnd().split(`
126
- `).pop()||""):t==="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:t==="cursor"||t==="codex"?/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i.test(n):!1:!1}function wr(t,e){return!t||!e?null:t.agent==="claude"?QI(e,t.name)||fR(e,t.name)||YI(e,t.name)||eR(e,t.name)||cR(e,t.name)||aR(e,t.name)||rR(e,t.name)||nR(e,t.name)||lR(e,t.name)||uR(e,t.name)||ZI(e,t.name):t.agent==="cursor"||t.agent==="codex"?Lh(t.agent,e,t.name):null}async function rd(t){if(!t)return null;let e=await Sn(t.name).catch(()=>"");return wr(t,e)}function Gg(t,e){let n=Array.isArray(e?.[0])?e[0].filter(a=>Number.isInteger(a)&&a>=0):[],r=Number.isInteger(t?.cursorIndex)?t.cursorIndex:0,o=(a,i)=>{let c=i-a;return Array.from({length:Math.abs(c)},()=>c>0?"Down":"Up")},s=[];if(t?.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 Vg(t,e){let n=Number.isInteger(t?.questionIndex)?t.questionIndex:0,o=(Number.isInteger(e)?e:n)-n;if(!o)return[];let s=o>0?"Tab":"BTab";return Array.from({length:Math.abs(o)},()=>s)}var jg,Qu,fr,Bg,pr,td,Lg,Fg,XI,Xu,tR,hr,Ug,Hg,Wg,nd,oR,Zu,iR,qg,Kg,od=M(()=>{Ht();ui();jg=/to navigate\b.*\bEsc to cancel|Enter to select\b/,Qu=/Chat about this/i,fr=/^\s*(❯)?\s*(\d+)\.\s+(?:\[([ xX✔])\]\s+)?(.+?)\s*$/,Bg=/^(type something|chat about this|submit)\b/i,pr=/^[─—-]{6,}\s*$/,td=/[\u2500-\u257F\u2550-\u256F┌┐└┘├┤│┬┴┼─✂]/;Lg=/^\s*Switch model\?\s*$/m;Fg=/^\s*Enter to confirm\s*·\s*Esc to cancel\s*$/,XI=/^\s*[─—▔-]{6,}\s*$/;Xu=/Resume from summary/i,tR=/^\s*This session is\b/;hr=/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/;Ug=/Choose the text style that looks best with your terminal/,Hg=/Let's get started\./;Wg=/Select login method:/;nd=/Paste code here if prompted/,oR=/^[A-Za-z0-9%&=+._~#?/:\-]+$/;Zu=/OAuth error:/,iR=/Press Enter to retry\./;qg=/Quick safety check: Is this a project you created or one you trust/;Kg=/^(.{0,60}?)Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/});function $i(t,e,n){if(!t||!e)return null;for(let r of pR)if(r.provider===t.agent)try{if(r.match(e,n))return r}catch{}return null}function hR(t){let e=sd.get(t);return e||(e={sentAt:[],last:0,emitted:new Set},sd.set(t,e)),e}function Yg(t,e,n=Date.now()){let r=hR(t);if(r.sentAt=r.sentAt.filter(s=>n-s<Jg),r.sentAt.length>=zg)return{action:"give-up"};if(n-r.last<mR)return{action:"wait"};r.last=n,r.sentAt.push(n);let o=!r.emitted.has(e);return o&&r.emitted.add(e),{action:"send",first:o}}function Xg(t,e=Date.now()){let n=sd.get(t);return n?n.sentAt.filter(r=>e-r<Jg).length>=zg:!1}var pR,mR,zg,Jg,sd,ad=M(()=>{pR=[{provider:"claude",id:"fullscreen-upsell",match(t,e){let n=t?.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||""}
127
- ${String(e||"")}`;return/Try the new fullscreen renderer|Flicker-free output/i.test(o)},keys:["Escape"]}];mR=5e3,zg=5,Jg=3600*1e3,sd=new Map});function io(t){return typeof t=="string"?t.trim():""}var Zg=M(()=>{});import{execFile as wR}from"node:child_process";import{promisify as gR}from"node:util";async function xt(t,e,{input:n}={}){let r=cd("git",["-C",t,...e],{maxBuffer:Qg});return n!==void 0&&r.child.stdin&&(r.child.stdin.on("error",()=>{}),r.child.stdin.end(n)),r}async function Oi(t){if(!t)return!1;try{let{stdout:e}=await xt(t,["rev-parse","--is-inside-work-tree"]);return e.trim()==="true"}catch{return!1}}async function ty(t){let{stdout:e}=await xt(t,["rev-parse","--show-toplevel"]);return e.trim()}async function yR(t){try{return await xt(t,["rev-parse","--verify","HEAD"]),!0}catch{return!1}}async function Rs(t,e="bostrat: subtask snapshot"){let{stdout:n}=await xt(t,["rev-parse","--absolute-git-dir"]),r=`${n.trim()}/bostrat-snapshot-index`,o={...process.env,GIT_INDEX_FILE:r},s=(a,i)=>cd("git",["-C",t,...a],{maxBuffer:Qg,env:o,...i});try{let a=await yR(t);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",e]:["commit-tree",c,"-m",e],{stdout:u}=await s(l);return u.trim()}finally{try{await cd("rm",["-f",r])}catch{}}}async function ld(t,e){let{stdout:n}=await xt(t,["status","--porcelain"]);return n.trim()?(await xt(t,["add","-A"]),await xt(t,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","-m",e]),!0):!1}async function ud(t,{ignorePlumbing:e=!1}={}){let{stdout:n}=await xt(t,["status","--porcelain"]),r=n.split(`
128
- `).filter(Boolean);return e&&(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 dd(t,e){if(!e)return 0;try{let{stdout:n}=await xt(t,["rev-list","--count",`${e}..HEAD`]);return Number(n.trim())||0}catch{return 0}}async function co(t,e,n,r){return await xt(t,["worktree","add","--no-track","-b",n,e,r]),e}async function ey(t,e){try{return await xt(t,["rev-parse","--verify","--quiet",`refs/heads/${e}`]),!0}catch{return!1}}async function ny(t,e,n){return await xt(t,["worktree","add",e,n]),e}async function Ci(t){if(process.env.BOSTRAT_TRACK_BASE_REF)return process.env.BOSTRAT_TRACK_BASE_REF;try{let{stdout:e}=await xt(t,["symbolic-ref","--short","refs/remotes/origin/HEAD"]);if(e.trim())return e.trim()}catch{}for(let[e,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 xt(t,["rev-parse","--verify","--quiet",e]),n}catch{}return"HEAD"}async function ry(t){await xt(t,["init","-q"]),await xt(t,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","--allow-empty","-qm","bostrat: track workspace"])}async function ae(t,e){try{await xt(t,["worktree","remove","--force",e])}catch{try{await xt(t,["worktree","prune"])}catch{}}}function bR(t){let e=/(\d+) files? changed/.exec(t),n=/(\d+) insertions?\(\+\)/.exec(t),r=/(\d+) deletions?\(-\)/.exec(t);return{files:e?Number(e[1]):0,insertions:n?Number(n[1]):0,deletions:r?Number(r[1]):0}}function fd(t,e){return!e||!e.length?t:[...t,"--",".",...e.map(n=>`:(exclude)${n}`)]}async function pd(t,e,n,r){let{stdout:o}=await xt(t,fd(["diff","--shortstat",e,n],r));return bR(o)}async function md(t,e,n,r){let{stdout:o}=await xt(t,fd(["diff","--name-only",e,n],r));return o.split(`
129
- `).map(s=>s.trim()).filter(Boolean)}async function hd(t,e,n,r){let{stdout:o}=await xt(t,fd(["diff","--binary",e,n],r));if(!o.trim())return{applied:!0,empty:!0,conflicts:[]};if((await id(t,o,["--whitespace=nowarn"])).ok)return{applied:!0,empty:!1,conflicts:[]};let s=await id(t,o,["--3way","--whitespace=nowarn"]),a=await kR(t);return a.length>0?{applied:!1,empty:!1,conflicts:a}:s.ok?{applied:!0,empty:!1,conflicts:[]}:(await id(t,o,["--reject","--whitespace=nowarn"]),{applied:!1,empty:!1,conflicts:[`patch did not apply cleanly: ${s.err}`]})}async function id(t,e,n){try{return await xt(t,["apply",...n,"-"],{input:e}),{ok:!0}}catch(r){return{ok:!1,err:r?.stderr?.trim()||r?.message||String(r)}}}async function kR(t){try{let{stdout:e}=await xt(t,["diff","--name-only","--diff-filter=U"]);return e.split(`
130
- `).map(n=>n.trim()).filter(Boolean)}catch{return[]}}var cd,Qg,wd=M(()=>{cd=gR(wR),Qg=64*1024*1024});import gd from"node:fs/promises";import sy from"node:path";import xR from"node:os";function ly(t){let e=new Date(t);return e.setHours(0,0,0,0),e.setDate(e.getDate()-(e.getDay()+6)%7),e.getTime()}function uy(t){let e=new Date(t);return e.setHours(0,0,0,0),e.setDate(1),e.getTime()}function dy(t){let e=new Date(ly(t));return e.setDate(e.getDate()+7),e.getTime()}function fy(t){let e=new Date(uy(t));return e.setMonth(e.getMonth()+1),e.getTime()}function Pi(t=Date.now()){for(let[e,n]of Object.entries(lo)){let r=n.startOf(t);if(r!==Ge[e]){Ge[e]=r;for(let o of gr.values())o[e]=0;for(let o of uo)o.includes(`:${e}:`)&&!o.endsWith(`:${r}`)&&uo.delete(o)}}}function py(t,e){let n=ye?.caps?.[t]?.[lo[e].capKey];return Number.isFinite(n)&&n>0?n:null}function fo(t,e=Date.now()){if(!t||!bd||!ye?.caps)return null;Pi(e);let n=gr.get(t);for(let r of Object.keys(lo)){let o=py(t,r);if(o==null)continue;let s=n?.[r]||0;if(s>=o)return{provider:t,window:r,limitUsd:o,spentUsd:Mi(s),resetsAt:lo[r].nextStart(e)}}return null}function my(t,e){let n=`hit:${t}:${e.provider}:${e.window}:${Ge[e.window]}`;return uo.has(n)?!1:(uo.add(n),!0)}function oy(t,e,n,r=Date.now()){if(!t||!e)return;Pi(r);let o=SR(t);for(let[s,a]of Object.entries(lo))n>=Ge[s]&&n<a.nextStart(r)&&(o[s]+=e)}async function vR(t,e,n=Date.now()){if(!ye?.caps||!yd)return;let r=gr.get(t);if(r)for(let[o,s]of Object.entries(lo)){let a=py(t,o);if(a==null)continue;let i=r[o]||0;if(i<a*cy||i>=a)continue;let c=`warn:${t}:${o}:${Ge[o]}`;if(!uo.has(c)){uo.add(c);try{let l=await yd(e);if(!l)continue;await I(l,{type:"usage.cap.warning",actor:"system",provider:t,payload:{provider:t,window:o,limitUsd:a,spentUsd:Mi(i),pct:Math.round(i/a*100),resetsAt:s.nextStart(n)}})}catch{}}}}function hy(t){let e={};for(let[n,r]of Object.entries(t||{})){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&&(e[n]=o)}return e}async function Ni(t,{source:e="local",updatedAt:n=Date.now()}={}){ye={caps:hy(t),updatedAt:n,source:e};try{await gd.mkdir(ay,{recursive:!0}),await gd.writeFile(iy(),JSON.stringify(ye,null,2))}catch{}return $s()}function $s(t=Date.now()){Pi(t);let e=new Set([...gr.keys(),...Object.keys(ye?.caps||{})]),n={};for(let r of e){let o=gr.get(r);n[r]={weeklyUsd:Mi(o?.weekly||0),monthlyUsd:Mi(o?.monthly||0)}}return{caps:ye?.caps||{},configured:!!ye,seeded:bd,updatedAt:ye?.updatedAt??null,spent:n,windows:{weekly:{start:Ge.weekly,resetsAt:dy(t)},monthly:{start:Ge.monthly,resetsAt:fy(t)}},warnPct:cy}}async function wy({listTracks:t,getTrack:e}={}){yd=e||null,Pi();try{let o=JSON.parse(await gd.readFile(iy(),"utf8"));ye={caps:hy(o?.caps),updatedAt:o?.updatedAt??null,source:o?.source??"file"}}catch{ye=null}let n=Date.now();Yt.on("event",o=>{if(o?.type!=="cost.recorded")return;let{usd:s}=Ke(o);oy(o.provider||"unknown",s,o.ts??Date.now()),vR(o.provider||"unknown",o.trackId).catch(()=>{})});let r=Math.min(Ge.weekly,Ge.monthly);for(let o of await t?.()||[]){let s;try{s=await L(o)}catch{continue}for(let a of s){if(a.type!=="cost.recorded")continue;let i=a.ts??0;i<r||i>=n||oy(a.provider||"unknown",Ke(a).usd,i,n)}}return bd=!0,$s()}var ay,iy,cy,lo,ye,bd,Ge,gr,uo,yd,SR,Mi,Bi=M(()=>{ct();ur();ay=process.env.BOSTRAT_STATE_DIR||sy.join(process.env.HOME||xR.tmpdir(),".bostrat"),iy=()=>sy.join(ay,"usage-caps.json"),cy=.8;lo={weekly:{startOf:ly,nextStart:dy,capKey:"weeklyUsd"},monthly:{startOf:uy,nextStart:fy,capKey:"monthlyUsd"}},ye=null,bd=!1,Ge={weekly:0,monthly:0},gr=new Map,uo=new Set,yd=null,SR=t=>{let e=gr.get(t);return e||(e={weekly:0,monthly:0},gr.set(t,e)),e};Mi=t=>Math.round(t*1e4)/1e4});import TR from"node:fs/promises";import AR from"node:os";import gy from"node:path";function Ty(t){return t==="codex"?RR:t==="cursor"?vy:xy}function yy(t){let e=String(t||"").split(`
131
- `),n=e.findIndex(o=>/Select Model and Effort/i.test(o));if(n<0)return null;let r=[];for(let o=n+1;o<e.length;o++){let s=e[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(e[o]))break}return r.length?r:null}function by(t){let e=String(t||"").split(`
132
- `),n=e.findIndex(o=>/Select Reasoning Level/i.test(o));if(n<0)return null;let r=[];for(let o=n+1;o<e.length;o++){let s=e[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(e[o]))break}return r.length?r:null}function $R(t){let e=String(t||"").split(`
133
- `);for(let n=e.length-1;n>=0;n--){let r=e[n].match(/Model changed to\s+(\S+)(?:\s+(\S+))?\s*$/i);if(r)return{model:r[1],effort:r[2]||null}}return null}function ky(t){let e=String(t||"").split(`
134
- `),n=e.findIndex(s=>/Available models|Models matching/i.test(s));if(n<0)return null;let r=/Models matching/i.test(e[n]),o=[];for(let s=n+1;s<e.length;s++){let a=e[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 Ay(t,e){if(typeof e!="string"||!e.trim())throw new Error("model (string) required");let n=e.trim();if(t==="codex"){let[r,o]=n.split(/[\s:]+/);if(o&&!Sy.has(o))throw new Error(`unknown codex effort "${o}" (low | medium | high | xhigh)`);return{model:r,effort:o||null}}if(t==="cursor"){let r=vy.find(o=>o.alias===n);return{model:n,filter:r?r.label:n}}if(!IR.has(n))throw new Error(`unknown model "${n}"`);return{model:n}}async function Os(t,e,{timeoutMs:n=ER}={}){let r=Date.now()+n;for(;;){let o=await yt(t,{lines:80}).catch(()=>""),s=e(o);if(s)return s;if(Date.now()>r)return null;await Di(_R)}}async function OR(t,e){return await Mt(t,`/model ${e.model}`,Ie("claude")),{verified:!1,note:"confirmed when the next turn's transcript model flips"}}async function CR(t,e){await si(t),await Mt(t,"/model",{enter:!1}),await Di(250),await Tt(t,["Enter"],{kind:"model-switch"});let n=await Os(t,yy);if(!n)throw new Error("codex model picker didn't open");let r=n.find(i=>i.id===e.model);if(!r)throw await Tt(t,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`unknown model "${e.model}" \u2014 codex offers: ${n.map(i=>i.id).join(", ")}`);let o=i=>{let c=$R(i);return!c||c.model!==e.model||e.effort&&c.effort&&c.effort.toLowerCase()!==e.effort.toLowerCase()?null:c};await Mt(t,String(r.n),{enter:!1,kind:"model-switch"});let s=await Os(t,i=>by(i)||!yy(i)&&o(i)&&{done:o(i)});if(!s)throw await Tt(t,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error("codex reasoning-level picker didn't open");if(!s.done){let i=e.effort?Sy.get(e.effort):null,c=i?s.find(l=>l.label.toLowerCase()===i.toLowerCase()):s.find(l=>l.isDefault)||s[0];if(!c)throw await Tt(t,["Escape","Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`codex doesn't offer effort "${e.effort}" for ${e.model}`);await Mt(t,String(c.n),{enter:!1,kind:"model-switch"})}let a=s.done||await Os(t,i=>!by(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 MR(){let t=gy.join(process.env.CURSOR_CONFIG_DIR||gy.join(AR.homedir(),".cursor"),"cli-config.json");try{return JSON.parse(await TR.readFile(t,"utf8"))?.model||null}catch{return null}}async function PR(t,e){await si(t),await ii(t,`/model ${e.filter}`,{kind:"model-switch"});let n=await Os(t,ky),r=c=>String(c||"").toLowerCase(),o=c=>r(c.label).startsWith(r(e.filter)),s=n?.rows.find(c=>c.active)||null;if(n&&!(s&&o(s)))for(let c=0;c<12;c++){let l=await Os(t,ky,{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 Tt(t,["Down"],{kind:"model-switch"}),await Di(250)}if(!n||!s||!o(s)){await Tt(t,["Escape"],{kind:"model-switch"}).catch(()=>{});let c=Array(`/model ${e.filter}`.length).fill("BSpace");throw await Tt(t,c,{settleMs:15,kind:"model-switch"}).catch(()=>{}),new Error(n?`cursor picker has no model matching "${e.filter}"`:"cursor model picker didn't open")}await Tt(t,["Enter"],{kind:"model-switch"}),await Di(800);let a=await MR();return{verified:!!a&&(a.modelId===e.model||a.displayModelId===e.model||r(a.displayName).startsWith(r(e.filter))),model:a?.modelId||null,note:"cursor applies this as the global default for new sessions too"}}async function Ey(t,e,n){return t==="codex"?CR(e,n):t==="cursor"?PR(e,n):OR(e,n)}var Di,ER,_R,xy,IR,RR,Sy,vy,_y=M(()=>{Ht();gs();Di=t=>new Promise(e=>setTimeout(e,t)),ER=Number(process.env.BOSTRAT_MODEL_PICKER_TIMEOUT_MS)||8e3,_R=300,xy=[{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"}],IR=new Set([...xy.map(t=>t.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"]),RR=[{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"}],Sy=new Map([["low","Low"],["medium","Medium"],["high","High"],["xhigh","Extra high"]]),vy=[{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 Li(t){let e=t||{},n=NR(e);return n&&(n.payload={ts:e.at,...n.payload}),n}function NR(t){switch(t.type){case"said":return{type:"turn.user",actor:"user",source:"orchestrator",boxId:t.box,provider:ee(t.agent),payload:{text:t.text,boxRole:t.boxRole,...t.kind?{kind:t.kind}:{},...t.attachments?.length?{attachments:t.attachments}:{}}};case"unsaid":return{type:"turn.retracted",actor:"user",source:"orchestrator",boxId:t.box,provider:ee(t.agent),payload:{saidTs:t.saidTs,text:t.text,boxRole:t.boxRole}};case"orchestration-prompt":return{type:"turn.user",actor:"orchestrator",source:"orchestrator",boxId:t.box,provider:ee(t.agent),payload:{text:t.prompt,kind:t.kind,boxRole:t.boxRole}};case"lead-handoff":return{type:"handoff.done",actor:"orchestrator",source:"orchestrator",boxId:t.to,provider:ee(t.toAgent),payload:{from:t.from,fromAgent:t.fromAgent,to:t.to,toAgent:t.toAgent,reason:t.reason,handoffStartedAt:t.handoffStartedAt,fromSessionId:t.fromSessionId,toSessionId:t.toSessionId,epoch:t.epoch,singleBox:t.singleBox,forced:t.forced,recovered:t.recovered,checkpoint:t.checkpoint}};case"lead-handoff-failed":return{type:"handoff.failed",actor:"orchestrator",source:"orchestrator",boxId:t.box,provider:ee(t.toAgent),payload:{box:t.box,fromAgent:t.fromAgent,toAgent:t.toAgent,reason:t.reason,error:t.error,rolledBack:t.rolledBack,handoffStartedAt:t.handoffStartedAt}};case"subtask-delegated":return{type:"subtask.delegated",actor:"orchestrator",source:"orchestrator",boxId:t.to,provider:ee(t.toAgent),payload:{task:t.task,subtaskId:t.subtaskId,reason:t.reason}};case"subtask-merged":return{type:"subtask.merged",actor:"orchestrator",source:"orchestrator",boxId:t.box||t.from,provider:ee(t.agent),payload:{...po(t)}};case"subtask-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:t.box||t.to,provider:ee(t.agent||t.toAgent),payload:{kind:"subtask-failed",...po(t)}};case"subtask-resumed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:t.box,provider:ee(t.agent),payload:{change:"subtask-resumed",...po(t)}};case"model-change":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:t.box,payload:{change:"model",model:t.to,from:t.from??null,verified:t.verified??null}};case"codex-update":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:t.box,provider:"codex",payload:{change:"cli-update",from:t.from??null,to:t.to??null,status:t.status,...t.error?{error:t.error}:{}}};case"opened":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:t.box,payload:{change:"opened",...po(t)}};case"archived":case"unarchived":case"track-deleted":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:t.type,...po(t)}};case"rehydrated":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:t.box,provider:ee(t.agent),payload:{change:"rehydrated"}};case"retagged":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:"retagged",...po(t)}};case"rehydrate-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:t.box,provider:ee(t.agent),payload:{kind:"rehydrate-failed",reason:t.reason}};default:return null}}function $y(t,e){let n=Li(e);if(!n)return;let r=e?.type==="track-deleted"?{id:t.id}:t;xd(()=>I(r,n))}async function Oy(t){if(!(!t?.id||Iy.has(t.id))){Iy.add(t.id);try{let e=await L(t),n=new Set(e.filter(r=>r.source==="orchestrator").map(r=>`${r.type}|${r.payload?.ts??"?"}`));for(let r of t.events||[]){let o=Li(r);!o||n.has(`${o.type}|${o.payload?.ts??"?"}`)||await I(t,o)}}catch{}}}function po(t){let{type:e,at:n,...r}=t;return r}function Cy(t,e,n){!n?.promptId||kd.get(t.id)===n.promptId||(kd.set(t.id,n.promptId),xd(()=>I(t,{type:"prompt.raised",actor:"agent",source:"pane",boxId:e?.name,provider:ee(n.provider||e?.agent),payload:{promptId:n.promptId,question:n.question||n.title||null,options:(n.options||[]).map(r=>r?.label??r).slice(0,12)}})))}function Sd(t,e,n,r={}){kd.delete(t.id),xd(()=>I(t,{type:"prompt.answered",actor:"user",source:"orchestrator",boxId:e?.name,provider:ee(n?.provider||e?.agent),payload:{promptId:n?.promptId,...r}}))}var ee,ji,xd,Ry,Iy,kd,vd=M(()=>{ct();ee=t=>t||null;ji=Promise.resolve(),xd=t=>(ji=ji.then(t).catch(()=>{}),ji),Ry=()=>ji;Iy=new Set;kd=new Map});function FR(t){return String(t).split(/(?<=[.?!])\s+|\n+/).map(e=>e.trim()).filter(Boolean)}function jy(t){let e=String(t||"").trim();if(!e)return null;let n=e.slice(-600);for(let r of FR(n).reverse()){if(!BR.test(r))continue;let o=r.endsWith("?")&&r.length<=LR&&jR.test(r);if(DR.test(r)||o)return r.length>200?r.slice(0,197)+"\u2026":r}return null}function Ly(t){let e=String(t||""),n=[];UR.test(e)&&n.push("commit"),HR.test(e)&&n.push("rebase"),WR.test(e)&&n.push("push");let r=KR.test(e);!r&&qR.test(e)&&n.push("pr");let o=null;if(r){let s=e.match(/(?:pr|pull\s+request)\s*\(?\s*#(\d+)\)?/i)||e.match(/#(\d+)/);o={number:s?Number(s[1]):null}}return{offered:n.length?n:null,toPr:o}}function mo(t,{branch:e=null,base:n=null,toPr:r=null,repos:o=null,offeredRebase:s=!1}={}){Array.isArray(t)||(t=t==="push"?["commit","push"]:["commit","push","pr"]);let a=new Set(t),i=Array.isArray(o)&&o.length>0,c=i?o.map(p=>`${p.name}/`).join(", "):null,l=e?` on this branch (${e})`:"",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 p=a.has("commit")?"the branch":`this branch${e?` (${e})`:""}`;u.push(i?`rebase ${p} in each changed checkout (${c}) onto its own base branch (fetch origin first), resolving any conflicts so both sides' intent is preserved`:`rebase ${p} 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 p=r&&!a.has("pr")?` (the open PR${r.number?` #${r.number}`:""} picks it up)`:"",m=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${m}${p}`:`push this branch${e?` (${e})`:""} from each changed checkout (${c}) to its remote${p}`):u.push(a.has("commit")||a.has("rebase")?`push it to the remote${m}${p}`:`push this branch${l} to the remote${p}`)}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 f=`Yes \u2014 go ahead: ${u.join(", then ")}.`;return d.length&&(f+=` ${d.join(", and ").replace(/^./,p=>p.toUpperCase())}.`),a.has("pr")&&(f+=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."),f}function Fy(t,{branch:e=null,base:n=null,prNumber:r=null,offeredRebase:o=!1}={}){let s=new Set(Array.isArray(t)?t:["commit","push","pr"]),a=e?` on this branch (${e})`:"",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${e?` (${e})`:""}`} 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}`:""}${e?` and its remote branch (${e})`:" and its remote branch"} exactly as they are \u2014 don't push ${e||"the old branch"} itself.`,l}function Uy(t,e=Date.now()){let n=[],r=null;for(let o of t||[]){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&&e-r.lastActivity<=GR&&n.push({box:r.box,from:r.from,to:e+1e12}),n}function Hy(t,e){let n=new Set;for(let r of e||[]){if(!r.settled)continue;let o=null;for(let s of t||[])s.kind!=="message"||s.role!=="assistant"||s.box!==r.box||s.ts==null||s.ts<r.from||s.ts>r.to+VR||(!o||s.ts>=o.ts)&&(o=s);o&&n.add(o)}return n}function Wy(t){let e=(Array.isArray(t)?t:[]).filter(r=>My[r]).map(r=>My[r]);return`The ship you were given the go-ahead for${e.length?` (${e.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 Py,Ny,By,Dy,BR,DR,jR,LR,Fi,UR,HR,WR,qR,KR,GR,VR,My,ho=M(()=>{Py=/(?<!\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,Ny=/(?<!\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,By=/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,Dy=/(?<!\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,BR=new RegExp(`\\b(?:${Py}|${Ny}|${By}|${Dy})\\b`,"i"),DR=/\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,jR=/^(?:commit|push|open|create|raise|rebase|ready|ok(?:ay)?\s+to|good\s+to)\b/i,LR=90;Fi=["commit","rebase","push","pr"],UR=new RegExp(`\\b(?:${Py})\\b`,"i"),HR=new RegExp(`\\b(?:${Dy})\\b`,"i"),WR=new RegExp(`\\b(?:${Ny})\\b`,"i"),qR=new RegExp(`\\b(?:${By})\\b`,"i"),KR=/\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;GR=3e4;VR=2500;My={commit:"commit",rebase:"rebase",push:"push",pr:"open a PR"}});import zR from"node:fs";import Td from"node:fs/promises";import Vy from"node:path";import JR from"node:os";function Yy(t,e=!1){if(!e&&t-Ky<YR)return;Ky=t;let n=JSON.stringify({windowStart:wo,byCaller:Object.fromEntries(Ve),lastHour:On});Gy=Gy.then(()=>Td.mkdir(zy,{recursive:!0})).then(()=>Td.writeFile(`${Ui}.tmp`,n)).then(()=>Td.rename(`${Ui}.tmp`,Ui)).catch(()=>{})}function Xy(t){t-wo<Jy||(On={start:wo,total:Hi(Ve),byCaller:Object.fromEntries(Ve)},On.total&&console.log(`[github] ${On.total} calls last hour`,On.byCaller),wo=t,Ve=new Map,Yy(t,!0))}function ze(t="other",e=Date.now()){Xy(e),Ve.set(t,(Ve.get(t)||0)+1),Yy(e)}function Zy(t=Date.now()){return Xy(t),{windowStart:wo,total:Hi(Ve),byCaller:Object.fromEntries(Ve),lastHour:On,backoffUntil:yr>t?yr:null}}function Cn(t){return XR.test(String(t?.message||t||""))}function Mn(t,e=Date.now()){return yr<=e&&console.warn(`[github] rate limited \u2014 backing off ${qy/6e4} min:`,String(t?.message||t||"").slice(0,200)),yr=Math.max(yr,e+qy),yr}function Wi(t=Date.now()){return Math.max(0,yr-t)}var zy,Ui,Jy,qy,YR,wo,Ve,On,yr,Ky,Hi,Gy,XR,Cs=M(()=>{zy=process.env.BOSTRAT_STATE_DIR||Vy.join(process.env.HOME||JR.tmpdir(),".bostrat"),Ui=Vy.join(zy,"github-metrics.json"),Jy=60*6e4,qy=5*6e4,YR=6e4,wo=Date.now(),Ve=new Map,On=null,yr=0,Ky=0,Hi=t=>[...t.values()].reduce((e,n)=>e+n,0);try{let t=JSON.parse(zR.readFileSync(Ui,"utf8"));t?.windowStart&&(Date.now()-t.windowStart<Jy?(wo=t.windowStart,Ve=new Map(Object.entries(t.byCaller||{})),On=t.lastHour||null):Hi(new Map(Object.entries(t.byCaller||{})))&&(On={start:t.windowStart,total:Hi(new Map(Object.entries(t.byCaller||{}))),byCaller:t.byCaller||{}}))}catch{}Gy=Promise.resolve();XR=/rate limit|too quickly|abuse detection|HTTP 429/i});import ZR from"node:crypto";import qi from"node:fs/promises";import Qy from"node:path";import QR from"node:os";async function Et(){return Pn||(Ad??=qi.readFile(_d,"utf8").then(t=>({links:JSON.parse(t)?.links??{},existed:!0})).catch(()=>({links:{},existed:!1})).then(async({links:t,existed:e})=>{if(Pn=t,!e&&wt()){let{records:n,source:r}=await $t("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;Pn[V(i.repo,i.number)]=i}Object.keys(Pn).length&&await Id().catch(()=>{})}}return Pn}).finally(()=>Ad=null),Ad)}async function Id(){let t=JSON.stringify({links:Pn},null,2),e=`${_d}.${process.pid}.tmp`;await qi.mkdir(tb,{recursive:!0}),await qi.writeFile(e,t),await qi.rename(e,_d)}async function Pt(t){Ed=Ed.then(Id,Id),await Ed.catch(()=>{});let e=Pn?.[t];e&&Ut("prlinks",{id:eb(t),updatedAt:Date.now(),...e},{trackId:e.trackId??null}).catch(()=>{})}async function ne({repo:t,number:e,trackId:n,url:r=null,headRef:o=null,title:s=null,source:a="matched"}){if(!t||!Number.isInteger(Number(e))||!n)return{link:null,created:!1};let i=await Et(),c=V(t,e);return i[c]?{link:i[c],created:!1}:(i[c]={repo:t,number:Number(e),trackId:n,url:r,headRef:o,title:s,source:a,announced:t$.has(a),firstSeen:Date.now()},await Pt(V(t,e)),{link:i[c],created:!0})}async function Ms(t,e){if(!t||e==null)return null;let n=(await Et())[V(t,e)];return!n||n.announced?null:(n.announced=!0,await Pt(V(t,e)),n)}async function Wt(t,e){return!t||e==null?null:(await Et())[V(t,e)]??null}async function Nn(t,e,n){if(!t||e==null)return null;let r=(await Et())[V(t,e)];return r?(r.state=n,r.resolvedAt=Date.now(),delete r.armedAt,delete r.autoMerge,delete r.archiveOnMerge,delete r.notifyOnMerge,delete r.notifyPending,await Pt(V(t,e)),r):null}async function nb(t,e,{headSha:n=null,trackId:r=null}={}){if(!t||e==null)return null;let o=(await Et())[V(t,e)];return o?(o.ciFix={delegatedAt:Date.now(),headSha:n,trackId:r},await Pt(V(t,e)),o):null}async function rb(t,e,{headSha:n=null,trackId:r=null}={}){if(!t||e==null)return null;let o=(await Et())[V(t,e)];return o?(o.reconcile={delegatedAt:Date.now(),headSha:n,trackId:r},await Pt(V(t,e)),o):null}async function Ki(t,e,{headSha:n=null}={}){if(!t||e==null)return null;let r=(await Et())[V(t,e)];return!r||!r.ciFix?null:(r.ciFixAwait={since:Date.now(),trackId:r.ciFix.trackId??null,headSha:n},delete r.ciFix,await Pt(V(t,e)),r)}async function Gi(t,e){if(!t||e==null)return null;let n=(await Et())[V(t,e)];return!n||!n.ciFixAwait?null:(delete n.ciFixAwait,await Pt(V(t,e)),n)}async function Vi(t,e,{headSha:n=null}={}){if(!t||e==null)return null;let r=(await Et())[V(t,e)];return!r||!r.reconcile?null:(r.reconcileAwait={since:Date.now(),trackId:r.reconcile.trackId??null,headSha:n},delete r.reconcile,await Pt(V(t,e)),r)}async function zi(t,e){if(!t||e==null)return null;let n=(await Et())[V(t,e)];return!n||!n.reconcileAwait?null:(delete n.reconcileAwait,await Pt(V(t,e)),n)}async function ob(t,e,{at:n=Date.now()}={}){if(!t||e==null)return null;let r=(await Et())[V(t,e)];return r?(r.baseFoldAt=n,await Pt(V(t,e)),r):null}async function sb(t,e){if(!t||e==null)return null;let n=(await Et())[V(t,e)];return!n||!n.baseFoldAt?null:(delete n.baseFoldAt,await Pt(V(t,e)),n)}async function ab(t,e,n){if(!t||e==null||!n)return null;let r=(await Et())[V(t,e)];return r?(r.lastHeadSha=n,await Pt(V(t,e)),r):null}async function Ps(t,e,{merge:n=null}={}){if(!t||e==null)return null;let r=(await Et())[V(t,e)];return r?(r.armedAt=Date.now(),n&&(r.autoMerge={method:n.method||"merge",armedAt:r.armedAt}),await Pt(V(t,e)),r):null}async function br(t,e,n=!0){if(!t||e==null)return null;let r=(await Et())[V(t,e)];return r?(n?r.archiveOnMerge=!0:delete r.archiveOnMerge,await Pt(V(t,e)),r):null}async function Ns(t,e,n=!0){if(!t||e==null)return null;let r=(await Et())[V(t,e)];return r?(n?r.notifyOnMerge=!0:delete r.notifyOnMerge,await Pt(V(t,e)),r):null}async function ib(t,e,n){if(!t||e==null)return null;let r=(await Et())[V(t,e)];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 Pt(V(t,e)),r}async function Bs(t,e){if(!t||e==null)return null;let n=(await Et())[V(t,e)];return!n||!n.armedAt&&!n.autoMerge?null:(delete n.armedAt,delete n.autoMerge,delete n.archiveOnMerge,delete n.notifyOnMerge,delete n.notifyPending,await Pt(V(t,e)),n)}async function cb(){return Object.values(await Et()).filter(t=>!e$.has(t.state))}async function kr(){return Object.values(await Et()).sort((t,e)=>e.firstSeen-t.firstSeen)}async function lb(){if(!wt())return{pushed:0,source:"unconfigured"};let{records:t,source:e}=await $t("prlinks");if(e!=="plane"||t.length)return{pushed:0,source:e};let n=await Et(),r=0;for(let[o,s]of Object.entries(n))await Ut("prlinks",{id:eb(o),updatedAt:Date.now(),...s},{trackId:s.trackId??null}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}var tb,_d,V,eb,Pn,Ad,Ed,t$,e$,Bn=M(()=>{bn();tb=process.env.BOSTRAT_STATE_DIR||Qy.join(process.env.HOME||QR.tmpdir(),".bostrat"),_d=Qy.join(tb,"pr-links.json"),V=(t,e)=>`${t}#${Number(e)}`,eb=t=>{let e=t.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^[^A-Za-z0-9]+/,"").slice(0,55),n=ZR.createHash("sha256").update(t).digest("hex").slice(0,8);return`${e||"pr"}-${n}`},Pn=null,Ad=null,Ed=Promise.resolve();t$=new Set(["api","observed","reconciled"]);e$=new Set(["merged","closed","lost"])});function Ji(t,e,n){let{state:r,reason:o}=ou(e,n);if(r!=="unknown"){if(t){let a=Date.now();for(let[i,c]of Ds)a-c.at>=ub()&&Ds.delete(i);Ds.set(t,{busy:r==="busy",at:a})}return r==="busy"}if(o!=="narrow"||!t)return!1;let s=Ds.get(t);return s?Date.now()-s.at>=ub()?(Ds.delete(t),!1):s.busy:!1}async function Rd(t,e){let n={working:!1,prompted:!1};if(!t)return n;let r=await yt(t,{lines:Ct}).catch(()=>"");if(!Ji(t,e,r))return Wh(e,r)?{working:!0,prompted:!1}:n;if(ao(e,r)){let o=await Sn(t).catch(()=>r),s=wr({name:t,agent:e},o);if(s)return!$i({name:t,agent:e},s,o)||Xg(t)?{working:!1,prompted:!0}:{working:!1,prompted:!1}}return{working:!0,prompted:!1}}async function Yi(t,e){return(await Rd(t,e)).working}var ub,Ds,Xi=M(()=>{Ht();hi();od();ad();ub=()=>Number(process.env.BOSTRAT_NARROW_CARRY_MS)||9e4,Ds=new Map});import{execFile as n$}from"node:child_process";import{promisify as r$}from"node:util";async function $d(t,e,{midTurn:n=Yi,pollMs:r=o$,capMs:o=s$}={}){let s=Date.now()+o;for(;await n(t,e).catch(()=>!1);){if(Date.now()>=s)return!1;await new Promise(a=>setTimeout(a,r))}return!0}function m$(t,e){let n=String(t||"").match(p$);return!!n&&n[1]!==e}function Od(t,e){return t.slice(e).replace(/^[\s;&|)]+/,"").replace(/"[^"]*"|'[^']*'/g,'""').split(/[;&|]/)[0]}function mb(t){let e=String(t||""),n=e.match(l$);if(!n)return null;let r=Od(e,n.index);return d$.test(r)?null:{repo:r.match(pb)?.[1]??null,head:r.match(f$)?.[1]??null}}function hb(t){let e=String(t||""),n=e.match(u$);if(!n)return null;let r=Od(e,n.index),o=Od(e,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("-")){h$.has(c)&&i++;continue}s=c.replace(/^["']+|["']+$/g,"")||null;break}return{repo:r.match(pb)?.[1]??null,selector:s,auto:/\s--auto\b/.test(r)}}async function g$(t,e,{exclude:n=()=>!1}={}){let r=async i=>{ze("observer");let{stdout:c}=await db("gh",["pr","list","--repo",t,"--author","@me","--state","all","--limit","10","--json",w$],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...i}}).catch(l=>{throw Cn(l)&&Mn(l),l});return JSON.parse(c||"[]")},o=i=>(i||[]).filter(c=>Date.parse(c.createdAt)>=e-a$&&!n(c)),s=await Ae({slug:t}),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 y$(t,e){if(e)return[e];let n=[];for(let r of wb(t)){let o=await st(r).catch(()=>null);o&&!n.includes(o)&&n.push(o)}for(let r of await Ue().catch(()=>[])){let o=await st(r.path).catch(()=>null);o&&!n.includes(o)&&n.push(o)}return n}function wb(t){let e=t.workspace;return e?.kind==="multi"?(e.repos??[]).map(n=>n?.base).filter(Boolean):[e?.base||t.cwd].filter(Boolean)}async function b$(t,e,n){let r=t.workspace?.branch,o=e?.head??null,s=c=>r&&c===r||o&&c===o,a=c=>o!=null&&!s(c.headRefName)||m$(c.headRefName,t.id),i=[];for(let c of await y$(t,e?.repo??null)){let l;try{l=await g$(c,n,{exclude:a})}catch{continue}for(let u of l){let d=await Wt(c,u.number);if(s(u.headRefName)){if(d&&d.trackId===t.id&&d.announced)return{settled:!0};if(d&&d.trackId!==t.id)continue;return{slug:c,pr:u}}d&&(d.trackId!==t.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 gb(t,e,{delays:n=fb,turnEnd:r}={}){let o=mb(e.command);if(!o)return null;let s=!!hb(e.command),a=`${t.id}|${e.id??e.ts??e.command}`;if(Dn.has(a))return null;Dn.add(a);let i=e.ts??Date.now(),c=(async()=>{try{for(let l of n){await new Promise(w=>setTimeout(w,l));let u=await b$(t,o,i).catch(()=>null);if(u?.settled)return null;if(!u)continue;let{slug:d,pr:f}=u,{link:p,created:m}=await ne({repo:d,number:f.number,trackId:t.id,url:f.url,headRef:f.headRefName,title:f.title,source:"observed"});return!m&&!(p?.trackId===t.id&&await Ms(d,f.number))?null:(await $d(e.box,e.agent,r),await I({id:t.id,cwd:t.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:e.box??null,provider:e.agent??null,payload:{ts:Date.now(),change:"opened",number:f.number,url:f.url,title:f.title,branch:f.headRefName,repo:d,...s?{selfMerge:!0}:{}}}),f)}return null}finally{Dn.delete(a)}})();return c.catch(()=>Dn.delete(a)),c}function yb(t,e,{delays:n=fb,turnEnd:r,openedWait:o}={}){let s=hb(e.command);if(!s)return null;let a=`merge|${t.id}|${e.id??e.ts??e.command}`;if(Dn.has(a))return null;Dn.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 m=wb(t);if(m.length>1&&/^\d+$/.test(String(s.selector??"")))return null;for(let w of m){let y=await st(w).catch(()=>null);y&&!d.includes(y)&&d.push(y)}}if(l||=t.workspace?.branch,!d.length||!l)return null;c=d[0];let f=async(m,w)=>{let y=await Wt(c,m.number);return y&&y.trackId!==t.id?null:(y||await ne({repo:c,number:m.number,trackId:t.id,url:m.url,headRef:m.headRefName,title:m.title,source:"merge-observed"}),await Ps(c,m.number),w&&((await L(t).catch(()=>[])).some($=>$.type==="pr.state.changed"&&($.payload?.change==="auto-armed"||$.payload?.change==="merged")&&$.payload?.number===m.number)||(await $d(e.box,e.agent,r),await I({id:t.id,cwd:t.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:e.box??null,provider:e.agent??null,payload:{ts:Date.now(),change:"auto-armed",number:m.number,url:m.url,title:m.title,branch:m.headRefName,repo:c}}))),m)},p=null;for(let m of n){await new Promise(C=>setTimeout(C,m));let w=[];for(let C of d)try{ze("observer");let{stdout:D}=await db("gh",["pr","view",String(l),"--repo",C,"--json",k$],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...await Ae({slug:C})}}),A=JSON.parse(D||"null");A?.number&&w.push({slug:C,pr:A})}catch(D){Cn(D)&&Mn(D)}let y=w.find(C=>C.pr.state==="MERGED")??(w.length===1?w[0]:null);if(!y)continue;c=y.slug;let k=y.pr;if(!k?.number)continue;if(k.state==="CLOSED")return null;if(k.state!=="MERGED"){if(p=k,s.auto)return f(k,!0);continue}let S=await Wt(c,k.number);if(S&&S.trackId!==t.id)return null;S||await ne({repo:c,number:k.number,trackId:t.id,url:k.url,headRef:k.headRefName,title:k.title,source:"merge-observed"}),await $d(e.box,e.agent,r);let $=await L(t).catch(()=>[]);if($.some(C=>C.type==="pr.state.changed"&&C.payload?.change==="merged"&&C.payload?.number===k.number))return null;let R=C=>C.some(D=>D.type==="pr.state.changed"&&D.payload?.change==="opened"&&D.payload?.number===k.number),J=0;if(!R($)){if(mb(e.command)&&await Ms(c,k.number)){let C=Date.now();J=C+1,await I({id:t.id,cwd:t.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:e.box??null,provider:e.agent??null,payload:{ts:C,change:"opened",number:k.number,url:k.url,title:k.title,branch:k.headRefName,repo:c,selfMerge:!0}})}else if((await Wt(c,k.number))?.announced){let C=o?.capMs??i$,D=o?.pollMs??c$,A=Date.now()+C;for(;Date.now()<A&&(await new Promise(N=>setTimeout(N,D)),!R(await L(t).catch(()=>[]))););}}return await I({id:t.id,cwd:t.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:e.box??null,provider:e.agent??null,payload:{ts:Math.max(Date.now(),J),change:"merged",number:k.number,url:k.url,title:k.title,branch:k.headRefName,repo:c}}),await Ye(c,k.number).catch(()=>{}),await Je(c,k.number).catch(()=>{}),await Nn(c,k.number,"merged"),k}return p?f(p,!1):null}finally{Dn.delete(a)}})();return i.catch(()=>Dn.delete(a)),i}var db,fb,o$,s$,a$,i$,c$,l$,u$,d$,pb,f$,p$,h$,w$,Dn,k$,bb=M(()=>{ct();Qn();Qt();Cs();Bn();xr();Xi();db=r$(n$),fb=[4e3,15e3,45e3],o$=2500,s$=5*6e4;a$=15e3,i$=9e4,c$=2e3,l$=/(?:^|[;&|]\s*|\)\s*)gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+create\b/,u$=/(?:^|[;&|]\s*|\)\s*)gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+merge\b/,d$=/\s--web\b/,pb=/(?:--repo|-R)[\s=]+([\w.-]+\/[\w.-]+)/,f$=/(?:--head|-H)[\s=]+([^\s"'`;&|]+)/,p$=/^track\/.+-([0-9a-f]{8})$/;h$=new Set(["--subject","-t","--body","-b","--body-file","-F","--match-head-commit","--author-email","-A","--repo","-R"]);w$="number,url,title,headRefName,createdAt";Dn=new Set;k$="number,url,title,headRefName,state"});import x$ from"node:fs/promises";import Md from"node:path";import S$ from"node:os";function Cd(t,e){let n=new RegExp(`\\b${e}="([^"]*)"`).exec(t);return n?n[1]:null}function Zi(t){let e=v$.exec(String(t||""));if(!e)return null;let[,n,r]=e,o=Cd(n,"from"),s=o?o.replace(/^uds:/,""):null,a=kb(s);return{socket:s,pid:a,name:Cd(n,"from-name"),mode:Cd(n,"from-mode"),text:r.trim()}}function kb(t){let e=/(\d+)\.sock$/.exec(String(t||""));return e?Number(e[1]):null}function T$(){return process.env.CLAUDE_CONFIG_DIR?Md.join(process.env.CLAUDE_CONFIG_DIR,"sessions"):Md.join(S$.homedir(),".claude","sessions")}async function A$(t){let e=kb(t);if(!e)return null;try{let n=await x$.readFile(Md.join(T$(),`${e}.json`),"utf8"),r=JSON.parse(n);return{pid:e,sessionId:r.sessionId??null,cwd:r.cwd??null,name:r.name??null,tmux:r.tmux??null}}catch{return null}}async function xb(t,e){let n=await A$(t?.socket),r=n?.cwd??null,o=null;if((n?.sessionId||r)&&typeof e=="function")try{o=await e(n?.sessionId??null,r)??null}catch{o=null}return{socket:t?.socket??null,pid:n?.pid??t?.pid??null,sessionId:n?.sessionId??null,cwd:r,tmux:n?.tmux??null,name:n?.name??t?.name??null,mode:t?.mode??null,trackId:o?.track?.id??null,trackName:o?.track?.name??null,boxId:o?.box?.name??null}}var v$,Pd=M(()=>{v$=/<cross-session-message\b([^>]*)>([\s\S]*?)<\/cross-session-message>/});import{randomUUID as E$}from"node:crypto";function js(t){return t.sourceId?`${t.role}|id:${t.sourceId}`:`${t.role}|${t.ts??"?"}|${String(t.text||"").slice(0,40)}`}function Sb(t){return t.id?`cmd|${t.box}|id:${t.id}`:`cmd|${t.box}|${t.ts??"?"}|${String(t.command||"").slice(0,40)}`}function vb(t){return`job|${t.box}|id:${t.id}`}async function Bd(t){return Nd.has(t.id)?Nd.get(t.id):(Qi.has(t.id)||Qi.set(t.id,L(t).then(e=>{let n={keys:new Set,cmdN:0};for(let r of e)if((r.type==="turn.user"||r.type==="turn.agent")&&r.payload?.text!=null){let o=r.type==="turn.user"?"user":"assistant";r.payload.sourceId&&n.keys.add(js({role:o,sourceId:r.payload.sourceId})),n.keys.add(js({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(js({role:"user",sourceId:r.payload.sourceId})),n.keys.add(js({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(Sb({id:o.id,box:r.boxId,ts:o.ts,command:o.command})),Number(o.n)>n.cmdN&&(n.cmdN=Number(o.n))}else r.type==="job.started"&&r.payload?.id&&n.keys.add(vb({id:r.payload.id,box:r.boxId}));return Nd.set(t.id,n),n}).finally(()=>Qi.delete(t.id))),Qi.get(t.id))}async function Tb(t,e){try{let n=(await Bd(t)).keys;for(let r of e||[]){if(!r||r.ts==null||!String(r.text||"").trim()&&!r.images?.length)continue;let o=js(r);if(n.has(o))continue;n.add(o);let s=r.role==="user"?Zi(r.text):null;if(s){await I(t,{type:"peer.message",actor:"peer",source:"transcript",boxId:r.box,provider:r.agent||null,payload:{text:s.text,ts:r.ts,keyText:String(r.text||"").slice(0,40),from:await xb(s,Ls),boxRole:r.boxRole,sourceId:r.sourceId||void 0}});continue}if(await I(t,{type:r.role==="user"?"turn.user":"turn.agent",actor:r.role==="user"?"user":"agent",source:"transcript",boxId:r.box,provider:r.agent||null,payload:{text:r.text,ts:r.ts,model:r.model||null,tools:r.tools||void 0,boxRole:r.boxRole,sourceId:r.sourceId||void 0,note:r.note||void 0,images:r.images?.length?r.images:void 0}}),r.role==="assistant"&&r.box===t.leadBox&&t.workspace?.branch){let a=jy(r.text);if(a){let{offered:i,toPr:c}=Ly(a),l;if(t.workspace?.kind==="multi"){let u=await go(t).catch(()=>[]);l=u.length?u.map(d=>({name:d.name,slug:d.repo??null})):void 0}await I(t,{type:"pr.offered",actor:"agent",source:"transcript",boxId:r.box,provider:r.agent||null,payload:{offerId:E$(),ts:r.ts,excerpt:a,branch:t.workspace.branch,base:t.workspace.baseRef?.replace(/^origin\//,"")||null,boxRole:r.boxRole,offered:i||void 0,toPr:c||void 0,repos:l}})}}}}catch{}}async function Ab(t,e){try{let n=await Bd(t),r=[...e||[]].filter(o=>o&&String(o.command||"").trim()).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=Sb(o);n.keys.has(s)||(n.keys.add(s),n.cmdN+=1,await I(t,{type:"tool.called",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{id:o.id??null,tool:o.tool||null,command:o.command,description:o.description||"",summary:o.summary||o.command,ts:o.ts??null,boxRole:o.boxRole,n:n.cmdN}}),gb(t,o),yb(t,o))}}catch{}}async function Eb(t,e){try{let n=await Bd(t),r=[...e||[]].filter(o=>o&&o.id).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=vb(o);n.keys.has(s)||(n.keys.add(s),await I(t,{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 Nd,Qi,_b=M(()=>{ct();ho();bb();Pd();xr();Nd=new Map,Qi=new Map});function _$(t){let e=[],n=null;for(let r of String(t||"").split(`
135
- `)){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;e.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 e}async function I$(t,e){let n=`${t.id}:${e.name}`;if(!Dd.has(n)){let r=await L(t),o=new Set;for(let s of r)s.type==="cost.recorded"&&s.boxId===e.name&&s.payload?.codexTs!=null&&o.add(s.payload.codexTs);Dd.set(n,o)}return Dd.get(n)}async function Ib(t,e){try{if(e?.agent!=="codex"||!e.cwd)return;let n=await cr(e.cwd,e.pinned?e.sessionId:null);if(!n)return;let r=await I$(t,e),o=_$(await Jt(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||e.model||"gpt-5.5";await I(t,{type:"cost.recorded",actor:"agent",source:"transcript",boxId:e.name,provider:"codex",payload:{usd:In(c,i),model:c,tokens:i,reasoningOutput:a.last.reasoningOutput||void 0,codexTs:a.ts,ts:a.ts}}),a===s&&a.contextWindow&&await I(t,{type:"context.usage",actor:"agent",source:"transcript",boxId:e.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 Dd,Rb=M(()=>{ct();Qr();we();Es();Dd=new Map});import tc from"node:fs";import Ld from"node:path";import R$ from"node:os";async function C$({sinceMs:t,cookie:e,fetchImpl:n=fetch}){let r=[];for(let o=1;o<=20;o++){let s=await n(O$,{method:"POST",headers:{"content-type":"application/json",origin:"https://cursor.com",cookie:`WorkosCursorSessionToken=${e}`},body:JSON.stringify({teamId:0,startDate:String(t),endDate:String(Date.now()),page:o,pageSize:$b})});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<$b)break}return r}function M$(t){if(!t)return null;let e=Number(t.timestamp)||null,n=t.tokenUsage||null,r=n?{input:n.inputTokens||0,output:n.outputTokens||0,cacheRead:n.cacheReadTokens||0,cacheWrite:n.cacheWriteTokens||0}:null,o=t.conversationId||null;return{id:[o||"?",e??"?",r?`${r.input}.${r.output}.${r.cacheRead}.${r.cacheWrite}`:"?"].join(":"),conversationId:o,ts:e,model:t.model||t.modelIntent||null,kind:t.kindLabel||t.kind||null,isHeadless:t.isHeadless===!0,tokens:r,vendorCents:n?.totalCents??null,chargedCents:t.chargedCents??null}}function Cb(){try{return JSON.parse(tc.readFileSync(ec(),"utf8"))}catch{return{sinceMs:0,seen:[]}}}function N$(t){try{tc.mkdirSync(Ld.dirname(ec()),{recursive:!0});let e=ec()+".tmp";tc.writeFileSync(e,JSON.stringify(t)),tc.renameSync(e,ec())}catch{}}async function D$({fetchImpl:t,now:e=Date.now()}={}){if(jn.rows&&e-jn.at<P$)return jn.rows;let n=process.env.BOSTRAT_CURSOR_USAGE_COOKIE;if(!n)return null;let r=Cb(),o=Math.max(r.sinceMs-6e4,e-24*36e5);try{let s=await C$({sinceMs:o,cookie:n,fetchImpl:t});jn={at:e,rows:s.map(M$).filter(Boolean),error:null}}catch(s){jn={at:e,rows:null,error:String(s?.message||s)}}return jn.rows}async function j$(t,e){let n=`${t.id}:${e.name}`;if(!jd.has(n)){let r=await L(t),o=new Set;for(let s of r)s.type==="cost.recorded"&&s.boxId===e.name&&s.payload?.cursorEventId&&o.add(s.payload.cursorEventId);jd.set(n,o)}return jd.get(n)}async function Mb(t,e,{fetchImpl:n}={}){try{if(e?.agent!=="cursor"||!e.cwd||!Ob())return;let r=await D$({fetchImpl:n});if(!r||!r.length)return;let o=await Rg(e.cwd,e.pinned?e.sessionId:null);if(!o?.chatId)return;let s=await j$(t,e),a=Cb(),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(`${t.id}:${e.name}:${l.id}`))continue;s.add(l.id),i.add(`${t.id}:${e.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,f=l.vendorCents!=null?l.vendorCents/100:0;!f&&d&&(f=In(u,d)),!f&&l.chargedCents!=null&&(f=l.chargedCents/100),await I(t,{type:"cost.recorded",actor:"agent",source:"vendor",boxId:e.name,provider:"cursor",payload:{usd:f,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}})}N$({sinceMs:c,seen:[...i].slice(-B$)})}catch{}}var $$,Ob,O$,$b,P$,jn,ec,B$,Fd,jd,Ud=M(()=>{ct();qu();Es();$$=process.env.BOSTRAT_STATE_DIR||Ld.join(process.env.HOME||R$.tmpdir(),".bostrat"),Ob=(t=process.env)=>!!t.BOSTRAT_CURSOR_USAGE_COOKIE,O$="https://cursor.com/api/dashboard/get-filtered-usage-events",$b=100;P$=5*6e4,jn={at:0,rows:null,error:null},ec=()=>Ld.join($$,"cursor-usage.json");B$=5e3;Fd=()=>({enabled:Ob(),lastPollAt:jn.at||null,error:jn.error}),jd=new Map});import Hs from"node:fs/promises";import Xt from"node:path";import L$ from"node:os";import F$ from"node:net";import{randomUUID as U$}from"node:crypto";import{execFile as H$}from"node:child_process";import{promisify as W$}from"node:util";function Y$(t){for(let e of zd(t))if(!Lb.test(e))return e;return null}function Fb(t){let e=zd(t),n=e.indexOf("--");return n===-1?e:e.slice(0,n)}function X$(t,e){let n=Fb(e);for(let r=0;r<n.length;r++){let o=/^--prefix=(.+)$/.exec(n[r]);if(o)return Xt.resolve(t,o[1]);if(n[r]==="--prefix"&&n[r+1])return Xt.resolve(t,n[r+1])}return t}function Q$(t){let e=!1,n=!1;for(let r of zd(t)){if(!e){if(Lb.test(r))continue;e=!0;continue}if(r.startsWith("-")){let o=r.indexOf("="),s=o===-1?null:r.slice(o+1);if(s&&Hd(s))return`serves the filesystem root ("${s}")`;n=o===-1;continue}if(n){if(n=!1,Hd(r))return`serves the filesystem root ("${r}")`;continue}if(Hd(r))return`serves the filesystem root ("${r}")`;if(Z$(r))return`serves a path that escapes the workspace ("${r}")`}return null}async function eO(t,e){if(Xt.resolve(t)===Xt.resolve(e))return!0;let[n,r]=await Promise.all([nc(t),nc(e)]);return n===r}async function nO(t){let n=(await Hs.readdir(t,{withFileTypes:!0}).catch(()=>[])).filter(o=>o.isDirectory()&&!o.name.startsWith(".")&&o.name!=="node_modules");return(await Promise.all(n.map(async o=>await Ub(Xt.join(t,o.name,Kd))?`./${o.name}`:null))).filter(Boolean)}async function rO(t,e){let[n,r]=await Promise.all([nc(t),nc(e)]),o=Xt.relative(n,r);if(o&&(o.startsWith("..")||Xt.isAbsolute(o)))throw Fs(`serve directory escapes the Track workspace: ${e}`)}async function oO(t,e){let n=Q$(e);if(n)throw Fs(`refusing this view: the command ${n} \u2014 serve a build dir, not the filesystem root`);if(!await tO(t))throw Fs(`serve directory does not exist: ${t}`);let r=Y$(e);if(!r)return;if(!r.includes("/")&&!await hh(r,{loginShell:!0,failOpen:!0}))throw Fs(`\`${r}\` is not on the box's PATH \u2014 install it in the box first`);if(V$.test(e)||z$.has(r)||!G$.has(r)||!Fb(e).includes("run")||J$.test(e))return;let o=X$(t,e);if(await Ub(Xt.join(o,Kd)))return;let s=await nO(o),a=s.length?` \u2014 found one in ${s.join(", ")}; run bostrat-view from there`:"";throw Fs(`no ${Kd} in ${o}${a}`)}async function Qe(){return $e||(Wd||=(async()=>{try{$e=JSON.parse(await Hs.readFile(jb,"utf8"))}catch{$e={views:[],adoptWatermarks:{}}}finally{Wd=null}return $e.views||=[],$e.adoptWatermarks||={},$e})(),Wd)}async function Ce(){await zt(jb,$e)}function Ze(t,e,n={}){return I({id:t.trackId,cwd:t.cwd},{type:"view.state.changed",actor:"orchestrator",source:"orchestrator",boxId:t.box||null,payload:{ts:Date.now(),change:e,viewId:t.id,name:t.name,slug:t.slug,port:t.port,cmd:t.cmd||null,...n}}).catch(()=>{})}function Yd(t){return Us.get(t)||null}function Wb(t,{name:e,box:n}={}){let r=Us.get(t);if(r&&!r.finishedAt)throw new Error("a view is already being spun up for this Track");let o={trackId:t,name:e||"preview",box:n||null,step:"spinning-up",startedAt:Date.now(),finishedAt:null,viewId:null,error:null};return Us.set(t,o),o}function Gd(t,e){let n=Us.get(t);n&&!n.finishedAt&&!n.viewId&&(n.viewId=e,n.step="booting")}function rc(t,{error:e=null}={}){let n=Us.get(t);return!n||n.finishedAt?null:(n.finishedAt=Date.now(),e&&(n.error=e),n)}function qb(t){let e=[];for(let n of t?.events||[])n.type!=="view-spinup"||!n.box||!n.startedAt||!n.endedAt||e.push({box:n.box,from:n.startedAt,to:n.endedAt});return e}function Vd(t){return String(t||"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40).replace(/-+$/g,"")||"view"}function sO(t,e){let n=Vd(e),r=new Set(t.views.map(o=>o.slug));if(!r.has(n)&&!Bb.has(n))return n;for(let o=2;;o++){let s=`${n}-${o}`;if(!r.has(s)&&!Bb.has(s))return s}}function Ws(t,{timeoutMs:e=1200}={}){return new Promise(n=>{let r=F$.connect({port:t,host:"127.0.0.1"}),o=s=>{r.destroy(),n(s)};r.setTimeout(e,()=>o(!1)),r.once("connect",()=>o(!0)),r.once("error",()=>o(!1))})}async function Xd(t){if(process.platform!=="darwin"){await Oe("fuser",["-k",`${t}/tcp`]).catch(()=>{});return}let e="";try{({stdout:e}=await Oe("lsof",["-t","-sTCP:LISTEN","-i",`tcp:${t}`]))}catch{return}for(let n of e.split(/\s+/).filter(Boolean)){let r=Number(n);if(!(!r||r===process.pid))try{process.kill(r,"SIGKILL")}catch{}}}function Kb(t=process.env){return new Set([Number(t.PORT)||3362,Number(t.BOSTRAT_TLS_PORT)||3443])}async function aO(t,e){let n=new Set(t.views.map(o=>o.port)),r=Kb();if(e){let o=Number(e);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=Pb;o<=Nb;o++)if(!(n.has(o)||r.has(o))&&!await Ws(o,{timeoutMs:250}))return o;throw new Error(`no free view port in ${Pb}-${Nb}`)}async function iO(t){try{let{stdout:e}=await Oe(B,j("list-sessions","-F","#{session_name}"));return e.split(`
136
- `).some(n=>n.trim()===yo(t))}catch{return!1}}async function qs(t){try{await Oe(B,j("kill-session","-t",yo(t)))}catch{}}async function Zd(t){if(!await ds())throw new Error("host tmux server not running and auto-start failed \u2014 cannot spawn a view server");let e=yo(t.slug),n=t.serveCwd??t.cwd,r=Xt.dirname(process.execPath);await Oe(B,j("new-session","-d","-s",e,"-c",n)),await Oe(B,j("send-keys","-t",e,"-l",`export PORT=${t.port} PATH="${r}:$PATH"`)),await Oe(B,j("send-keys","-t",e,"Enter")),await Oe(B,j("send-keys","-t",e,"-l",t.cmd)),await Oe(B,j("send-keys","-t",e,"Enter"))}async function Db(t,e=12){try{let{stdout:n}=await Oe(B,j("capture-pane","-t",yo(t),"-p"));return String(n||"").trimEnd().split(`
106
+ `});function dI(t){return{id:t.id,kind:"prompt",groupId:t.groupId,provider:t.provider,box:t.box,agent:t.provider,questionTotal:t.questions.length,answeredVia:"chat",questions:t.questions.map((e,n)=>({index:n,header:e.header||"",question:e.question,multiSelect:!!e.multiSelect,chosen:[]})),ts:t.ts}}function pI(t,e,n){let r=Qw(n),o=t.has(r)?r:null;if(!o&&n.number!=null)for(let[i,c]of t){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?t.get(o):t.get(s);if(o&&o!==s){t.delete(o);let i=e.get(o);if(e.delete(o),i?.length){let c=e.get(s)??[];e.set(s,c.concat(i))}}return t.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 hr(t){let e=[],n=new Set,r=new Set,o=new Map,s=new Map,a=new Set,i=new Map,c=new Set,l=new Map,u=/^Agent "([\s\S]+)" finished$/,f=new Map;for(let g of t||[]){if(g.type!=="tool.called"||g.source!=="transcript")continue;let m=String(g.payload?.command||"");if(/\bbostrat-mock\s+(?:add|update)\b/.test(m))for(let v of m.matchAll(/[\w./~-]+\.(?:png|jpe?g|gif|webp|bmp|svg)\b/gi)){let $=v[0].split("/").pop().toLowerCase();f.has($)||f.set($,[]),f.get($).push(g.payload?.ts??g.ts)}}let d=3*6e4,p=20*6e4,h=(g,m)=>!!(g?.name&&f.get(String(g.name).toLowerCase()))?.some($=>$>=m-d&&$<=m+p);for(let g of t||[])if(g.type==="turn.retracted"){r.add(`${g.boxId}|${g.payload?.saidTs}`);let m=Ot(g.payload?.text);m&&(o.has(g.boxId)||o.set(g.boxId,[]),o.get(g.boxId).push(m))}else if(g.type==="turn.user"&&g.source==="orchestrator"){let m=Ot(g.payload?.text);m&&(s.has(g.boxId)||s.set(g.boxId,new Set),s.get(g.boxId).add(m))}else if(g.type==="job.started"&&g.payload?.id)a.add(g.payload.id),(g.payload.kind||"agent")==="agent"&&g.payload.name&&c.add(g.payload.name);else if(g.type==="turn.user"&&g.payload?.note?.kind==="task"){let m=g.payload.note,v={status:m.status||null,summary:m.summary||null,resultHead:m.resultHead??null,ts:ot(g)};m.toolUseId&&i.set(m.toolUseId,v);let $=String(m.summary||"").match(u);$&&l.set($[1],v)}let w=new Map,y=new Map,k=null,x=new Map,E=new Map,O=new Map,z=new Map,C=new Map,N=new Map,T=new Map,D=new Map,j=new Map,st=new Map,rt=new Map,A=new Map,B=new Map,X=()=>{for(let g of B.values())g.questions.length&&e.push(g);B.clear()},yt=null,dt=6e4,bt=new Map,kt=(g,m)=>{let v=o.get(g);if(!v?.length)return!1;let $=Ot(m),it=s.get(g);return v.some(ct=>{if(!$.startsWith(ct))return!1;let mt=Ot($.slice(ct.length));return!!mt&&!!it?.has(mt)})};for(let g of t||[]){let m=g.payload||{};switch(g.type){case"turn.user":{if(g.source==="hook"||!String(m.text||"").trim()&&!m.images?.length&&!m.attachments?.length)break;{let v=m.note||Pi(m.text);if(v){if(v.kind==="task"){if(v.toolUseId&&a.has(v.toolUseId))break;let $=String(v.summary||"").match(u);if(!v.toolUseId&&$&&c.has($[1]))break}if(v.kind==="command"&&Gw(v.command))break;if(v.kind==="resume-summary"){e.push({id:g.id,kind:"resume-summary",title:v.title||"Context resumed from summary",bullets:v.bullets||[],sections:v.sections||[],rawChars:v.rawChars??null,ts:ot(g),box:g.boxId,agent:g.provider});break}v.kind!=="suppress"&&e.push({id:g.id,kind:"event",type:zw(v),name:v.name??null,command:v.command??null,summary:v.summary??null,status:v.status??null,ts:ot(g),box:g.boxId,agent:g.provider});break}}if(r.has(`${g.boxId}|${ot(g)}`)||g.source==="transcript"&&kt(g.boxId,m.text))break;if(m.kind==="merge-notify"||m.kind==="ship-notify"){e.push({id:g.id,kind:"event",type:m.kind==="ship-notify"?"ship-notified":"merge-notified",text:m.text,ts:ot(g),box:g.boxId,agent:g.provider});break}if(m.kind==="mock-picked"||m.kind==="ci-fix"||m.kind==="reconcile"||m.kind==="pr-go"||m.kind==="push-go"||m.kind==="spin-up-view"||m.kind==="prompt-answer"){m.kind==="prompt-answer"&&(yt=null);break}for(let v of x.values())v.status="stale";x.clear();for(let v of O.values())v.status="stale";O.clear(),yt&&yt.box===g.boxId&&(e.push(dI(yt)),yt=null),e.push({id:g.id,kind:"message",role:"user",text:m.text,ts:ot(g),box:g.boxId,agent:g.provider,boxRole:m.boxRole,...g.actor==="orchestrator"?{orchestration:m.kind||!0}:{},...m.sourceId?{sourceId:m.sourceId}:{},...m.attachments?.length?{attachments:m.attachments}:{},...m.images?.length?{images:m.images}:{}});break}case"peer.message":{let v=m.from||{};e.push({id:g.id,kind:"event",type:"peer-message",text:m.text,from:v.trackName||v.boxId||v.name||null,fromTrackId:v.trackId||null,ts:ot(g),box:g.boxId,agent:g.provider});break}case"turn.agent":{if(m.model==="<synthetic>"&&/^No response requested\.$/.test(String(m.text||"").trim()))break;X();let v=(m.images||[]).filter(mt=>!h(mt,ot(g)));if(!String(m.text||"").trim()&&!v.length)break;if(g.provider==="cursor"){let mt=`${g.boxId}|${m.text}`;if(n.has(mt))break;n.add(mt)}(!yt||yt.box===g.boxId)&&(yt=null);let $=g.provider==="codex"?(m.tools||[]).filter(mt=>!Ru.has(mt)&&!Cs.has(mt)):m.tools||[],it=m.text,ct=null;if(ju.has(g.provider)){let mt=Lu(String(m.text||""));mt&&(it=mt.text,ct={questions:mt.questions})}e.push({id:g.id,kind:"message",role:"assistant",text:it,ts:ot(g),box:g.boxId,agent:g.provider,boxRole:m.boxRole,...ct?{ask:ct}:{},...$.length?{tools:$}:{},...m.model?{model:m.model}:{},...m.sourceId?{sourceId:m.sourceId}:{},...v.length?{images:v}:{}}),ct&&(yt={id:g.id,groupId:Fu(g.provider,m.sourceId||g.id,ct.questions),provider:g.provider,box:g.boxId,questions:ct.questions,ts:ot(g)});break}case"job.started":{if(!m.id)break;let v=ot(g),$=i.get(m.id);if(!$&&(m.kind||"agent")==="agent"&&m.name){let b=l.get(m.name);b&&b.ts>=v&&($=b)}let it={jobId:m.id,jobKind:m.kind||"agent",name:m.name||null,detail:m.detail||null,status:$?$.status==="killed"?"stopped":$.status&&$.status!=="completed"?"failed":"done":"running",startedTs:v,finishedTs:$?.ts??null,summary:$?.summary??null,resultHead:$?.resultHead??null},ct=bt.get(g.boxId),mt=ct?.jobs[ct.jobs.length-1]?.startedTs;if(ct&&mt!=null&&v-mt<=dt)ct.jobs.push(it);else{let b={id:g.id,kind:"job-dock",dockId:m.id,ts:v,box:g.boxId,agent:g.provider,jobs:[it]};bt.set(g.boxId,b),e.push(b)}break}case"handoff.done":e.push(be(g,"lead-handoff"));break;case"subtask.delegated":e.push({...be(g,"subtask-delegated"),to:g.boxId,toAgent:g.provider});break;case"subtask.merged":e.push(be(g,"subtask-merged"));break;case"pr.state.changed":{if(!m.change)break;if(m.change==="opened"){for(let $ of x.values())$.status="stale";x.clear();for(let $ of O.values())$.status="stale";O.clear()}let v=be(g,`pr-${m.change}`);if(v.box=g.boxId??null,fI.has(m.change)&&m.number!=null){let $=pI(w,y,m);if(w.size>=2){for(let ct of y.values())for(let mt of ct)mt.grouped=!0;v.groupPrs=[...w.values()];let it=[v];for(let ct of w.keys())y.set(ct,it)}else{let it=y.get($)??[];it.push(v),y.set($,it)}}else if(m.change==="merged"||m.change==="closed"||m.change==="lost"){let $=Qw(m),it=k&&!k.complete||w.size>=2;if(w.has($))w.delete($),y.delete($);else if(m.number!=null)for(let ct of[...w.keys()])ct.endsWith(`#${m.number}`)&&(w.delete(ct),y.delete(ct));if(it&&m.number!=null){(!k||k.complete)&&(k={id:g.id,kind:"event",type:"pr-group-settled",prs:[],remaining:[],complete:!1,at:ot(g),ts:ot(g),box:g.boxId,agent:g.provider},e.push(k)),k.prs.push({number:m.number,url:m.url??null,title:m.title??null,repo:m.repo??null,branch:m.branch??null,change:m.change,ts:ot(g)}),k.remaining=[...w.values()],k.complete=w.size===0;break}}e.push(v);break}case"pr.offered":{if(!m.offerId)break;for(let $ of x.values())$.status="stale";x.clear();for(let $ of O.values())$.status="stale";O.clear();let v={id:g.id,kind:"pr-offer",offerId:m.offerId,excerpt:m.excerpt||null,branch:m.branch||null,base:m.base||null,offered:Array.isArray(m.offered)&&m.offered.length?m.offered:null,toPr:m.toPr&&typeof m.toPr=="object"?{number:m.toPr.number??null}:null,repos:Array.isArray(m.repos)&&m.repos.length?m.repos:null,status:"open",ts:ot(g),box:g.boxId,agent:g.provider};x.set(m.offerId,v),E.set(m.offerId,v),e.push(v);break}case"pr.offer.answered":{let v=E.get(m.offerId);v&&(v.status=m.action||"dismiss",v.actions=Array.isArray(m.actions)?m.actions:null,v.notify=m.notify===!0,m.existingPr&&typeof m.existingPr=="object"&&(v.existingPr={number:m.existingPr.number??null}),x.delete(m.offerId));break}case"pr.exists.offered":{if(!m.offerId)break;for(let $ of O.values())$.status="stale";O.clear();let v={id:g.id,kind:"pr-exists-offer",offerId:m.offerId,srcOfferId:m.srcOfferId??null,branch:m.branch||null,base:m.base||null,pr:m.pr&&typeof m.pr=="object"?{number:m.pr.number??null,url:m.pr.url??null,title:m.pr.title??null}:null,actions:Array.isArray(m.actions)&&m.actions.length?m.actions:null,notify:m.notify===!0,status:"open",ts:ot(g),box:g.boxId,agent:g.provider};O.set(m.offerId,v),z.set(m.offerId,v),e.push(v);break}case"pr.exists.answered":{let v=z.get(m.offerId);v&&(v.status=m.choice||"dismiss",O.delete(m.offerId));break}case"box.state.changed":{let v=m.change==="model"?"model-change":m.change;if(!v)break;let $=be(g,v);v==="model-change"&&($.to=m.model),e.push($);break}case"track.transferred":case"track.recovered":e.push(be(g,"track-moved"));break;case"view.state.changed":{if(m.change!=="created"||m.restarted)break;e.push({id:g.id,kind:"view-card",viewId:m.viewId,name:m.name,slug:m.slug,port:m.port,origin:m.origin,ts:ot(g),box:g.boxId,agent:g.provider});break}case"view.spinup.failed":{e.push({id:g.id,kind:"view-spinup-failed",name:m.name||null,reason:m.reason||"no-view",ts:ot(g),box:g.boxId,agent:g.provider});break}case"mock.state.changed":{if(m.change==="picked"){e.push({id:g.id,kind:"mock-picked",mockId:m.mockId,name:m.name,group:m.group??null,version:m.version??null,siblings:m.siblings??[],ts:ot(g),box:g.boxId,agent:g.provider});break}if(m.change!=="created")break;e.push({id:g.id,kind:"mock-card",mockId:m.mockId,name:m.name,group:m.group??null,ts:ot(g),box:g.boxId,agent:g.provider});break}case"flow.state.changed":{if(m.change!=="created")break;e.push({id:g.id,kind:"flow-card",flowId:m.flowId,name:m.name,stepCount:m.stepCount??null,mockIds:m.mockIds??[],ts:ot(g),box:g.boxId,agent:g.provider});break}case"runbook.state.changed":{if(m.change!=="created")break;e.push({id:g.id,kind:"runbook-card",runbookId:m.runbookId,name:m.name,ts:ot(g),box:g.boxId,agent:g.provider});break}case"ticket.linked":{e.push({id:g.id,kind:"ticket-card",provider:m.provider||"linear",key:m.key,url:m.url,title:m.title??null,linkSource:m.linkSource??null,ts:ot(g),box:g.boxId,agent:g.provider});break}case"box.fullscreen.detected":{if(!m.offerId)break;for(let $ of T.values())$.box===(m.box||g.boxId)&&($.status="stale",T.delete($.offerId));let v={id:g.id,kind:"fullscreen-offer",offerId:m.offerId,status:"open",ts:ot(g),box:m.box||g.boxId,agent:m.agent||g.provider};T.set(m.offerId,v),D.set(m.offerId,v),e.push(v);break}case"box.fullscreen.answered":{let v=D.get(m.offerId);v&&(v.status=m.action==="restarted"?"restarted":m.action==="cleared"?"cleared":"dismiss",T.delete(m.offerId));break}case"ticket.move.offered":{if(!m.offerId)break;for(let $ of C.values())$.key===m.key&&($.status="stale",C.delete($.offerId));let v={id:g.id,kind:"ticket-offer",offerId:m.offerId,provider:m.provider||"linear",key:m.key,url:m.url??null,phase:m.phase??null,from:m.from??null,to:m.to?.name??null,prNumber:m.prNumber??null,status:"open",ts:ot(g),box:g.boxId,agent:g.provider};C.set(m.offerId,v),N.set(m.offerId,v),e.push(v);break}case"ticket.move.answered":{let v=N.get(m.offerId);v&&(v.status=m.action==="moved"?"moved":"dismiss",C.delete(m.offerId));break}case"ticket.state.changed":{for(let v of C.values())v.key===m.key&&v.to===m.to&&(v.status="stale",C.delete(v.offerId));if(m.mode==="offer")break;e.push(be(g,"ticket-state"));break}case"ticket.commented":{e.push({id:g.id,kind:"ticket-comment",key:m.key,url:m.url??null,excerpt:m.excerpt??null,ts:ot(g),box:g.boxId,agent:g.provider});break}case"ticket.flow.changed":e.push(be(g,"ticket-flow"));break;case"ticket.create.offered":{if(!m.proposalId)break;for(let $ of j.values())$.status="stale";j.clear();let v={id:g.id,kind:"ticket-create-offer",proposalId:m.proposalId,provider:m.provider||"linear",epic:m.epic??null,issues:Array.isArray(m.issues)?m.issues:[],team:m.team??null,needsTeam:!!m.needsTeam,linkCurrentTrack:!!m.linkCurrentTrack,status:"open",ts:ot(g),box:g.boxId,agent:g.provider};j.set(m.proposalId,v),st.set(m.proposalId,v),e.push(v);break}case"ticket.create.answered":{let v=st.get(m.proposalId);v&&(v.status=m.action==="created"?"created":"dismiss",v.createdCount=m.createdCount??null,v.failedCount=m.failedCount??null,j.delete(m.proposalId));break}case"loop.create.offered":{if(!m.proposalId)break;for(let $ of rt.values())$.status="stale";rt.clear();let v={id:g.id,kind:"loop-create-offer",proposalId:m.proposalId,name:m.name??"",schedule:m.schedule??"",prompt:m.prompt??"",expectation:m.expectation??null,notify:m.notify??"off",assignment:m.assignment??{provider:"claude"},repo:m.repo??null,status:"open",ts:ot(g),box:g.boxId,agent:g.provider};rt.set(m.proposalId,v),A.set(m.proposalId,v),e.push(v);break}case"loop.create.answered":{let v=A.get(m.proposalId);v&&(v.status=m.action==="created"?"created":"dismiss",rt.delete(m.proposalId));break}case"loop.created":{let v=m.proposalId?A.get(m.proposalId):null;v&&(v.created={loopId:m.loopId??null,nextFireAt:Number.isFinite(Number(m.nextFireAt))?Number(m.nextFireAt):null});break}case"ticket.created":{let v={items:Array.isArray(m.items)?m.items:[],failed:Array.isArray(m.failed)?m.failed:[],team:m.team??null},$=m.proposalId?st.get(m.proposalId):null;if($){$.created=v;break}e.push({id:g.id,kind:"ticket-created",...v,ts:ot(g),box:g.boxId,agent:g.provider});break}case"error":{if(!m.kind)break;e.push(be(g,m.kind));break}case"usage.cap.hit":e.push(be(g,"usage-cap-hit"));break;case"usage.cap.warning":e.push(be(g,"usage-cap-warning"));break;case"provider.connected":{e.push({id:g.id,kind:"event",type:"provider-connected",provider:m.provider||g.provider,ts:ot(g),at:ot(g),box:g.boxId,agent:g.provider});break}case"prompt.answered":{if(yt=null,m.control||!m.question)break;let v=m.groupId||m.promptId;if(!v)break;let $=B.get(v);$||($={id:g.id,kind:"prompt",groupId:v,provider:g.provider,box:g.boxId,agent:g.provider,questionTotal:m.questionTotal??1,questions:[],ts:ot(g)},B.set(v,$));let it=m.questionIndex??0,ct={index:it,header:m.header||"",question:m.question,multiSelect:!!m.multiSelect,chosen:Array.isArray(m.chosen)?m.chosen:[]},mt=$.questions.findIndex(b=>b.index===it&&Ot(b.question)===Ot(ct.question));mt>=0?$.questions[mt]=ct:$.questions.push(ct),$.questions.sort((b,_)=>b.index-_.index),$.questionTotal=Math.max($.questionTotal,m.questionTotal??1),$.questions.length>=$.questionTotal&&(e.push($),B.delete(v));break}default:break}}return hI(e.sort((g,m)=>(g.ts??0)-(m.ts??0)))}function hI(t){let e=new Map,n=[];for(let r of t){if(r.kind!=="message"||!r.box){n.push(r);continue}let o=r.role==="assistant"&&!String(r.text||"").trim()&&r.images?.length,s=e.get(r.box);if(o&&s&&(r.ts??0)-s.lastTs<=mI){s.item.images.push(...r.images),s.lastTs=r.ts??s.lastTs;continue}if(o){let a={...r,images:[...r.images]};e.set(r.box,{item:a,lastTs:r.ts??0}),n.push(a)}else e.delete(r.box),n.push(r)}return n}function Wu(t,e=null){let n=[];for(let o of t||[]){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:wI(s),ts:s.ts??o.ts,n:s.n,box:o.boxId,agent:o.provider,boxRole:s.boxRole})}if(!n.length)return[];let r=(e??hr(t)).filter(o=>o.kind==="message");return Cw(n,r)}function wI(t){let e=String(t.summary||"").trim();return e&&e!==t.command&&e!==io(t.command)?e:Rn(t.command,t.description||"")}function be(t,e){let{ts:n,change:r,...o}=t.payload||{};return{id:t.id,kind:"event",type:e,...o,at:ot(t),ts:ot(t)}}function tg(t){let e=[...t];for(let n=0;n<e.length;n++){let r=e[n];if(r?.kind!=="event"||r.type!=="archived")continue;let o=(r.ts??0)+gI,s=n;for(;s+1<e.length;){let a=e[s+1];if((a?.ts??0)>o||a?.kind==="event"&&yI.has(a.type))break;s++}s>n&&e.splice(s,0,...e.splice(n,1)),n=s}return e}function eg(t){let e=[...t];for(let n=0;n<e.length;n++){let r=e[n];if(r?.kind!=="event"||!kI.has(r.type)||!r.box)continue;let o=(r.ts??0)+bI,s=n;for(;s+1<e.length;){let a=e[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&&e.splice(s,0,...e.splice(n,1)),n=s}return e}var ot,fI,Qw,mI,gI,yI,bI,kI,qu=M(()=>{co();lo();Cu();Bu();Hu();ot=t=>t.payload?.ts??t.ts;fI=new Set(["opened","ci-fixed","reconciled","pushed"]),Qw=t=>`${t.repo??""}#${t.number}`;mI=2*6e4;gI=12e4,yI=new Set(["archived","unarchived","opened"]);bI=2500,kI=new Set(["pr-opened","pr-merged","pr-auto-armed"])});function AI(t){let e=null,n=null,r=null;for(let o of t??[]){let s=o?.ts??null;s&&(r=Math.max(r??0,s)),o?.type==="handoff.artifact"&&(e={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:e,lastPush:n,lastEventAt:r}}function _I(t){for(let e=(t?.length??0)-1;e>=0;e--){let n=t[e];if(n?.type==="handoff.artifact"&&!n.payload?.reconstructed)return n}return null}function II(t,e){let n=[],r=[],o=new Set,s=new Set;for(let a=(t?.length??0)-1;a>=0;a--){let i=t[a];if(i?.type!=="tool.called")continue;if(e!=null&&(i.ts??0)<=e)break;let c=i.payload||{};c.path&&!o.has(c.path)&&n.length<vI&&(o.add(c.path),n.push(c.path)),c.head&&!s.has(c.head)&&r.length<TI&&(s.add(c.head),r.push(c.head))}return{files:n,heads:r}}function sg(t,{trackName:e="this Track",now:n=null,mode:r="failover"}={}){let o=AI(t),s=_I(t),a=s?.payload?.content??null,i=s?s.payload?.ts??s.ts??null:null,c=hr(t??[]).filter(d=>d?.kind==="message"&&typeof d.text=="string"&&d.text.trim()).slice(-xI);if(!a&&!c.length)return null;let l=[];if(l.push(`# Reconstructed resume brief \u2014 ${e}`),l.push(""),l.push(og[r]??og.failover),l.push(""),o.lastPush?.sha){let d=rg(n,o.lastPush.ts),p=d?` (~${d} min before the loss)`:"";l.push(`**Code state:** last pushed ref \`${o.lastPush.ref}\` @ \`${o.lastPush.sha.slice(0,12)}\`${p}`+(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 d=rg(n,i);l.push(`## Last real checkpoint (written by the previous agent${d?`, ~${d} min before this reconstruction`:""})`),l.push(""),l.push(a.trim()),l.push("")}let u=II(t??[],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(d=>`\`${d}\``).join(", ")}`),u.heads.length&&(u.files.length&&l.push(""),l.push(`Commands run (most recent first): ${u.heads.map(d=>`\`${d}\``).join(" \xB7 ")}`)),l.push("")),c.length){l.push(`## Recent conversation (last ${c.length} message${c.length===1?"":"s"})`),l.push("");for(let d of c)l.push(`**${d.role==="user"?"operator":"agent"}:** ${EI(d.text,SI)}`),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 f=l.join(`
107
+ `);return f.length<=ng?f:`${f.slice(0,ng)}
108
+
109
+ [\u2026 brief truncated]`}var xI,SI,ng,vI,TI,EI,rg,og,ag=M(()=>{qu();xI=12,SI=2e3,ng=48e3,vI=30,TI=10;EI=(t,e)=>{let n=String(t??"").trim();return n.length<=e?n:`${n.slice(0,e-1)}\u2026`},rg=(t,e)=>t&&e?Math.max(1,Math.round((t-e)/6e4)):null;og={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.",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 RI from"node:fs";import $n from"node:fs/promises";import On from"node:path";function pg(t){let e=lr(String(t??"")),n=Buffer.byteLength(e,"utf8");return n<=ig?{content:e,bytes:n,truncated:!1}:{content:`${Buffer.from(e,"utf8").subarray(0,ig).toString("utf8").replace(/�+$/,"")}
110
+
111
+ [\u2026 truncated by bostrat at 32 KiB \u2014 full artifact in the workspace]`,bytes:n,truncated:!0}}function jI(t){let e=String(t||"").split(/\r?\n/).map(s=>s.trim()).filter(Boolean),n=[],r=[];for(let s of e)if(lg.test(s)){if(r.length>=bg)continue;let a=BI(s.replace(lg,"").replace(/[.;,:]+$/,""),kg,PI);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>cg&&(o=`${o.slice(0,cg-1).trimEnd()}\u2026`),{text:o,items:r.length>1?r:[]}}async function xg(t,e,{timeoutMs:n=9e4}={}){let r=On.join(e,MI),o=On.join(r,NI);await $n.mkdir(r,{recursive:!0});let s=await Di(o),a=await et(t);if(!a)throw new Error(`session "${t}" not found`);return await Bi(t,a,DI(o)),await Ig(o,s,n),jI(await $n.readFile(o,"utf8"))}function Sg(t,e){let n=(e||"").trim();if(!n)return!1;if(t==="assistant")return n===hg||n===yg;let r=n.replace(/^\/[a-z0-9:_-]+\s+/i,"");return r.startsWith(mg)||n===$I||r.startsWith(wg)||r.startsWith(gg)}function vg(t){let e=[];for(let r of t?.events||[]){if(r.type!=="lead-handoff"||!r.from)continue;let o=r.at??Date.now(),s=r.handoffStartedAt??o-LI;e.push({box:r.from,from:s,to:o}),r.to&&r.to!==r.from&&e.push({box:r.to,from:s,to:o})}let n=t?.handoff;return n?.fromBox&&n.startedAt&&n.finishedAt&&e.push({box:n.fromBox,from:n.startedAt,to:n.finishedAt}),n?.toBox&&n.startedAt&&n.finishedAt&&e.push({box:n.toBox,from:n.startedAt,to:n.finishedAt}),e}function Tg(t,e){let n=[];for(let r of t?.boxes||[]){let o=e?.(r.name);o?.startedAt&&n.push({box:r.name,from:o.startedAt,to:o.finishedAt||Date.now()+1e12})}return n}function Ag(t,{windows:e=[]}={}){if(Sg(t.role,t.text))return!0;if(t.role!=="assistant"||!t.ts)return!1;for(let n of e)if(t.box===n.box&&t.ts>=n.from&&t.ts<=n.to)return!0;return!1}function ji(t){return Ku.get(t)||null}async function Eg(t){let e=Ku.get(t);if(e&&!e.finishedAt)throw new Error("a handoff is already running for this session");let n=await et(t);if(!n)throw new Error(`session "${t}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${t}"`);let r={name:t,step:"summarize",startedAt:Date.now(),finishedAt:null,error:null,file:On.join(n.cwd,dg,fg)};return Ku.set(t,r),HI(r,n.cwd).catch(o=>{r.error=o?.message||String(o),r.finishedAt=Date.now()}),r}async function HI(t,e){t.step="summarize",await _g(t.name,e),t.step="clear";let n=await et(t.name);await Bi(t.name,n,"/clear"),await zu(FI),t.step="resume",await Bi(t.name,n,CI),t.step="done",t.finishedAt=Date.now()}async function _g(t,e,{timeoutMs:n=UI}={}){let r=On.join(e,dg),o=On.join(r,fg);await $n.mkdir(r,{recursive:!0});let s=await Di(o),a=await et(t);await G({flow:"checkpoint",phase:"summarize-start",sessionName:t,cwd:e,file:o,beforeMtime:s}),await Bi(t,a,OI(o)),await Ig(o,s,n),await G({flow:"checkpoint",phase:"summarize-done",sessionName:t,file:o,afterMtime:await Di(o)});let i=await Sw(e,o,{exclude:u=>Sg(u.role,u.text)});await G({flow:"checkpoint",phase:"seed-enriched",sessionName:t,file:o,...i});let c=/workspaces[/\\]([0-9a-f]{8})$/.exec(e||"")?.[1];if(c){await I({id:c,cwd:e},{type:"memory.seed",actor:"orchestrator",payload:{...i,tokensEst:i.chars?Math.round(i.chars/4):0,ts:Date.now()}}).catch(()=>{});try{let u=await $n.readFile(o,"utf8");await I({id:c,cwd:e},{type:"handoff.artifact",actor:"orchestrator",payload:{...pg(u),ts:Date.now()}})}catch{}}await xh(e);let l=await WI(r,o);return c&&await Ch(c,l||o,{box:t,agent:a?.agent??null}),o}async function Gu(t,{timeoutMs:e}={}){let n=await et(t);if(!n)throw new Error(`session "${t}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${t}"`);return _g(t,n.cwd,e?{timeoutMs:e}:void 0)}async function Vu(t,e,{trackName:n="this Track"}={}){let r=await F({id:t,cwd:e}),o=sg(r,{trackName:n,now:Date.now(),mode:"in-place"});if(!o)return null;let s=On.join(e,ug);return await $n.mkdir(On.dirname(s),{recursive:!0}),await $n.writeFile(s,o,"utf8"),await I({id:t,cwd:e},{type:"handoff.artifact",actor:"orchestrator",payload:{...pg(o),reconstructed:!0,ts:Date.now()}}).catch(()=>{}),ug}async function Di(t){try{return(await $n.stat(t)).mtimeMs}catch{return 0}}async function Ig(t,e,n){let r=Date.now()+n;for(;;){if(await Di(t)>e)return;if(Date.now()>r)throw new Error(`timed out waiting for the handoff file to be written (${t})`);await zu(2e3)}}async function WI(t,e){try{if(!RI.existsSync(e))return null;let n=new Date().toISOString().replace(/[:.]/g,"-"),r=On.join(t,`${n}.md`);return await $n.copyFile(e,r),r}catch{return null}}function zu(t){return new Promise(e=>setTimeout(e,t))}async function Bi(t,e,n){if(e){let o=e.agent==="claude"?process.env.BOSTRAT_AGENT_CMD||"claude":e.agent==="cursor"?process.env.BOSTRAT_CURSOR_CMD||"cursor-agent":e.agent==="codex"?process.env.BOSTRAT_CODEX_CMD||"codex":"";await In({cwd:e.cwd,sessionId:e.sessionId,sessionName:t,agent:e.agent,agentCmd:o})}let r=await et(t);if(!r)throw new Error(`session "${t}" disappeared before the orchestration prompt could be sent`);await It(t,["Escape"],{kind:"drive-wipe"}),await zu(150),await eo(t,xi,{kind:"drive-wipe"}),await Pt(t,n,{kind:"orchestration-drive",...$e(r.agent)})}var dg,fg,ig,mg,hg,wg,$I,OI,CI,gg,yg,MI,NI,cg,bg,kg,PI,DI,lg,BI,LI,FI,UI,Ku,ug,Ju=M(()=>{qt();Ri();Ke();_s();vw();ci();at();pi();ag();dg=".bostrat/handoff",fg="latest.md",ig=32*1024;mg="Checkpoint: write a work-in-progress handoff",hg="HANDOFF WRITTEN",wg="Resume from .bostrat/handoff/latest.md",$I="/clear",OI=t=>`${mg} to the EXACT absolute path ${t} (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 ${hg} and take no further action.`,CI=`${wg}: read it, restate the Objective and the single next step in one line, then continue the work from 'Next steps'.`,gg="Beat: write a",yg="BEAT WRITTEN",MI=".bostrat/arc",NI="beat.txt",cg=200,bg=4,kg=5,PI=36,DI=t=>`${gg} short summary of what this workstream accomplished, to the EXACT absolute path ${t} (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 ${bg} further lines, each starting with "- " and naming ONE piece in at most ${kg} 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 ${yg} and take no further action.`,lg=/^(?:[-–—*•·]|\d+[.)])\s+/,BI=(t,e,n)=>{let r=t.split(/\s+/).filter(Boolean).slice(0,e).join(" ");return r.length>n?`${r.slice(0,n-1).trimEnd()}\u2026`:r};LI=6e5;FI=3500,UI=3e5,Ku=new Map;ug=".bostrat/handoff/status-latest.md"});function $g(t,e,n){if(t==null)return e==="from"?-1/0:1/0;if(!qI.test(String(t)))throw new Error(`pricing.js: ${n} window ${e} must be YYYY-MM-DD, got ${JSON.stringify(t)}`);let r=Date.parse(`${t}T${e==="from"?"00:00:00.000":"23:59:59.999"}Z`);if(!Number.isFinite(r))throw new Error(`pricing.js: ${n} window ${e} is not a real date: ${t}`);return r}function KI(t){let e={};for(let[n,r]of Object.entries(t)){if(!Array.isArray(r)||r.length===0)throw new Error(`pricing.js: ${n} must be a non-empty array of rate windows`);e[n]=r.map(o=>({...o,fromMs:$g(o.from,"from",n),toMs:$g(o.to,"to",n)}))}return e}function VI(t){if(t==null)return Date.now();if(typeof t=="number")return Number.isFinite(t)?t:null;if(t instanceof Date){let n=t.getTime();return Number.isFinite(n)?n:null}let e=Date.parse(String(t));return Number.isFinite(e)?e:null}function zI(t){if(!t)return null;let e=String(t).trim();return Yu[e]?e:Rg[e]?Rg[e]:Object.keys(Yu).find(r=>e.startsWith(r))||null}function Og(t,e){let n=zI(t);if(!n)return null;let r=VI(e);return r===null?null:GI[n].find(o=>r>=o.fromMs&&r<=o.toMs)||null}function Cn(t,e={},n){let r=Og(t,n);return r?((e.input||0)*r.input+(e.output||0)*r.output+(e.cacheWrite||0)*r.cacheWrite+(e.cacheRead||0)*r.cacheRead)/1e6:0}var Yu,Rg,qI,GI,Cg,Ds=M(()=>{Yu={"claude-opus-5":[{from:null,to:null,input:5,output:25,cacheWrite:10,cacheRead:.5,note:"GA rates; verified 2026-08-06 via the claude-api skill."}],"claude-opus-4-8":[{from:null,to:null,input:5,output:25,cacheWrite:10,cacheRead:.5,note:"verified 2026-08-06 via the claude-api skill."}],"claude-sonnet-5":[{from:null,to:"2026-08-31",input:2,output:10,cacheWrite:4,cacheRead:.2,note:"GA introductory pricing ($2/$10); verified 2026-08-06 via the claude-api skill."},{from:"2026-09-01",to:null,input:3,output:15,cacheWrite:6,cacheRead:.3,note:"standard rates resume after the intro window; verified 2026-08-06."}],"claude-sonnet-4-6":[{from:null,to:null,input:3,output:15,cacheWrite:6,cacheRead:.3,note:"verified 2026-08-06 via the claude-api skill."}],"claude-haiku-4-5":[{from:null,to:null,input:1,output:5,cacheWrite:2,cacheRead:.1,note:"verified 2026-08-06 via the claude-api skill."}],"claude-fable-5":[{from:null,to:null,input:10,output:50,cacheWrite:20,cacheRead:1,note:"verified 2026-08-06 via the claude-api skill; 83% of fleet spend."}],"gpt-5.5":[{from:null,to:null,input:5,output:30,cacheWrite:5,cacheRead:.5,note:"verified 2026-07-03; no cache-write premium on 5.5-and-earlier."}],"gpt-5.6-sol":[{from:null,to:null,input:5,output:30,cacheWrite:6.25,cacheRead:.5,note:"verified 2026-07-18; cacheWrite = 1.25\xD7 input (30-min TTL)."}],"gpt-5.6-terra":[{from:null,to:null,input:2.5,output:15,cacheWrite:3.125,cacheRead:.25,note:"verified 2026-07-18; cacheWrite = 1.25\xD7 input (30-min TTL)."}],"gpt-5.6-luna":[{from:null,to:null,input:1,output:6,cacheWrite:1.25,cacheRead:.1,note:"verified 2026-07-18; cacheWrite = 1.25\xD7 input (30-min TTL)."}]},Rg={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"},qI=/^\d{4}-\d{2}-\d{2}$/;GI=KI(Yu);Cg=(t,e)=>Og(t,e)!==null});function JI(t){return t?{input:t.input||0,output:t.output||0,cacheRead:t.cacheRead||0,cacheWrite:t.cacheWrite??t.cacheCreation??0}:null}function Ng(t,e){e&&(t.input+=e.input,t.output+=e.output,t.cacheRead+=e.cacheRead,t.cacheCreation+=e.cacheWrite)}function Ve(t){let e=t.payload?.model||"unknown",n=JI(t.payload?.tokens),r=Number(t.payload?.usd)||0,o=t.source==="vendor",s=r,a=!1;if(n&&!o){let l=Cn(e,n,t.ts);l>0&&(s=l,a=Math.abs(l-r)>1e-9)}let i=n?n.input+n.output+n.cacheRead+n.cacheWrite:0,c=!s&&i>0&&!Cg(e,t.ts);return{usd:s,model:e,tokens:n,repriced:a,unpriced:c,asRecorded:r}}function Mn(t,{boxLabels:e={}}={}){let n=(t||[]).filter(d=>d.type==="cost.recorded"),r={},o={},s={},a=0,i=0,c=0,l=0,u=new Set,f=Mg();for(let d of n){let{usd:p,model:h,tokens:w,repriced:y,unpriced:k,asRecorded:x}=Ve(d);i+=x;let E=d.provider||"unknown",O=d.boxId||"unattributed";if(y&&c++,k&&(l++,u.add(h)),a+=p,Ng(f,w),r[h]||={usd:0,tokens:Mg(),events:0},r[h].usd+=p,r[h].events+=1,Ng(r[h].tokens,w),o[E]||={usd:0,events:0},o[E].usd+=p,o[E].events+=1,s[O]||={usd:0,events:0,provider:E,models:new Set,label:e[O]||O},s[O].usd+=p,s[O].events+=1,h!=="unknown"&&s[O].models.add(h),d.epoch!=null){let z=(s[O].epochs||={})[d.epoch]||={usd:0,events:0,provider:E,models:new Set};z.usd+=p,z.events+=1,z.provider=E,h!=="unknown"&&z.models.add(h)}}return{totalUsd:fo(a),asRecordedUsd:fo(i),totalTokens:f,turns:n.length,repricedTurns:c,unpricedTurns:l,unpricedModels:[...u],byModel:Li(r,d=>({...d,usd:fo(d.usd)})),byProvider:Li(o,d=>({...d,usd:fo(d.usd)})),byBox:Li(s,d=>({usd:fo(d.usd),events:d.events,provider:d.provider,label:d.label,models:[...d.models],...d.epochs?{epochs:Li(d.epochs,p=>({usd:fo(p.usd),events:p.events,provider:p.provider,models:[...p.models]}))}:{}}))}}var Mg,fo,Li,wr=M(()=>{Ds();Mg=()=>({input:0,output:0,cacheRead:0,cacheCreation:0});fo=t=>Math.round(t*1e4)/1e4,Li=(t,e)=>Object.fromEntries(Object.entries(t).map(([n,r])=>[n,e(r)]))});function YI(t){if(!Number.isFinite(t)||t<=0)return null;let e=t/864e5;if(e>=1)return`${Math.round(e)}d`;let n=t/36e5;return n>=1?`${Math.round(n)}h`:`${Math.max(1,Math.round(t/6e4))}m`}function Pg(t,e=[]){let n=[],r=t?.events||[],o=new Map,s=0;for(let u of e){if(u.type!=="pr.state.changed")continue;let f=u.payload||{};!f.repo||f.number==null||(f.change==="merged"?o.set(`${f.repo}#${f.number}`,f):f.change==="opened"&&s++)}if(o.size){let u=[...o.keys()].map(f=>{let[d,p]=f.split("#");return`${d.split("/").pop()}#${p}`});n.push(`Merged ${u.slice(0,4).join(", ")}${u.length>4?` +${u.length-4}`:""}`)}else s&&n.push(Xu(s,"PR")+" opened");let a=Object.keys(t?.subtasks||{}).length||r.filter(u=>u.type==="subtask-delegated").length;a&&n.push(Xu(a,"subtask"));let i=r.filter(u=>u.type==="lead-handoff"&&u.fromAgent&&u.toAgent);if(i.length){let u=i.slice(0,3).map(f=>`${f.fromAgent}\u2192${f.toAgent}`).join(", ");n.push(`${Xu(i.length,"handoff")} ${u}${i.length>3?"\u2026":""}`)}let c=Mn(e);c.totalUsd>=.01&&n.push(`$${c.totalUsd.toFixed(2)}`);let l=Number.isFinite(t?.archivedAt)&&Number.isFinite(t?.createdAt)?YI(t.archivedAt-t.createdAt):null;return n.length&&l&&n.push(l),n.length?n.join(" \xB7 "):null}var Xu,Dg=M(()=>{wr();Xu=(t,e)=>`${t} ${e}${t===1?"":"s"}`});import{execFile as XI}from"node:child_process";import{promisify as ZI}from"node:util";import{randomUUID as QI}from"node:crypto";async function Zu(t,e){let n=Date.now()+e;for(;;){if(await to(t))return!0;if(Date.now()>n)return!1;await Fi(eR)}}async function rR(t,e){let n=jg[e]||jg.default;n.escape&&(await It(t,["Escape"],{kind:"swap-exit"}),await Fi(150)),n.wipe&&await eo(t,xi,{kind:"swap-exit"}),await Si(t,n.text,{perCharDelayMs:90,kind:"swap-exit"});let r=$e(e).submitDelayMs||0;await Fi(Math.max(r,250)),await It(t,["Enter"],{kind:"swap-exit"})}async function oR(t,e){try{let{stdout:n}=await po(L,U("show-environment","-t",t,e));return!String(n||"").trimStart().startsWith("-")}catch{return!1}}async function Lg(t){await po(L,U("respawn-pane","-k","-t",t))}async function Qu(t,e={}){if(!At(t))throw new Error("invalid session name");let n=String(e.agentCmd||"").trim();if(!n)throw new Error("agentCmd is required");let r=await et(t);if(!r)throw new Error(`session "${t}" not found`);if(!r.cwd)throw new Error(`can't resolve cwd for "${t}"`);let o=r.agent||"agent",s=e.agent||vn(n),a=Number(e.exitTimeoutMs)||tR;await G({flow:"swap",phase:"start",sessionName:t,from:o,to:s,cwd:r.cwd});let i=!1;if(!await to(t)&&(await rR(t,o),!await Zu(t,a)&&(i=!0,await G({flow:"swap",phase:"respawn-forced",sessionName:t,from:o}),await Lg(t),!await Zu(t,Bg))))throw new Error(`pane shell did not come back after respawn-pane in "${t}"`);let c=s==="claude"&&ur(n),l=c?Za():null,u=await oR(t,"ANTHROPIC_API_KEY"),f=!1;try{l?(await po(L,U("set-environment","-t",t,"ANTHROPIC_API_KEY",l)),f=!0):u&&(await po(L,U("set-environment","-u","-t",t,"ANTHROPIC_API_KEY")),f=!0)}catch(y){throw l?hi(y,l):y}if(f&&!i&&(await Lg(t),!await Zu(t,Bg)))throw new Error(`pane shell did not come back after env respawn in "${t}"`);let d=!!e.resumeSessionId,p=e.resumeSessionId||QI(),h=d?n:eu(n,p,t),w=d?e.pinned===!0:/(^|\s)--session-id(\s|=)/.test(h);return c&&await gn(r.cwd),s==="codex"&&await qr(r.cwd),s==="cursor"&&await Kr(r.cwd),await dr(t),await po(L,U("set-option","-t",t,"@bostrat-sid",p)),await po(L,U("set-option","-t",t,"@bostrat-agent",s)),await Fi(nR),await Pt(t,h,{kind:"swap-launch"}),await G({flow:"swap",phase:"done",sessionName:t,from:o,to:s,sid:p,forced:i,envRespawned:f}),{name:t,cwd:r.cwd,sessionId:p,agent:s,pinned:w,forced:i,envRespawned:f}}var po,Fi,tR,Bg,eR,nR,jg,Fg=M(()=>{qt();ls();ti();ei();_s();Ke();po=ZI(XI),Fi=t=>new Promise(e=>setTimeout(e,t)),tR=Number(process.env.BOSTRAT_SWAP_EXIT_TIMEOUT_MS)||15e3,Bg=Number(process.env.BOSTRAT_SWAP_SHELL_TIMEOUT_MS)||8e3,eR=250,nR=400,jg={claude:{escape:!0,wipe:!0,text:"/exit"},codex:{escape:!0,wipe:!0,text:"/quit"},cursor:{escape:!0,wipe:!0,text:"/quit"},default:{escape:!1,wipe:!1,text:"exit"}}});async function Ug(t,{maxBytes:e=2097152,limit:n=100}={}){let r;try{r=await Xt(t,e)}catch{return[]}let o=new Map,s=new Set;for(let i of r.split(`
112
+ `)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.isSidechain)continue;let u=l.message?.content;if(!Array.isArray(u))continue;let f=l.timestamp?Date.parse(l.timestamp):null;for(let d of u)if(!(!d||typeof d!="object"))if(d.type==="tool_use"&&d.id){if(d.name==="Agent"){let p=d.input||{};o.set(d.id,{id:d.id,kind:"agent",name:String(p.description||"").trim()||null,detail:String(p.subagent_type||"").trim()||null,ts:f,proven:!1})}else if(d.name==="Bash"&&d.input?.run_in_background===!0){let p=String(d.input.command||"").trim();o.set(d.id,{id:d.id,kind:"command",name:String(d.input.description||"").trim()||(p?io(p):null),detail:p?io(p):null,ts:f,proven:!0})}}else d.type==="tool_result"&&d.tool_use_id&&sR.test(aR(d.content))&&s.add(d.tool_use_id)}let a=[];for(let i of o.values()){if(!i.proven&&!s.has(i.id))continue;let{proven:c,...l}=i;a.push(l)}return a.slice(-n)}var sR,aR,Hg=M(()=>{ye();co();sR=/^Async (?:agent|task) launched/i,aR=t=>{if(typeof t=="string")return t.trim();if(!Array.isArray(t))return"";let e=t.find(n=>n&&n.type==="text"&&typeof n.text=="string");return e?e.text.trim():""}});function Nn(t,e){if(!t)return null;let n=String(t);if(e){let o=e.endsWith("/")?e:`${e}/`;if(n===e)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 iR(t){let e=typeof t=="string"?t:String(t?.patch??t?.input??""),n=[];for(let r of e.matchAll(/^\*{3} (?:Update|Add|Delete) File: (.+)$/gm))n.push(r[1].trim());return n}function Wg(t,e,n){switch(t){case"Shell":{let r=String(e?.command||"").trim();return r?{command:r,description:String(e?.description||"").trim()}:null}case"Read":{let r=e?.path;if(!r)return null;let o=Number(e?.offset)||null,s=o&&Number(e?.limit)?o+Number(e.limit)-1:null;return{command:ke(`read ${Nn(r,n)}${o?` (lines ${o}\u2013${s??"end"})`:""}`,140),description:o?`Read lines ${o}\u2013${s??"end"} of ${mo(r)}`:`Read ${mo(r)}`}}case"Grep":{let r=e?.pattern;if(!r)return null;let o=e?.path?Nn(e.path,n):null,s=e?.glob?` --glob ${td(e.glob)}`:"",a=ke(String(r),40);return{command:ke(`grep ${td(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=e?.glob_pattern;if(!r)return null;let o=e?.target_directory?Nn(e.target_directory,n):null;return{command:ke(`glob ${td(r)}${o&&o!=="."?` ${o}`:""}`,140),description:`Find files matching \u201C${ke(String(r),40)}\u201D`}}case"StrReplace":return e?.path?{command:ke(`edit ${Nn(e.path,n)}`,140),description:`Edit ${mo(e.path)}`}:null;case"Write":return e?.path?{command:ke(`write ${Nn(e.path,n)}`,140),description:`Write ${mo(e.path)}`}:null;case"Delete":return e?.path?{command:ke(`delete ${Nn(e.path,n)}`,140),description:`Delete ${mo(e.path)}`}:null;case"ReadLints":{let o=(Array.isArray(e?.paths)?e.paths:[]).map(s=>Nn(s,n)).filter(Boolean);return{command:ke(o.length?`lints ${o.join(" ")}`:"lints",140),description:"Check lints"}}case"ApplyPatch":{let r=iR(e);if(!r.length)return null;let o=r.length>1?` (+${r.length-1} more)`:"";return{command:ke(`apply_patch ${Nn(r[0],n)}${o}`,140),description:r.length>1?`Patch ${r.length} files`:`Patch ${mo(r[0])}`}}case"Await":{let r=e?.shell_id??e?.task_id;return{command:ke(`await ${r??"background output"}`,140),description:"Wait for a background command"}}default:return null}}var Ui,ke,mo,td,qg=M(()=>{Ui=new Set(["Shell","Read","Grep","Glob","StrReplace","Write","ReadLints","Delete","ApplyPatch","Await"]),ke=(t,e=88)=>t.length>e?`${t.slice(0,e).trimEnd()}\u2026`:t,mo=t=>String(t).replace(/\/+$/,"").split("/").pop()||String(t);td=t=>`"${String(t).replace(/"/g,'\\"')}"`});import Bs from"node:fs";import cR from"node:fs/promises";import gr from"node:path";import lR from"node:os";import uR from"node:crypto";import dR from"node:zlib";function Vg(t){let e=uR.createHash("md5").update(String(t)).digest("hex");return gr.join(fR,e)}function zg(t){try{let e=JSON.parse(Bs.readFileSync(gr.join(t,"meta.json"),"utf8"));return{createdAtMs:Number(e.createdAtMs)||null,updatedAtMs:Number(e.updatedAtMs)||Number(e.createdAtMs)||null,hasConversation:e.hasConversation===!0}}catch{return null}}function pR(t){let e=Vg(t),n;try{n=Bs.readdirSync(e,{withFileTypes:!0}).filter(o=>o.isDirectory())}catch{return null}let r=null;for(let o of n){let s=gr.join(e,o.name),a=gr.join(s,"store.db");if(!Bs.existsSync(a))continue;let i=zg(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 Hi(t,e){if(!t)return null;if(e){let n=gr.join(Vg(t),e),r=gr.join(n,"store.db");if(Bs.existsSync(r))return{id:e,dir:n,store:r,...zg(n)||{createdAtMs:null,updatedAtMs:null}}}return pR(t)}function Kg(t,e){let n=t.prepare("SELECT data FROM blobs WHERE id = ?").get(e);return n?Buffer.from(n.data):null}function mR(t){if(!t)return null;let e=t;if(e.length>1&&e[0]===31&&e[1]===139)try{e=dR.gunzipSync(e)}catch{}try{return JSON.parse(e.toString("utf8"))}catch{return null}}function hR(t){let e=[],n=0,r=t.length,o=()=>{let s=0,a=0;for(;n<r;){let i=t[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=t.subarray(n,n+c);n+=c,a===1&&c===32&&e.push(l.toString("hex"))}else if(i===0)o();else if(i===5)n+=4;else if(i===1)n+=8;else break}return e}function wR(t,e){if(!Array.isArray(t))return[];let n=[];for(let r of t){if(!r||r.type!=="tool-call"||!Ui.has(r.toolName))continue;let o=Wg(r.toolName,r.args,e);!o||!o.command||n.push({id:r.toolCallId||null,tool:r.toolName,command:o.command,description:o.description||""})}return n}async function ed(t,e){if(!Gg)return ho;let{DatabaseSync:n}=Gg,r;try{r=new n(t,{readOnly:!0})}catch{return ho}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 ho;let s;try{s=JSON.parse(Buffer.from(String(o.value),"hex").toString("utf8"))}catch{return ho}let a=s.lastUsedModel||null,i=s.latestRootBlobId?Kg(r,s.latestRootBlobId):null;if(!i)return{...ho,model:a};let c=[],l=[],u=[],f=null,d=[];for(let p of hR(i)){let h=mR(Kg(r,p));if(!h)continue;let w=h.providerOptions?.cursor;if(w?.requestId&&d.push(w.requestId),w?.modelProviderMessageId&&d.push(w.modelProviderMessageId),h.role!=="assistant")continue;if(Array.isArray(h.content))for(let x of h.content){let E=x?.providerOptions?.cursor?.modelName;E&&(f=E)}l.push(...wR(h.content,e).map((x,E)=>({...x,id:x.id||`${p}:${E}`}))),u.push(...yR(h.content));let y=gR(h.content);if(!y)continue;let k=[...new Set(u)];u=[],c.push({id:p,text:y,tools:k.length?k:void 0,commands:l,model:f}),l=[]}return{turns:c,trailingCommands:l,model:a,requestIds:d}}catch{return ho}finally{try{r.close()}catch{}}}function Jg(t,e){let n=t.updatedAtMs;if(!n)try{n=Math.round(Bs.statSync(t.store).mtimeMs)}catch{n=Date.now()}let r=t.createdAtMs;(!r||r>n)&&(r=n-e*1e3);let o=Math.max(0,n-r);return{end:n,tsAt:s=>Math.round(r+o*(s+1)/e)}}async function Yg(t,e,{limit:n=80}={}){let r=Hi(t,e);if(!r)return[];let{turns:o,model:s}=await ed(r.store,t);if(!o.length)return[];let a=o.slice(-n),{tsAt:i}=Jg(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 Xg(t,e){let n=Hi(t,e);if(!n)return null;let{turns:r,requestIds:o,model:s}=await ed(n.store,t);return{chatId:n.id,requestIds:o,models:[...new Set(r.map(a=>a.model).filter(Boolean))],configuredModel:s,updatedAtMs:n.updatedAtMs||null}}async function Zg(t,e,{limit:n=80}={}){let r=Hi(t,e);if(!r)return[];let{turns:o,trailingCommands:s}=await ed(r.store,t);if(!o.length&&!s.length)return[];let a=o.slice(-n),{end:i,tsAt:c}=Jg(r,a.length||1),l=[];a.forEach((u,f)=>{for(let d of u.commands)l.push({...d,summary:Rn(d.command,d.description),ts:c(f)})});for(let u of s)l.push({...u,summary:Rn(u.command,u.description),ts:i+1});return l}async function Qg(t,e){let n=Hi(t,e);if(!n)return null;if(n.updatedAtMs)return n.updatedAtMs;try{return Math.round((await cR.stat(n.store)).mtimeMs)}catch{return null}}var fR,gR,yR,Gg,ho,nd=M(()=>{co();qg();fR=process.env.BOSTRAT_CURSOR_CHATS||gr.join(lR.homedir(),".cursor","chats");gR=t=>typeof t=="string"?t.trim():Array.isArray(t)?t.filter(e=>e&&e.type==="text"&&typeof e.text=="string").map(e=>e.text).join(`
113
+ `).trim():"",yR=t=>Array.isArray(t)?t.filter(e=>e&&e.type==="tool-call"&&e.toolName).map(e=>e.toolName):[],Gg=process.getBuiltinModule?.("node:sqlite"),ho={turns:[],trailingCommands:[],model:null,requestIds:[]}});import bR from"node:fs/promises";function ad(t){return ty.set(t.agent,t),t}function js(t){return ty.get(t)||kR}async function cd(t,e={}){return(await js(t.agent).readMessages(t,e)).map(id(t))}async function ey(t,e={}){return(await js(t.agent).readCommands(t,e)).map(id(t))}async function ny(t,e={}){return(await js(t.agent).readJobs(t,e)).map(id(t))}var wo,rd,od,sd,kR,ty,id,ry=M(()=>{ye();Ti();co();Hg();nd();lo();wo=class{constructor(e,n=new Set){this.agent=e,this.cliTools=n}async readMessages(){return[]}async readCommands(){return[]}async readJobs(){return[]}async updatedAt(){return null}},rd=class extends wo{transcript(e){return!e?.cwd||!e?.sessionId?null:Ge(e.cwd,e.sessionId)}async readMessages(e,n){let r=this.transcript(e);return r?cu(r,n):[]}async readCommands(e,n){let r=this.transcript(e);return r?Ow(r,n):[]}async readJobs(e,n){let r=this.transcript(e);return r?Ug(r,n):[]}async updatedAt(e){let n=this.transcript(e);if(!n)return null;try{return Math.round((await bR.stat(n)).mtimeMs)}catch{return null}}},od=class extends wo{async readMessages(e,n){return Yg(e.cwd,e.sessionId,n)}async readCommands(e,n){return Zg(e.cwd,e.sessionId,n)}async updatedAt(e){return Qg(e.cwd,e.sessionId)}},sd=class extends wo{sessionId(e){return e?.pinned?e.sessionId:null}async readMessages(e,n){return Pw(e.cwd,this.sessionId(e),n)}async readCommands(e,n){return Dw(e.cwd,this.sessionId(e),n)}async updatedAt(e){return Bw(e.cwd,this.sessionId(e))}},kR=new wo("unknown"),ty=new Map;ad(new rd("claude",Eu));ad(new od("cursor",Ui));ad(new sd("codex",Cs));id=t=>e=>({...e,box:t.name,agent:t.agent,boxRole:t.role})});function kr(t){let e=t.search(fd);return(e>=0?t.slice(0,e):t).trim()}function xR(t){if(!t)return"";let e=t.replace(/[│┌└├─┘┤┬┴┼─✂].*$/,"").trim();return!e||/hidden|\d+\s+lines?/i.test(e)?"":e}function SR(t){let e=String(t).trim();return!!(!e||br.test(t)||fd.test(e)||/hidden|\d+\s+lines?/i.test(e)||/notespress|press n to add/i.test(e)||/^\s*notes?\s*$/i.test(e))}function vR(t,e=""){let n=[],r=/([☐☒])\s+([^☐☒←→✔]+)/g,o;for(;(o=r.exec(t))!==null;)n.push({label:o[2].trim(),answered:o[1]==="\u2612",current:!1});if(!n.length)return null;let s=TR(n,e);return n.forEach((a,i)=>{a.current=i===s}),{tabs:n,questionIndex:s,questionTotal:n.length,currentTabLabel:n[s].label}}function TR(t,e){let n=String(e).toLowerCase(),r=t.findIndex(c=>!c.answered),o=r>=0?r:t.length-1;if(!n)return o;let s=t.map(c=>{let l=c.label.toLowerCase(),u=l.split(/\s+/).filter(d=>d.length>3&&n.includes(d)).length;if(u)return u;let f=l.slice(0,8).trim();return f.length>=4&&n.includes(f)?1:0}),a=Math.max(...s);if(a===0||s[o]===a)return o;let i=s.flatMap((c,l)=>c===a?[l]:[]);return i.length===1?i[0]:o}function sy(t){return t.replace(/[←→✔☐☒●▶]/g," ").replace(/\bSubmit\b/g," ").replace(/\s+/g," ").trim()}function AR(t,e=""){let n=String(t);if(!iy.test(n))return null;let r=n.replace(/\r/g,"").split(`
114
+ `),o=-1;for(let u=r.length-1;u>=0;u--)if(/^\s*Switch model\?\s*$/.test(r[u])){o=u;break}if(o<0)return null;let s=[],a=[];for(let u=o+1;u<r.length;u++){let f=r[u].match(yr);if(f)s.push({cursor:!!f[1],label:f[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let d=r[u].trim();d&&!br.test(r[u])&&a.push(d)}}if(s.length<2)return null;let i=s.map(u=>({label:kr(u.label),description:""})),c=Math.max(0,s.findIndex(u=>u.cursor)),l=["Switch model?",...a].join(" ");return{provider:"claude",box:e,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 _R(t,e=""){let n=String(t).replace(/\r/g,"").split(`
115
+ `),r=n.length-1;for(;r>=0&&n[r].trim()==="";)r--;if(r<0||!cy.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(yr);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&&!(ER.test(n[c])||br.test(n[c]));c--){let l=n[c].trim();l&&a.unshift(l)}let i=s.map(c=>({label:kr(c.label),description:""}));return{provider:"claude",box:e,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 IR(t,e=""){let n=String(t);if(!/ready to submit your answers/i.test(n))return null;let r=n.replace(/\r/g,"").split(`
116
+ `),o=[];for(let c=0;c<r.length;c++){let l=r[c].match(yr);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:e,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 $R(t,e=""){let n=String(t);if(!ld.test(n))return null;let r=n.replace(/\r/g,"").split(`
117
+ `),o=-1;for(let u=r.length-1;u>=0;u--)if(RR.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 f=r[u].match(yr);if(f)s.push({cursor:!!f[1],label:f[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let d=r[u].trim();d&&!br.test(r[u])&&a.push(d)}}if(s.length<2||!s.some(u=>ld.test(u.label)))return null;let i=s.map(u=>({label:kr(u.label),description:""})),c=Math.max(0,s.findIndex(u=>u.cursor)),l=a.join(" ");return{provider:"claude",box:e,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 pd(t){let e=[];for(let r=0;r<t.length;r++){let o=t[r].match(yr);o&&e.push({line:r,cursor:!!o[1],n:Number(o[2]),label:o[4].trim()})}let n=e.sort((r,o)=>r.n-o.n);return n.length<2||n.some((r,o)=>r.n!==o+1)?null:n}function OR(t,e=""){let n=String(t);if(!ly.test(n)||!uy.test(n)||xr.test(n))return null;let r=n.replace(/\r/g,"").split(`
118
+ `),o=pd(r);return o?{provider:"claude",box:e,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:kr(s.label),description:""}))}]}:null}function CR(t,e=""){let n=String(t);if(!dy.test(n)||xr.test(n))return null;let r=n.replace(/\r/g,"").split(`
119
+ `),o=pd(r);if(!o)return null;let s=o.map(a=>{let[i,...c]=a.label.split("\xB7");return{label:kr(i),description:c.join("\xB7").trim()}});return{provider:"claude",box:e,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 NR(t,e){let n=t[e].trim();for(let r=e+1;r<t.length;r++){let o=t[r].trim();if(!o||!MR.test(o)||md.test(t[r]))break;n+=o}return n}function PR(t,e=""){let n=String(t);if(!md.test(n)||xr.test(n))return null;let r=n.replace(/\r/g,"").split(`
120
+ `),o="";for(let s=0;s<r.length;s++)if(/^\s*https:\/\//.test(r[s])){o=NR(r,s);break}return o?{provider:"claude",box:e,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 BR(t,e=""){let n=String(t);if(!ud.test(n)||!DR.test(n)||xr.test(n))return null;let s=([...n.replace(/\r/g,"").split(`
121
+ `)].reverse().find(a=>ud.test(a))||"OAuth error").trim();return{provider:"claude",box:e,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 jR(t,e=""){let n=String(t);if(!fy.test(n)||xr.test(n))return null;let r=n.replace(/\r/g,"").split(`
122
+ `),o=pd(r);return o?{provider:"claude",box:e,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:kr(s.label),description:""}))}]}:null}function LR(t,e=""){let n=String(t);if(xr.test(n))return null;let r=n.replace(/\r/g,"").split(`
123
+ `),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(py);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(br.test(r[l])||fd.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:e,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 FR(t){let e=-1;for(let r=t.length-1;r>=0;r--)if(dd.test(t[r])){e=r;break}if(e<0)return null;let n=-1;for(let r=e-1;r>=0;r--)if(/[☐☒]/.test(t[r])){n=r;break}return n<0?null:{headerLine:n,chatLine:e,optStart:n+1,optEnd:e}}function UR(t,e=""){let n=String(t);if(!ay.test(n)||!dd.test(n))return null;let r=n.replace(/\r/g,"").split(`
124
+ `),o=FR(r);if(!o)return null;let{headerLine:s,chatLine:a,optStart:i,optEnd:c}=o,l=[],u=-1;for(let T=i;T<c;T++){let D=r[T].match(yr);D&&(u<0&&(u=T),l.push({line:T,cursor:!!D[1],checked:D[3]!=null&&D[3]!==" ",hasCheckbox:D[3]!=null,label:D[4].trim(),desc:""}))}if(!l.length)return null;for(let T of l)for(let D=T.line+1;D<Math.min(r.length,T.line+4)&&!(yr.test(r[D])||br.test(r[D]));D++){let j=r[D].trim();if(!(!j||SR(r[D])||oy.test(j))){T.desc=xR(j);break}}let f=l.filter(T=>!oy.test(T.label));if(!f.length)return null;let d=f.some(T=>T.hasCheckbox),p=Math.max(0,f.findIndex(T=>T.cursor)),h=s>=0?s+1:0,w=[];for(let T=h;T<u;T++){let D=r[T].trim();D&&!br.test(r[T])&&!/[☐☒]/.test(r[T])&&w.push(D)}let y=w.join(" ")||(s>=0?sy(r[s]):"")||"The agent is asking a question",k=s>=0?vR(r[s],y):null,x=k?.currentTabLabel||(s>=0?sy(r[s]):""),E=f.map(T=>({label:kr(T.label),description:T.desc})),O=E.map(T=>T.label).join("|"),C=`claude:${k?`q${k.questionIndex+1}/${k.questionTotal}`:"q1/1"}:${x}:${y}:${O}`.slice(0,240),N=k?`claude:ask:${k.tabs.map(T=>T.label).join("|")}`.slice(0,240):C;return{provider:"claude",box:e,multiSelect:d,cursorIndex:p,promptId:C,groupId:N,...k?{questionIndex:k.questionIndex,questionTotal:k.questionTotal,currentTabLabel:k.currentTabLabel,tabs:k.tabs}:{},questions:[{question:y,header:x,multiSelect:d,options:E}]}}function go(t,e){let n=String(e||"");return n?t==="claude"?ay.test(n)&&dd.test(n)||iy.test(n)||ld.test(n)||cy.test(n.trimEnd().split(`
125
+ `).pop()||"")?!0:xr.test(n)?!1:ly.test(n)&&uy.test(n)||dy.test(n)||md.test(n)||ud.test(n)||fy.test(n)||py.test(n.trimEnd().split(`
126
+ `).pop()||""):t==="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:t==="cursor"||t==="codex"?/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i.test(n):!1:!1}function Sr(t,e){return!t||!e?null:t.agent==="claude"?IR(e,t.name)||UR(e,t.name)||AR(e,t.name)||$R(e,t.name)||BR(e,t.name)||PR(e,t.name)||CR(e,t.name)||OR(e,t.name)||jR(e,t.name)||LR(e,t.name)||_R(e,t.name):t.agent==="cursor"||t.agent==="codex"?lw(t.agent,e,t.name):null}async function hd(t){if(!t)return null;let e=await En(t.name).catch(()=>"");return Sr(t,e)}function my(t,e){let n=Array.isArray(e?.[0])?e[0].filter(a=>Number.isInteger(a)&&a>=0):[],r=Number.isInteger(t?.cursorIndex)?t.cursorIndex:0,o=(a,i)=>{let c=i-a;return Array.from({length:Math.abs(c)},()=>c>0?"Down":"Up")},s=[];if(t?.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 hy(t,e){let n=Number.isInteger(t?.questionIndex)?t.questionIndex:0,o=(Number.isInteger(e)?e:n)-n;if(!o)return[];let s=o>0?"Tab":"BTab";return Array.from({length:Math.abs(o)},()=>s)}var ay,dd,yr,oy,br,fd,iy,cy,ER,ld,RR,xr,ly,uy,dy,md,MR,ud,DR,fy,py,wd=M(()=>{qt();Ai();ay=/to navigate\b.*\bEsc to cancel|Enter to select\b/,dd=/Chat about this/i,yr=/^\s*(❯)?\s*(\d+)\.\s+(?:\[([ xX✔])\]\s+)?(.+?)\s*$/,oy=/^(type something|chat about this|submit)\b/i,br=/^[─—-]{6,}\s*$/,fd=/[\u2500-\u257F\u2550-\u256F┌┐└┘├┤│┬┴┼─✂]/;iy=/^\s*Switch model\?\s*$/m;cy=/^\s*Enter to confirm\s*·\s*Esc to cancel\s*$/,ER=/^\s*[─—▔-]{6,}\s*$/;ld=/Resume from summary/i,RR=/^\s*This session is\b/;xr=/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/;ly=/Choose the text style that looks best with your terminal/,uy=/Let's get started\./;dy=/Select login method:/;md=/Paste code here if prompted/,MR=/^[A-Za-z0-9%&=+._~#?/:\-]+$/;ud=/OAuth error:/,DR=/Press Enter to retry\./;fy=/Quick safety check: Is this a project you created or one you trust/;py=/^(.{0,60}?)Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/});function Wi(t,e,n){if(!t||!e)return null;for(let r of HR)if(r.provider===t.agent)try{if(r.match(e,n))return r}catch{}return null}function qR(t){let e=gd.get(t);return e||(e={sentAt:[],last:0,emitted:new Set},gd.set(t,e)),e}function yy(t,e,n=Date.now()){let r=qR(t);if(r.sentAt=r.sentAt.filter(s=>n-s<gy),r.sentAt.length>=wy)return{action:"give-up"};if(n-r.last<WR)return{action:"wait"};r.last=n,r.sentAt.push(n);let o=!r.emitted.has(e);return o&&r.emitted.add(e),{action:"send",first:o}}function by(t,e=Date.now()){let n=gd.get(t);return n?n.sentAt.filter(r=>e-r<gy).length>=wy:!1}var HR,WR,wy,gy,gd,yd=M(()=>{HR=[{provider:"claude",id:"fullscreen-upsell",match(t,e){let n=t?.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||""}
127
+ ${String(e||"")}`;return/Try the new fullscreen renderer|Flicker-free output/i.test(o)},keys:["Escape"]}];WR=5e3,wy=5,gy=3600*1e3,gd=new Map});function yo(t){return typeof t=="string"?t.trim():""}var ky=M(()=>{});import{execFile as KR}from"node:child_process";import{promisify as GR}from"node:util";async function _t(t,e,{input:n}={}){let r=kd("git",["-C",t,...e],{maxBuffer:xy});return n!==void 0&&r.child.stdin&&(r.child.stdin.on("error",()=>{}),r.child.stdin.end(n)),r}async function qi(t){if(!t)return!1;try{let{stdout:e}=await _t(t,["rev-parse","--is-inside-work-tree"]);return e.trim()==="true"}catch{return!1}}async function Sy(t){let{stdout:e}=await _t(t,["rev-parse","--show-toplevel"]);return e.trim()}async function VR(t){try{return await _t(t,["rev-parse","--verify","HEAD"]),!0}catch{return!1}}async function bo(t,e="bostrat: subtask snapshot"){let{stdout:n}=await _t(t,["rev-parse","--absolute-git-dir"]),r=`${n.trim()}/bostrat-snapshot-index`,o={...process.env,GIT_INDEX_FILE:r},s=(a,i)=>kd("git",["-C",t,...a],{maxBuffer:xy,env:o,...i});try{let a=await VR(t);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",e]:["commit-tree",c,"-m",e],{stdout:u}=await s(l);return u.trim()}finally{try{await kd("rm",["-f",r])}catch{}}}async function xd(t,e){let{stdout:n}=await _t(t,["status","--porcelain"]);return n.trim()?(await _t(t,["add","-A"]),await _t(t,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","-m",e]),!0):!1}async function Sd(t,{ignorePlumbing:e=!1}={}){let{stdout:n}=await _t(t,["status","--porcelain"]),r=n.split(`
128
+ `).filter(Boolean);return e&&(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 vd(t,e){if(!e)return 0;try{let{stdout:n}=await _t(t,["rev-list","--count",`${e}..HEAD`]);return Number(n.trim())||0}catch{return 0}}async function ko(t,e,n,r){return await _t(t,["worktree","add","--no-track","-b",n,e,r]),e}async function vy(t,e){try{return await _t(t,["rev-parse","--verify","--quiet",`refs/heads/${e}`]),!0}catch{return!1}}async function Ki(t,e,n){return await _t(t,["worktree","add",e,n]),e}async function xo(t){if(process.env.BOSTRAT_TRACK_BASE_REF)return process.env.BOSTRAT_TRACK_BASE_REF;try{let{stdout:e}=await _t(t,["symbolic-ref","--short","refs/remotes/origin/HEAD"]);if(e.trim())return e.trim()}catch{}for(let[e,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 _t(t,["rev-parse","--verify","--quiet",e]),n}catch{}return"HEAD"}async function Td(t){await _t(t,["init","-q"]),await _t(t,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","--allow-empty","-qm","bostrat: track workspace"])}async function re(t,e){try{await _t(t,["worktree","remove","--force",e])}catch{try{await _t(t,["worktree","prune"])}catch{}}}function zR(t){let e=/(\d+) files? changed/.exec(t),n=/(\d+) insertions?\(\+\)/.exec(t),r=/(\d+) deletions?\(-\)/.exec(t);return{files:e?Number(e[1]):0,insertions:n?Number(n[1]):0,deletions:r?Number(r[1]):0}}function Ad(t,e){return!e||!e.length?t:[...t,"--",".",...e.map(n=>`:(exclude)${n}`)]}async function Ed(t,e,n,r){let{stdout:o}=await _t(t,Ad(["diff","--shortstat",e,n],r));return zR(o)}async function _d(t,e,n,r){let{stdout:o}=await _t(t,Ad(["diff","--name-only",e,n],r));return o.split(`
129
+ `).map(s=>s.trim()).filter(Boolean)}async function Id(t,e,n,r){let{stdout:o}=await _t(t,Ad(["diff","--binary",e,n],r));if(!o.trim())return{applied:!0,empty:!0,conflicts:[]};if((await bd(t,o,["--whitespace=nowarn"])).ok)return{applied:!0,empty:!1,conflicts:[]};let s=await bd(t,o,["--3way","--whitespace=nowarn"]),a=await JR(t);return a.length>0?{applied:!1,empty:!1,conflicts:a}:s.ok?{applied:!0,empty:!1,conflicts:[]}:(await bd(t,o,["--reject","--whitespace=nowarn"]),{applied:!1,empty:!1,conflicts:[`patch did not apply cleanly: ${s.err}`]})}async function bd(t,e,n){try{return await _t(t,["apply",...n,"-"],{input:e}),{ok:!0}}catch(r){return{ok:!1,err:r?.stderr?.trim()||r?.message||String(r)}}}async function JR(t){try{let{stdout:e}=await _t(t,["diff","--name-only","--diff-filter=U"]);return e.split(`
130
+ `).map(n=>n.trim()).filter(Boolean)}catch{return[]}}var kd,xy,Rd=M(()=>{kd=GR(KR),xy=64*1024*1024});import $d from"node:fs/promises";import Ay from"node:path";import YR from"node:os";function Ry(t){let e=new Date(t);return e.setHours(0,0,0,0),e.setDate(e.getDate()-(e.getDay()+6)%7),e.getTime()}function $y(t){let e=new Date(t);return e.setHours(0,0,0,0),e.setDate(1),e.getTime()}function Oy(t){let e=new Date(Ry(t));return e.setDate(e.getDate()+7),e.getTime()}function Cy(t){let e=new Date($y(t));return e.setMonth(e.getMonth()+1),e.getTime()}function Vi(t=Date.now()){for(let[e,n]of Object.entries(So)){let r=n.startOf(t);if(r!==ze[e]){ze[e]=r;for(let o of vr.values())o[e]=0;for(let o of vo)o.includes(`:${e}:`)&&!o.endsWith(`:${r}`)&&vo.delete(o)}}}function My(t,e){let n=xe?.caps?.[t]?.[So[e].capKey];return Number.isFinite(n)&&n>0?n:null}function Tr(t,e=Date.now()){if(!t||!Cd||!xe?.caps)return null;Vi(e);let n=vr.get(t);for(let r of Object.keys(So)){let o=My(t,r);if(o==null)continue;let s=n?.[r]||0;if(s>=o)return{provider:t,window:r,limitUsd:o,spentUsd:Gi(s),resetsAt:So[r].nextStart(e)}}return null}function Ny(t,e){let n=`hit:${t}:${e.provider}:${e.window}:${ze[e.window]}`;return vo.has(n)?!1:(vo.add(n),!0)}function Ty(t,e,n,r=Date.now()){if(!t||!e)return;Vi(r);let o=XR(t);for(let[s,a]of Object.entries(So))n>=ze[s]&&n<a.nextStart(r)&&(o[s]+=e)}async function ZR(t,e,n=Date.now()){if(!xe?.caps||!Od)return;let r=vr.get(t);if(r)for(let[o,s]of Object.entries(So)){let a=My(t,o);if(a==null)continue;let i=r[o]||0;if(i<a*Iy||i>=a)continue;let c=`warn:${t}:${o}:${ze[o]}`;if(!vo.has(c)){vo.add(c);try{let l=await Od(e);if(!l)continue;await I(l,{type:"usage.cap.warning",actor:"system",provider:t,payload:{provider:t,window:o,limitUsd:a,spentUsd:Gi(i),pct:Math.round(i/a*100),resetsAt:s.nextStart(n)}})}catch{}}}}function Py(t){let e={};for(let[n,r]of Object.entries(t||{})){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&&(e[n]=o)}return e}async function zi(t,{source:e="local",updatedAt:n=Date.now()}={}){xe={caps:Py(t),updatedAt:n,source:e};try{await $d.mkdir(Ey,{recursive:!0}),await $d.writeFile(_y(),JSON.stringify(xe,null,2))}catch{}return Ls()}function Ls(t=Date.now()){Vi(t);let e=new Set([...vr.keys(),...Object.keys(xe?.caps||{})]),n={};for(let r of e){let o=vr.get(r);n[r]={weeklyUsd:Gi(o?.weekly||0),monthlyUsd:Gi(o?.monthly||0)}}return{caps:xe?.caps||{},configured:!!xe,seeded:Cd,updatedAt:xe?.updatedAt??null,spent:n,windows:{weekly:{start:ze.weekly,resetsAt:Oy(t)},monthly:{start:ze.monthly,resetsAt:Cy(t)}},warnPct:Iy}}async function Dy({listTracks:t,getTrack:e}={}){Od=e||null,Vi();try{let o=JSON.parse(await $d.readFile(_y(),"utf8"));xe={caps:Py(o?.caps),updatedAt:o?.updatedAt??null,source:o?.source??"file"}}catch{xe=null}let n=Date.now();Zt.on("event",o=>{if(o?.type!=="cost.recorded")return;let{usd:s}=Ve(o);Ty(o.provider||"unknown",s,o.ts??Date.now()),ZR(o.provider||"unknown",o.trackId).catch(()=>{})});let r=Math.min(ze.weekly,ze.monthly);for(let o of await t?.()||[]){let s;try{s=await F(o)}catch{continue}for(let a of s){if(a.type!=="cost.recorded")continue;let i=a.ts??0;i<r||i>=n||Ty(a.provider||"unknown",Ve(a).usd,i,n)}}return Cd=!0,Ls()}var Ey,_y,Iy,So,xe,Cd,ze,vr,vo,Od,XR,Gi,Ji=M(()=>{at();wr();Ey=process.env.BOSTRAT_STATE_DIR||Ay.join(process.env.HOME||YR.tmpdir(),".bostrat"),_y=()=>Ay.join(Ey,"usage-caps.json"),Iy=.8;So={weekly:{startOf:Ry,nextStart:Oy,capKey:"weeklyUsd"},monthly:{startOf:$y,nextStart:Cy,capKey:"monthlyUsd"}},xe=null,Cd=!1,ze={weekly:0,monthly:0},vr=new Map,vo=new Set,Od=null,XR=t=>{let e=vr.get(t);return e||(e={weekly:0,monthly:0},vr.set(t,e)),e};Gi=t=>Math.round(t*1e4)/1e4});import QR from"node:fs/promises";import t$ from"node:os";import By from"node:path";function qy(t){return t==="codex"?o$:t==="cursor"?Wy:Uy}function jy(t){let e=String(t||"").split(`
131
+ `),n=e.findIndex(o=>/Select Model and Effort/i.test(o));if(n<0)return null;let r=[];for(let o=n+1;o<e.length;o++){let s=e[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(e[o]))break}return r.length?r:null}function Ly(t){let e=String(t||"").split(`
132
+ `),n=e.findIndex(o=>/Select Reasoning Level/i.test(o));if(n<0)return null;let r=[];for(let o=n+1;o<e.length;o++){let s=e[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(e[o]))break}return r.length?r:null}function s$(t){let e=String(t||"").split(`
133
+ `);for(let n=e.length-1;n>=0;n--){let r=e[n].match(/Model changed to\s+(\S+)(?:\s+(\S+))?\s*$/i);if(r)return{model:r[1],effort:r[2]||null}}return null}function Fy(t){let e=String(t||"").split(`
134
+ `),n=e.findIndex(s=>/Available models|Models matching/i.test(s));if(n<0)return null;let r=/Models matching/i.test(e[n]),o=[];for(let s=n+1;s<e.length;s++){let a=e[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 Ky(t,e){if(typeof e!="string"||!e.trim())throw new Error("model (string) required");let n=e.trim();if(t==="codex"){let[r,o]=n.split(/[\s:]+/);if(o&&!Hy.has(o))throw new Error(`unknown codex effort "${o}" (low | medium | high | xhigh)`);return{model:r,effort:o||null}}if(t==="cursor"){let r=Wy.find(o=>o.alias===n);return{model:n,filter:r?r.label:n}}if(!r$.has(n))throw new Error(`unknown model "${n}"`);return{model:n}}async function Fs(t,e,{timeoutMs:n=e$}={}){let r=Date.now()+n;for(;;){let o=await Tt(t,{lines:80}).catch(()=>""),s=e(o);if(s)return s;if(Date.now()>r)return null;await Yi(n$)}}async function a$(t,e){return await Pt(t,`/model ${e.model}`,$e("claude")),{verified:!1,note:"confirmed when the next turn's transcript model flips"}}async function i$(t,e){await ki(t),await Pt(t,"/model",{enter:!1}),await Yi(250),await It(t,["Enter"],{kind:"model-switch"});let n=await Fs(t,jy);if(!n)throw new Error("codex model picker didn't open");let r=n.find(i=>i.id===e.model);if(!r)throw await It(t,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`unknown model "${e.model}" \u2014 codex offers: ${n.map(i=>i.id).join(", ")}`);let o=i=>{let c=s$(i);return!c||c.model!==e.model||e.effort&&c.effort&&c.effort.toLowerCase()!==e.effort.toLowerCase()?null:c};await Pt(t,String(r.n),{enter:!1,kind:"model-switch"});let s=await Fs(t,i=>Ly(i)||!jy(i)&&o(i)&&{done:o(i)});if(!s)throw await It(t,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error("codex reasoning-level picker didn't open");if(!s.done){let i=e.effort?Hy.get(e.effort):null,c=i?s.find(l=>l.label.toLowerCase()===i.toLowerCase()):s.find(l=>l.isDefault)||s[0];if(!c)throw await It(t,["Escape","Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`codex doesn't offer effort "${e.effort}" for ${e.model}`);await Pt(t,String(c.n),{enter:!1,kind:"model-switch"})}let a=s.done||await Fs(t,i=>!Ly(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 c$(){let t=By.join(process.env.CURSOR_CONFIG_DIR||By.join(t$.homedir(),".cursor"),"cli-config.json");try{return JSON.parse(await QR.readFile(t,"utf8"))?.model||null}catch{return null}}async function l$(t,e){await ki(t),await Si(t,`/model ${e.filter}`,{kind:"model-switch"});let n=await Fs(t,Fy),r=c=>String(c||"").toLowerCase(),o=c=>r(c.label).startsWith(r(e.filter)),s=n?.rows.find(c=>c.active)||null;if(n&&!(s&&o(s)))for(let c=0;c<12;c++){let l=await Fs(t,Fy,{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 It(t,["Down"],{kind:"model-switch"}),await Yi(250)}if(!n||!s||!o(s)){await It(t,["Escape"],{kind:"model-switch"}).catch(()=>{});let c=Array(`/model ${e.filter}`.length).fill("BSpace");throw await It(t,c,{settleMs:15,kind:"model-switch"}).catch(()=>{}),new Error(n?`cursor picker has no model matching "${e.filter}"`:"cursor model picker didn't open")}await It(t,["Enter"],{kind:"model-switch"}),await Yi(800);let a=await c$();return{verified:!!a&&(a.modelId===e.model||a.displayModelId===e.model||r(a.displayName).startsWith(r(e.filter))),model:a?.modelId||null,note:"cursor applies this as the global default for new sessions too"}}async function Gy(t,e,n){return t==="codex"?i$(e,n):t==="cursor"?l$(e,n):a$(e,n)}var Yi,e$,n$,Uy,r$,o$,Hy,Wy,Vy=M(()=>{qt();_s();Yi=t=>new Promise(e=>setTimeout(e,t)),e$=Number(process.env.BOSTRAT_MODEL_PICKER_TIMEOUT_MS)||8e3,n$=300,Uy=[{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"}],r$=new Set([...Uy.map(t=>t.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"]),o$=[{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"}],Hy=new Map([["low","Low"],["medium","Medium"],["high","High"],["xhigh","Extra high"]]),Wy=[{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 Zi(t){let e=t||{},n=u$(e);return n&&(n.payload={ts:e.at,...n.payload}),n}function u$(t){switch(t.type){case"said":return{type:"turn.user",actor:"user",source:"orchestrator",boxId:t.box,provider:Qt(t.agent),payload:{text:t.text,boxRole:t.boxRole,...t.kind?{kind:t.kind}:{},...t.attachments?.length?{attachments:t.attachments}:{}}};case"unsaid":return{type:"turn.retracted",actor:"user",source:"orchestrator",boxId:t.box,provider:Qt(t.agent),payload:{saidTs:t.saidTs,text:t.text,boxRole:t.boxRole}};case"orchestration-prompt":return{type:"turn.user",actor:"orchestrator",source:"orchestrator",boxId:t.box,provider:Qt(t.agent),payload:{text:t.prompt,kind:t.kind,boxRole:t.boxRole}};case"lead-handoff":return{type:"handoff.done",actor:"orchestrator",source:"orchestrator",boxId:t.to,provider:Qt(t.toAgent),payload:{from:t.from,fromAgent:t.fromAgent,to:t.to,toAgent:t.toAgent,reason:t.reason,handoffStartedAt:t.handoffStartedAt,fromSessionId:t.fromSessionId,toSessionId:t.toSessionId,epoch:t.epoch,singleBox:t.singleBox,forced:t.forced,recovered:t.recovered,checkpoint:t.checkpoint}};case"lead-handoff-failed":return{type:"handoff.failed",actor:"orchestrator",source:"orchestrator",boxId:t.box,provider:Qt(t.toAgent),payload:{box:t.box,fromAgent:t.fromAgent,toAgent:t.toAgent,reason:t.reason,error:t.error,rolledBack:t.rolledBack,handoffStartedAt:t.handoffStartedAt}};case"subtask-delegated":return{type:"subtask.delegated",actor:"orchestrator",source:"orchestrator",boxId:t.to,provider:Qt(t.toAgent),payload:{task:t.task,subtaskId:t.subtaskId,reason:t.reason}};case"subtask-merged":return{type:"subtask.merged",actor:"orchestrator",source:"orchestrator",boxId:t.box||t.from,provider:Qt(t.agent),payload:{...Ar(t)}};case"subtask-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:t.box||t.to,provider:Qt(t.agent||t.toAgent),payload:{kind:"subtask-failed",...Ar(t)}};case"subtask-resumed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:t.box,provider:Qt(t.agent),payload:{change:"subtask-resumed",...Ar(t)}};case"model-change":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:t.box,payload:{change:"model",model:t.to,from:t.from??null,verified:t.verified??null}};case"codex-update":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:t.box,provider:"codex",payload:{change:"cli-update",from:t.from??null,to:t.to??null,status:t.status,...t.error?{error:t.error}:{}}};case"opened":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:t.box,payload:{change:"opened",...Ar(t)}};case"archived":case"unarchived":case"track-deleted":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:t.type,...Ar(t)}};case"rehydrated":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:t.box,provider:Qt(t.agent),payload:{change:"rehydrated"}};case"transferred-in":return{type:t.mode==="recover"?"track.recovered":"track.transferred",actor:"orchestrator",source:"orchestrator",boxId:t.box,provider:Qt(t.agent),payload:{...Ar(t)}};case"transferred-out":return null;case"retagged":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:"retagged",...Ar(t)}};case"rehydrate-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:t.box,provider:Qt(t.agent),payload:{kind:"rehydrate-failed",reason:t.reason}};default:return null}}function Yy(t,e){let n=Zi(e);if(!n)return;let r=e?.type==="track-deleted"?{id:t.id}:t;Nd(()=>I(r,n))}async function Xy(t){if(!(!t?.id||zy.has(t.id))){zy.add(t.id);try{let e=await F(t),n=new Set(e.filter(r=>r.source==="orchestrator").map(r=>`${r.type}|${r.payload?.ts??"?"}`));for(let r of t.events||[]){let o=Zi(r);!o||n.has(`${o.type}|${o.payload?.ts??"?"}`)||await I(t,o)}}catch{}}}function Ar(t){let{type:e,at:n,...r}=t;return r}function Zy(t,e,n){!n?.promptId||Md.get(t.id)===n.promptId||(Md.set(t.id,n.promptId),Nd(()=>I(t,{type:"prompt.raised",actor:"agent",source:"pane",boxId:e?.name,provider:Qt(n.provider||e?.agent),payload:{promptId:n.promptId,question:n.question||n.title||null,options:(n.options||[]).map(r=>r?.label??r).slice(0,12)}})))}function Pd(t,e,n,r={}){Md.delete(t.id),Nd(()=>I(t,{type:"prompt.answered",actor:"user",source:"orchestrator",boxId:e?.name,provider:Qt(n?.provider||e?.agent),payload:{promptId:n?.promptId,...r}}))}var Qt,Xi,Nd,Jy,zy,Md,Dd=M(()=>{at();Qt=t=>t||null;Xi=Promise.resolve(),Nd=t=>(Xi=Xi.then(t).catch(()=>{}),Xi),Jy=()=>Xi;zy=new Set;Md=new Map});function h$(t){return String(t).split(/(?<=[.?!])\s+|\n+/).map(e=>e.trim()).filter(Boolean)}function ob(t){let e=String(t||"").trim();if(!e)return null;let n=e.slice(-600);for(let r of h$(n).reverse()){if(!d$.test(r))continue;let o=r.endsWith("?")&&r.length<=m$&&p$.test(r);if(f$.test(r)||o)return r.length>200?r.slice(0,197)+"\u2026":r}return null}function sb(t){let e=String(t||""),n=[];w$.test(e)&&n.push("commit"),g$.test(e)&&n.push("rebase"),y$.test(e)&&n.push("push");let r=k$.test(e);!r&&b$.test(e)&&n.push("pr");let o=null;if(r){let s=e.match(/(?:pr|pull\s+request)\s*\(?\s*#(\d+)\)?/i)||e.match(/#(\d+)/);o={number:s?Number(s[1]):null}}return{offered:n.length?n:null,toPr:o}}function To(t,{branch:e=null,base:n=null,toPr:r=null,repos:o=null,offeredRebase:s=!1}={}){Array.isArray(t)||(t=t==="push"?["commit","push"]:["commit","push","pr"]);let a=new Set(t),i=Array.isArray(o)&&o.length>0,c=i?o.map(p=>`${p.name}/`).join(", "):null,l=e?` on this branch (${e})`:"",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 p=a.has("commit")?"the branch":`this branch${e?` (${e})`:""}`;u.push(i?`rebase ${p} in each changed checkout (${c}) onto its own base branch (fetch origin first), resolving any conflicts so both sides' intent is preserved`:`rebase ${p} 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 p=r&&!a.has("pr")?` (the open PR${r.number?` #${r.number}`:""} picks it up)`:"",h=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${h}${p}`:`push this branch${e?` (${e})`:""} from each changed checkout (${c}) to its remote${p}`):u.push(a.has("commit")||a.has("rebase")?`push it to the remote${h}${p}`:`push this branch${l} to the remote${p}`)}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 f=[];a.has("commit")||f.push("don't create any new commits \u2014 ship what's already committed"),s&&!a.has("rebase")&&f.push("don't rebase \u2014 leave the branch's history as it is"),!a.has("push")&&!a.has("pr")&&f.push("don't push"),a.has("pr")||f.push("don't open a pull request");let d=`Yes \u2014 go ahead: ${u.join(", then ")}.`;return f.length&&(d+=` ${f.join(", and ").replace(/^./,p=>p.toUpperCase())}.`),a.has("pr")&&(d+=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."),d}function ab(t,{branch:e=null,base:n=null,prNumber:r=null,offeredRebase:o=!1}={}){let s=new Set(Array.isArray(t)?t:["commit","push","pr"]),a=e?` on this branch (${e})`:"",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${e?` (${e})`:""}`} 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}`:""}${e?` and its remote branch (${e})`:" and its remote branch"} exactly as they are \u2014 don't push ${e||"the old branch"} itself.`,l}function ib(t,e=Date.now()){let n=[],r=null;for(let o of t||[]){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&&e-r.lastActivity<=x$&&n.push({box:r.box,from:r.from,to:e+1e12}),n}function cb(t,e){let n=new Set;for(let r of e||[]){if(!r.settled)continue;let o=null;for(let s of t||[])s.kind!=="message"||s.role!=="assistant"||s.box!==r.box||s.ts==null||s.ts<r.from||s.ts>r.to+S$||(!o||s.ts>=o.ts)&&(o=s);o&&n.add(o)}return n}function lb(t){let e=(Array.isArray(t)?t:[]).filter(r=>Qy[r]).map(r=>Qy[r]);return`The ship you were given the go-ahead for${e.length?` (${e.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 tb,eb,nb,rb,d$,f$,p$,m$,Qi,w$,g$,y$,b$,k$,x$,S$,Qy,Ao=M(()=>{tb=/(?<!\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,eb=/(?<!\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,nb=/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,rb=/(?<!\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,d$=new RegExp(`\\b(?:${tb}|${eb}|${nb}|${rb})\\b`,"i"),f$=/\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,p$=/^(?:commit|push|open|create|raise|rebase|ready|ok(?:ay)?\s+to|good\s+to)\b/i,m$=90;Qi=["commit","rebase","push","pr"],w$=new RegExp(`\\b(?:${tb})\\b`,"i"),g$=new RegExp(`\\b(?:${rb})\\b`,"i"),y$=new RegExp(`\\b(?:${eb})\\b`,"i"),b$=new RegExp(`\\b(?:${nb})\\b`,"i"),k$=/\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;x$=3e4;S$=2500;Qy={commit:"commit",rebase:"rebase",push:"push",pr:"open a PR"}});import v$ from"node:fs";import Bd from"node:fs/promises";import pb from"node:path";import T$ from"node:os";function wb(t,e=!1){if(!e&&t-db<A$)return;db=t;let n=JSON.stringify({windowStart:Eo,byCaller:Object.fromEntries(Je),lastHour:Pn});fb=fb.then(()=>Bd.mkdir(mb,{recursive:!0})).then(()=>Bd.writeFile(`${tc}.tmp`,n)).then(()=>Bd.rename(`${tc}.tmp`,tc)).catch(()=>{})}function gb(t){t-Eo<hb||(Pn={start:Eo,total:ec(Je),byCaller:Object.fromEntries(Je)},Pn.total&&console.log(`[github] ${Pn.total} calls last hour`,Pn.byCaller),Eo=t,Je=new Map,wb(t,!0))}function Ye(t="other",e=Date.now()){gb(e),Je.set(t,(Je.get(t)||0)+1),wb(e)}function yb(t=Date.now()){return gb(t),{windowStart:Eo,total:ec(Je),byCaller:Object.fromEntries(Je),lastHour:Pn,backoffUntil:Er>t?Er:null}}function Dn(t){return E$.test(String(t?.message||t||""))}function Bn(t,e=Date.now()){return Er<=e&&console.warn(`[github] rate limited \u2014 backing off ${ub/6e4} min:`,String(t?.message||t||"").slice(0,200)),Er=Math.max(Er,e+ub),Er}function nc(t=Date.now()){return Math.max(0,Er-t)}var mb,tc,hb,ub,A$,Eo,Je,Pn,Er,db,ec,fb,E$,Us=M(()=>{mb=process.env.BOSTRAT_STATE_DIR||pb.join(process.env.HOME||T$.tmpdir(),".bostrat"),tc=pb.join(mb,"github-metrics.json"),hb=60*6e4,ub=5*6e4,A$=6e4,Eo=Date.now(),Je=new Map,Pn=null,Er=0,db=0,ec=t=>[...t.values()].reduce((e,n)=>e+n,0);try{let t=JSON.parse(v$.readFileSync(tc,"utf8"));t?.windowStart&&(Date.now()-t.windowStart<hb?(Eo=t.windowStart,Je=new Map(Object.entries(t.byCaller||{})),Pn=t.lastHour||null):ec(new Map(Object.entries(t.byCaller||{})))&&(Pn={start:t.windowStart,total:ec(new Map(Object.entries(t.byCaller||{}))),byCaller:t.byCaller||{}}))}catch{}fb=Promise.resolve();E$=/rate limit|too quickly|abuse detection|HTTP 429/i});import _$ from"node:crypto";import rc from"node:fs/promises";import bb from"node:path";import I$ from"node:os";async function Rt(){return jn||(jd??=rc.readFile(Fd,"utf8").then(t=>({links:JSON.parse(t)?.links??{},existed:!0})).catch(()=>({links:{},existed:!1})).then(async({links:t,existed:e})=>{if(jn=t,!e&&vt()){let{records:n,source:r}=await Mt("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;jn[V(i.repo,i.number)]=i}Object.keys(jn).length&&await Ud().catch(()=>{})}}return jn}).finally(()=>jd=null),jd)}async function Ud(){let t=JSON.stringify({links:jn},null,2),e=`${Fd}.${process.pid}.tmp`;await rc.mkdir(kb,{recursive:!0}),await rc.writeFile(e,t),await rc.rename(e,Fd)}async function Dt(t){Ld=Ld.then(Ud,Ud),await Ld.catch(()=>{});let e=jn?.[t];e&&Wt("prlinks",{id:xb(t),updatedAt:Date.now(),...e},{trackId:e.trackId??null}).catch(()=>{})}async function oe({repo:t,number:e,trackId:n,url:r=null,headRef:o=null,title:s=null,source:a="matched"}){if(!t||!Number.isInteger(Number(e))||!n)return{link:null,created:!1};let i=await Rt(),c=V(t,e);return i[c]?{link:i[c],created:!1}:(i[c]={repo:t,number:Number(e),trackId:n,url:r,headRef:o,title:s,source:a,announced:R$.has(a),firstSeen:Date.now()},await Dt(V(t,e)),{link:i[c],created:!0})}async function Hs(t,e){if(!t||e==null)return null;let n=(await Rt())[V(t,e)];return!n||n.announced?null:(n.announced=!0,await Dt(V(t,e)),n)}async function Kt(t,e){return!t||e==null?null:(await Rt())[V(t,e)]??null}async function Ln(t,e,n){if(!t||e==null)return null;let r=(await Rt())[V(t,e)];return r?(r.state=n,r.resolvedAt=Date.now(),delete r.armedAt,delete r.autoMerge,delete r.archiveOnMerge,delete r.notifyOnMerge,delete r.notifyPending,await Dt(V(t,e)),r):null}async function Sb(t,e,{headSha:n=null,trackId:r=null}={}){if(!t||e==null)return null;let o=(await Rt())[V(t,e)];return o?(o.ciFix={delegatedAt:Date.now(),headSha:n,trackId:r},await Dt(V(t,e)),o):null}async function vb(t,e,{headSha:n=null,trackId:r=null}={}){if(!t||e==null)return null;let o=(await Rt())[V(t,e)];return o?(o.reconcile={delegatedAt:Date.now(),headSha:n,trackId:r},await Dt(V(t,e)),o):null}async function oc(t,e,{headSha:n=null}={}){if(!t||e==null)return null;let r=(await Rt())[V(t,e)];return!r||!r.ciFix?null:(r.ciFixAwait={since:Date.now(),trackId:r.ciFix.trackId??null,headSha:n},delete r.ciFix,await Dt(V(t,e)),r)}async function sc(t,e){if(!t||e==null)return null;let n=(await Rt())[V(t,e)];return!n||!n.ciFixAwait?null:(delete n.ciFixAwait,await Dt(V(t,e)),n)}async function ac(t,e,{headSha:n=null}={}){if(!t||e==null)return null;let r=(await Rt())[V(t,e)];return!r||!r.reconcile?null:(r.reconcileAwait={since:Date.now(),trackId:r.reconcile.trackId??null,headSha:n},delete r.reconcile,await Dt(V(t,e)),r)}async function ic(t,e){if(!t||e==null)return null;let n=(await Rt())[V(t,e)];return!n||!n.reconcileAwait?null:(delete n.reconcileAwait,await Dt(V(t,e)),n)}async function Tb(t,e,{at:n=Date.now()}={}){if(!t||e==null)return null;let r=(await Rt())[V(t,e)];return r?(r.baseFoldAt=n,await Dt(V(t,e)),r):null}async function Ab(t,e){if(!t||e==null)return null;let n=(await Rt())[V(t,e)];return!n||!n.baseFoldAt?null:(delete n.baseFoldAt,await Dt(V(t,e)),n)}async function Eb(t,e,n){if(!t||e==null||!n)return null;let r=(await Rt())[V(t,e)];return r?(r.lastHeadSha=n,await Dt(V(t,e)),r):null}async function Ws(t,e,{merge:n=null}={}){if(!t||e==null)return null;let r=(await Rt())[V(t,e)];return r?(r.armedAt=Date.now(),n&&(r.autoMerge={method:n.method||"merge",armedAt:r.armedAt}),await Dt(V(t,e)),r):null}async function _r(t,e,n=!0){if(!t||e==null)return null;let r=(await Rt())[V(t,e)];return r?(n?r.archiveOnMerge=!0:delete r.archiveOnMerge,await Dt(V(t,e)),r):null}async function qs(t,e,n=!0){if(!t||e==null)return null;let r=(await Rt())[V(t,e)];return r?(n?r.notifyOnMerge=!0:delete r.notifyOnMerge,await Dt(V(t,e)),r):null}async function _b(t,e,n){if(!t||e==null)return null;let r=(await Rt())[V(t,e)];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 Dt(V(t,e)),r}async function Ks(t,e){if(!t||e==null)return null;let n=(await Rt())[V(t,e)];return!n||!n.armedAt&&!n.autoMerge?null:(delete n.armedAt,delete n.autoMerge,delete n.archiveOnMerge,delete n.notifyOnMerge,delete n.notifyPending,await Dt(V(t,e)),n)}async function Ib(){return Object.values(await Rt()).filter(t=>!$$.has(t.state))}async function Ir(){return Object.values(await Rt()).sort((t,e)=>e.firstSeen-t.firstSeen)}async function Rb(){if(!vt())return{pushed:0,source:"unconfigured"};let{records:t,source:e}=await Mt("prlinks");if(e!=="plane"||t.length)return{pushed:0,source:e};let n=await Rt(),r=0;for(let[o,s]of Object.entries(n))await Wt("prlinks",{id:xb(o),updatedAt:Date.now(),...s},{trackId:s.trackId??null}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}var kb,Fd,V,xb,jn,jd,Ld,R$,$$,Fn=M(()=>{Sn();kb=process.env.BOSTRAT_STATE_DIR||bb.join(process.env.HOME||I$.tmpdir(),".bostrat"),Fd=bb.join(kb,"pr-links.json"),V=(t,e)=>`${t}#${Number(e)}`,xb=t=>{let e=t.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^[^A-Za-z0-9]+/,"").slice(0,55),n=_$.createHash("sha256").update(t).digest("hex").slice(0,8);return`${e||"pr"}-${n}`},jn=null,jd=null,Ld=Promise.resolve();R$=new Set(["api","observed","reconciled"]);$$=new Set(["merged","closed","lost"])});function cc(t,e,n){let{state:r,reason:o}=mu(e,n);if(r!=="unknown"){if(t){let a=Date.now();for(let[i,c]of Gs)a-c.at>=$b()&&Gs.delete(i);Gs.set(t,{busy:r==="busy",at:a})}return r==="busy"}if(o!=="narrow"||!t)return!1;let s=Gs.get(t);return s?Date.now()-s.at>=$b()?(Gs.delete(t),!1):s.busy:!1}async function Hd(t,e){let n={working:!1,prompted:!1};if(!t)return n;let r=await Tt(t,{lines:Nt}).catch(()=>"");if(!cc(t,e,r))return pw(e,r)?{working:!0,prompted:!1}:n;if(go(e,r)){let o=await En(t).catch(()=>r),s=Sr({name:t,agent:e},o);if(s)return!Wi({name:t,agent:e},s,o)||by(t)?{working:!1,prompted:!0}:{working:!1,prompted:!1}}return{working:!0,prompted:!1}}async function lc(t,e){return(await Hd(t,e)).working}var $b,Gs,uc=M(()=>{qt();Ri();wd();yd();$b=()=>Number(process.env.BOSTRAT_NARROW_CARRY_MS)||9e4,Gs=new Map});import{execFile as O$}from"node:child_process";import{promisify as C$}from"node:util";async function Wd(t,e,{midTurn:n=lc,pollMs:r=M$,capMs:o=N$}={}){let s=Date.now()+o;for(;await n(t,e).catch(()=>!1);){if(Date.now()>=s)return!1;await new Promise(a=>setTimeout(a,r))}return!0}function W$(t,e){let n=String(t||"").match(H$);return!!n&&n[1]!==e}function qd(t,e){return t.slice(e).replace(/^[\s;&|)]+/,"").replace(/"[^"]*"|'[^']*'/g,'""').split(/[;&|]/)[0]}function Nb(t){let e=String(t||""),n=e.match(j$);if(!n)return null;let r=qd(e,n.index);return F$.test(r)?null:{repo:r.match(Mb)?.[1]??null,head:r.match(U$)?.[1]??null}}function Pb(t){let e=String(t||""),n=e.match(L$);if(!n)return null;let r=qd(e,n.index),o=qd(e,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("-")){q$.has(c)&&i++;continue}s=c.replace(/^["']+|["']+$/g,"")||null;break}return{repo:r.match(Mb)?.[1]??null,selector:s,auto:/\s--auto\b/.test(r)}}async function G$(t,e,{exclude:n=()=>!1}={}){let r=async i=>{Ye("observer");let{stdout:c}=await Ob("gh",["pr","list","--repo",t,"--author","@me","--state","all","--limit","10","--json",K$],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...i}}).catch(l=>{throw Dn(l)&&Bn(l),l});return JSON.parse(c||"[]")},o=i=>(i||[]).filter(c=>Date.parse(c.createdAt)>=e-P$&&!n(c)),s=await _e({slug:t}),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 V$(t,e){if(e)return[e];let n=[];for(let r of Db(t)){let o=await lt(r).catch(()=>null);o&&!n.includes(o)&&n.push(o)}for(let r of await We().catch(()=>[])){let o=await lt(r.path).catch(()=>null);o&&!n.includes(o)&&n.push(o)}return n}function Db(t){let e=t.workspace;return e?.kind==="multi"?(e.repos??[]).map(n=>n?.base).filter(Boolean):[e?.base||t.cwd].filter(Boolean)}async function z$(t,e,n){let r=t.workspace?.branch,o=e?.head??null,s=c=>r&&c===r||o&&c===o,a=c=>o!=null&&!s(c.headRefName)||W$(c.headRefName,t.id),i=[];for(let c of await V$(t,e?.repo??null)){let l;try{l=await G$(c,n,{exclude:a})}catch{continue}for(let u of l){let f=await Kt(c,u.number);if(s(u.headRefName)){if(f&&f.trackId===t.id&&f.announced)return{settled:!0};if(f&&f.trackId!==t.id)continue;return{slug:c,pr:u}}f&&(f.trackId!==t.id||f.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 Bb(t,e,{delays:n=Cb,turnEnd:r}={}){let o=Nb(e.command);if(!o)return null;let s=!!Pb(e.command),a=`${t.id}|${e.id??e.ts??e.command}`;if(Un.has(a))return null;Un.add(a);let i=e.ts??Date.now(),c=(async()=>{try{for(let l of n){await new Promise(w=>setTimeout(w,l));let u=await z$(t,o,i).catch(()=>null);if(u?.settled)return null;if(!u)continue;let{slug:f,pr:d}=u,{link:p,created:h}=await oe({repo:f,number:d.number,trackId:t.id,url:d.url,headRef:d.headRefName,title:d.title,source:"observed"});return!h&&!(p?.trackId===t.id&&await Hs(f,d.number))?null:(await Wd(e.box,e.agent,r),await I({id:t.id,cwd:t.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:e.box??null,provider:e.agent??null,payload:{ts:Date.now(),change:"opened",number:d.number,url:d.url,title:d.title,branch:d.headRefName,repo:f,...s?{selfMerge:!0}:{}}}),d)}return null}finally{Un.delete(a)}})();return c.catch(()=>Un.delete(a)),c}function jb(t,e,{delays:n=Cb,turnEnd:r,openedWait:o}={}){let s=Pb(e.command);if(!s)return null;let a=`merge|${t.id}|${e.id??e.ts??e.command}`;if(Un.has(a))return null;Un.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 f=[];if(c)f=[c];else{let h=Db(t);if(h.length>1&&/^\d+$/.test(String(s.selector??"")))return null;for(let w of h){let y=await lt(w).catch(()=>null);y&&!f.includes(y)&&f.push(y)}}if(l||=t.workspace?.branch,!f.length||!l)return null;c=f[0];let d=async(h,w)=>{let y=await Kt(c,h.number);return y&&y.trackId!==t.id?null:(y||await oe({repo:c,number:h.number,trackId:t.id,url:h.url,headRef:h.headRefName,title:h.title,source:"merge-observed"}),await Ws(c,h.number),w&&((await F(t).catch(()=>[])).some(E=>E.type==="pr.state.changed"&&(E.payload?.change==="auto-armed"||E.payload?.change==="merged")&&E.payload?.number===h.number)||(await Wd(e.box,e.agent,r),await I({id:t.id,cwd:t.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:e.box??null,provider:e.agent??null,payload:{ts:Date.now(),change:"auto-armed",number:h.number,url:h.url,title:h.title,branch:h.headRefName,repo:c}}))),h)},p=null;for(let h of n){await new Promise(C=>setTimeout(C,h));let w=[];for(let C of f)try{Ye("observer");let{stdout:N}=await Ob("gh",["pr","view",String(l),"--repo",C,"--json",J$],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...await _e({slug:C})}}),T=JSON.parse(N||"null");T?.number&&w.push({slug:C,pr:T})}catch(N){Dn(N)&&Bn(N)}let y=w.find(C=>C.pr.state==="MERGED")??(w.length===1?w[0]:null);if(!y)continue;c=y.slug;let k=y.pr;if(!k?.number)continue;if(k.state==="CLOSED")return null;if(k.state!=="MERGED"){if(p=k,s.auto)return d(k,!0);continue}let x=await Kt(c,k.number);if(x&&x.trackId!==t.id)return null;x||await oe({repo:c,number:k.number,trackId:t.id,url:k.url,headRef:k.headRefName,title:k.title,source:"merge-observed"}),await Wd(e.box,e.agent,r);let E=await F(t).catch(()=>[]);if(E.some(C=>C.type==="pr.state.changed"&&C.payload?.change==="merged"&&C.payload?.number===k.number))return null;let O=C=>C.some(N=>N.type==="pr.state.changed"&&N.payload?.change==="opened"&&N.payload?.number===k.number),z=0;if(!O(E)){if(Nb(e.command)&&await Hs(c,k.number)){let C=Date.now();z=C+1,await I({id:t.id,cwd:t.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:e.box??null,provider:e.agent??null,payload:{ts:C,change:"opened",number:k.number,url:k.url,title:k.title,branch:k.headRefName,repo:c,selfMerge:!0}})}else if((await Kt(c,k.number))?.announced){let C=o?.capMs??D$,N=o?.pollMs??B$,T=Date.now()+C;for(;Date.now()<T&&(await new Promise(D=>setTimeout(D,N)),!O(await F(t).catch(()=>[]))););}}return await I({id:t.id,cwd:t.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:e.box??null,provider:e.agent??null,payload:{ts:Math.max(Date.now(),z),change:"merged",number:k.number,url:k.url,title:k.title,branch:k.headRefName,repo:c}}),await Ze(c,k.number).catch(()=>{}),await Xe(c,k.number).catch(()=>{}),await Ln(c,k.number,"merged"),k}return p?d(p,!1):null}finally{Un.delete(a)}})();return i.catch(()=>Un.delete(a)),i}var Ob,Cb,M$,N$,P$,D$,B$,j$,L$,F$,Mb,U$,H$,q$,K$,Un,J$,Lb=M(()=>{at();ar();Jt();Us();Fn();Rr();uc();Ob=C$(O$),Cb=[4e3,15e3,45e3],M$=2500,N$=5*6e4;P$=15e3,D$=9e4,B$=2e3,j$=/(?:^|[;&|]\s*|\)\s*)gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+create\b/,L$=/(?:^|[;&|]\s*|\)\s*)gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+merge\b/,F$=/\s--web\b/,Mb=/(?:--repo|-R)[\s=]+([\w.-]+\/[\w.-]+)/,U$=/(?:--head|-H)[\s=]+([^\s"'`;&|]+)/,H$=/^track\/.+-([0-9a-f]{8})$/;q$=new Set(["--subject","-t","--body","-b","--body-file","-F","--match-head-commit","--author-email","-A","--repo","-R"]);K$="number,url,title,headRefName,createdAt";Un=new Set;J$="number,url,title,headRefName,state"});import Y$ from"node:fs/promises";import Gd from"node:path";import X$ from"node:os";function Kd(t,e){let n=new RegExp(`\\b${e}="([^"]*)"`).exec(t);return n?n[1]:null}function dc(t){let e=Z$.exec(String(t||""));if(!e)return null;let[,n,r]=e,o=Kd(n,"from"),s=o?o.replace(/^uds:/,""):null,a=Fb(s);return{socket:s,pid:a,name:Kd(n,"from-name"),mode:Kd(n,"from-mode"),text:r.trim()}}function Fb(t){let e=/(\d+)\.sock$/.exec(String(t||""));return e?Number(e[1]):null}function Q$(){return process.env.CLAUDE_CONFIG_DIR?Gd.join(process.env.CLAUDE_CONFIG_DIR,"sessions"):Gd.join(X$.homedir(),".claude","sessions")}async function tO(t){let e=Fb(t);if(!e)return null;try{let n=await Y$.readFile(Gd.join(Q$(),`${e}.json`),"utf8"),r=JSON.parse(n);return{pid:e,sessionId:r.sessionId??null,cwd:r.cwd??null,name:r.name??null,tmux:r.tmux??null}}catch{return null}}async function Ub(t,e){let n=await tO(t?.socket),r=n?.cwd??null,o=null;if((n?.sessionId||r)&&typeof e=="function")try{o=await e(n?.sessionId??null,r)??null}catch{o=null}return{socket:t?.socket??null,pid:n?.pid??t?.pid??null,sessionId:n?.sessionId??null,cwd:r,tmux:n?.tmux??null,name:n?.name??t?.name??null,mode:t?.mode??null,trackId:o?.track?.id??null,trackName:o?.track?.name??null,boxId:o?.box?.name??null}}var Z$,Vd=M(()=>{Z$=/<cross-session-message\b([^>]*)>([\s\S]*?)<\/cross-session-message>/});import{randomUUID as eO}from"node:crypto";function Vs(t){return t.sourceId?`${t.role}|id:${t.sourceId}`:`${t.role}|${t.ts??"?"}|${String(t.text||"").slice(0,40)}`}function Hb(t){return t.id?`cmd|${t.box}|id:${t.id}`:`cmd|${t.box}|${t.ts??"?"}|${String(t.command||"").slice(0,40)}`}function Wb(t){return`job|${t.box}|id:${t.id}`}async function Jd(t){return zd.has(t.id)?zd.get(t.id):(fc.has(t.id)||fc.set(t.id,F(t).then(e=>{let n={keys:new Set,cmdN:0};for(let r of e)if((r.type==="turn.user"||r.type==="turn.agent")&&r.payload?.text!=null){let o=r.type==="turn.user"?"user":"assistant";r.payload.sourceId&&n.keys.add(Vs({role:o,sourceId:r.payload.sourceId})),n.keys.add(Vs({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(Vs({role:"user",sourceId:r.payload.sourceId})),n.keys.add(Vs({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(Hb({id:o.id,box:r.boxId,ts:o.ts,command:o.command})),Number(o.n)>n.cmdN&&(n.cmdN=Number(o.n))}else r.type==="job.started"&&r.payload?.id&&n.keys.add(Wb({id:r.payload.id,box:r.boxId}));return zd.set(t.id,n),n}).finally(()=>fc.delete(t.id))),fc.get(t.id))}async function qb(t,e){try{let n=(await Jd(t)).keys;for(let r of e||[]){if(!r||r.ts==null||!String(r.text||"").trim()&&!r.images?.length)continue;let o=Vs(r);if(n.has(o))continue;n.add(o);let s=r.role==="user"?dc(r.text):null;if(s){await I(t,{type:"peer.message",actor:"peer",source:"transcript",boxId:r.box,provider:r.agent||null,payload:{text:s.text,ts:r.ts,keyText:String(r.text||"").slice(0,40),from:await Ub(s,zs),boxRole:r.boxRole,sourceId:r.sourceId||void 0}});continue}if(await I(t,{type:r.role==="user"?"turn.user":"turn.agent",actor:r.role==="user"?"user":"agent",source:"transcript",boxId:r.box,provider:r.agent||null,payload:{text:r.text,ts:r.ts,model:r.model||null,tools:r.tools||void 0,boxRole:r.boxRole,sourceId:r.sourceId||void 0,note:r.note||void 0,images:r.images?.length?r.images:void 0}}),r.role==="assistant"&&r.box===t.leadBox&&t.workspace?.branch){let a=ob(r.text);if(a){let{offered:i,toPr:c}=sb(a),l;if(t.workspace?.kind==="multi"){let u=await _o(t).catch(()=>[]);l=u.length?u.map(f=>({name:f.name,slug:f.repo??null})):void 0}await I(t,{type:"pr.offered",actor:"agent",source:"transcript",boxId:r.box,provider:r.agent||null,payload:{offerId:eO(),ts:r.ts,excerpt:a,branch:t.workspace.branch,base:t.workspace.baseRef?.replace(/^origin\//,"")||null,boxRole:r.boxRole,offered:i||void 0,toPr:c||void 0,repos:l}})}}}}catch{}}async function Kb(t,e){try{let n=await Jd(t),r=[...e||[]].filter(o=>o&&String(o.command||"").trim()).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=Hb(o);n.keys.has(s)||(n.keys.add(s),n.cmdN+=1,await I(t,{type:"tool.called",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{id:o.id??null,tool:o.tool||null,command:o.command,description:o.description||"",summary:o.summary||o.command,ts:o.ts??null,boxRole:o.boxRole,n:n.cmdN}}),Bb(t,o),jb(t,o))}}catch{}}async function Gb(t,e){try{let n=await Jd(t),r=[...e||[]].filter(o=>o&&o.id).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=Wb(o);n.keys.has(s)||(n.keys.add(s),await I(t,{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 zd,fc,Vb=M(()=>{at();Ao();Lb();Vd();Rr();zd=new Map,fc=new Map});function nO(t){let e=[],n=null;for(let r of String(t||"").split(`
135
+ `)){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;e.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 e}async function rO(t,e){let n=`${t.id}:${e.name}`;if(!Yd.has(n)){let r=await F(t),o=new Set;for(let s of r)s.type==="cost.recorded"&&s.boxId===e.name&&s.payload?.codexTs!=null&&o.add(s.payload.codexTs);Yd.set(n,o)}return Yd.get(n)}async function zb(t,e){try{if(e?.agent!=="codex"||!e.cwd)return;let n=await mr(e.cwd,e.pinned?e.sessionId:null);if(!n)return;let r=await rO(t,e),o=nO(await Xt(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||e.model||"gpt-5.5";await I(t,{type:"cost.recorded",actor:"agent",source:"transcript",boxId:e.name,provider:"codex",payload:{usd:Cn(c,i),model:c,tokens:i,reasoningOutput:a.last.reasoningOutput||void 0,codexTs:a.ts,ts:a.ts}}),a===s&&a.contextWindow&&await I(t,{type:"context.usage",actor:"agent",source:"transcript",boxId:e.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 Yd,Jb=M(()=>{at();lo();ye();Ds();Yd=new Map});import pc from"node:fs";import Zd from"node:path";import oO from"node:os";async function iO({sinceMs:t,cookie:e,fetchImpl:n=fetch}){let r=[];for(let o=1;o<=20;o++){let s=await n(aO,{method:"POST",headers:{"content-type":"application/json",origin:"https://cursor.com",cookie:`WorkosCursorSessionToken=${e}`},body:JSON.stringify({teamId:0,startDate:String(t),endDate:String(Date.now()),page:o,pageSize:Yb})});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<Yb)break}return r}function cO(t){if(!t)return null;let e=Number(t.timestamp)||null,n=t.tokenUsage||null,r=n?{input:n.inputTokens||0,output:n.outputTokens||0,cacheRead:n.cacheReadTokens||0,cacheWrite:n.cacheWriteTokens||0}:null,o=t.conversationId||null;return{id:[o||"?",e??"?",r?`${r.input}.${r.output}.${r.cacheRead}.${r.cacheWrite}`:"?"].join(":"),conversationId:o,ts:e,model:t.model||t.modelIntent||null,kind:t.kindLabel||t.kind||null,isHeadless:t.isHeadless===!0,tokens:r,vendorCents:n?.totalCents??null,chargedCents:t.chargedCents??null}}function Zb(){try{return JSON.parse(pc.readFileSync(mc(),"utf8"))}catch{return{sinceMs:0,seen:[]}}}function uO(t){try{pc.mkdirSync(Zd.dirname(mc()),{recursive:!0});let e=mc()+".tmp";pc.writeFileSync(e,JSON.stringify(t)),pc.renameSync(e,mc())}catch{}}async function fO({fetchImpl:t,now:e=Date.now()}={}){if(Hn.rows&&e-Hn.at<lO)return Hn.rows;let n=process.env.BOSTRAT_CURSOR_USAGE_COOKIE;if(!n)return null;let r=Zb(),o=Math.max(r.sinceMs-6e4,e-24*36e5);try{let s=await iO({sinceMs:o,cookie:n,fetchImpl:t});Hn={at:e,rows:s.map(cO).filter(Boolean),error:null}}catch(s){Hn={at:e,rows:null,error:String(s?.message||s)}}return Hn.rows}async function pO(t,e){let n=`${t.id}:${e.name}`;if(!Xd.has(n)){let r=await F(t),o=new Set;for(let s of r)s.type==="cost.recorded"&&s.boxId===e.name&&s.payload?.cursorEventId&&o.add(s.payload.cursorEventId);Xd.set(n,o)}return Xd.get(n)}async function Qb(t,e,{fetchImpl:n}={}){try{if(e?.agent!=="cursor"||!e.cwd||!Xb())return;let r=await fO({fetchImpl:n});if(!r||!r.length)return;let o=await Xg(e.cwd,e.pinned?e.sessionId:null);if(!o?.chatId)return;let s=await pO(t,e),a=Zb(),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(`${t.id}:${e.name}:${l.id}`))continue;s.add(l.id),i.add(`${t.id}:${e.name}:${l.id}`),l.ts&&l.ts>c&&(c=l.ts);let u=l.model||o.models[o.models.length-1]||"cursor-unknown",f=l.tokens||null,d=l.vendorCents!=null?l.vendorCents/100:0;!d&&f&&(d=Cn(u,f)),!d&&l.chargedCents!=null&&(d=l.chargedCents/100),await I(t,{type:"cost.recorded",actor:"agent",source:"vendor",boxId:e.name,provider:"cursor",payload:{usd:d,model:u,...f?{tokens:f}:{},...l.vendorCents!=null?{vendorCents:l.vendorCents}:{},...l.chargedCents!=null?{chargedCents:l.chargedCents}:{},...l.kind?{kind:l.kind}:{},conversationId:l.conversationId,cursorEventId:l.id,ts:l.ts??void 0}})}uO({sinceMs:c,seen:[...i].slice(-dO)})}catch{}}var sO,Xb,aO,Yb,lO,Hn,mc,dO,Qd,Xd,tf=M(()=>{at();nd();Ds();sO=process.env.BOSTRAT_STATE_DIR||Zd.join(process.env.HOME||oO.tmpdir(),".bostrat"),Xb=(t=process.env)=>!!t.BOSTRAT_CURSOR_USAGE_COOKIE,aO="https://cursor.com/api/dashboard/get-filtered-usage-events",Yb=100;lO=5*6e4,Hn={at:0,rows:null,error:null},mc=()=>Zd.join(sO,"cursor-usage.json");dO=5e3;Qd=()=>({enabled:Xb(),lastPollAt:Hn.at||null,error:Hn.error}),Xd=new Map});import Xs from"node:fs/promises";import te from"node:path";import mO from"node:os";import hO from"node:net";import{randomUUID as wO}from"node:crypto";import{execFile as gO}from"node:child_process";import{promisify as yO}from"node:util";function AO(t){for(let e of cf(t))if(!sk.test(e))return e;return null}function ak(t){let e=cf(t),n=e.indexOf("--");return n===-1?e:e.slice(0,n)}function EO(t,e){let n=ak(e);for(let r=0;r<n.length;r++){let o=/^--prefix=(.+)$/.exec(n[r]);if(o)return te.resolve(t,o[1]);if(n[r]==="--prefix"&&n[r+1])return te.resolve(t,n[r+1])}return t}function IO(t){let e=!1,n=!1;for(let r of cf(t)){if(!e){if(sk.test(r))continue;e=!0;continue}if(r.startsWith("-")){let o=r.indexOf("="),s=o===-1?null:r.slice(o+1);if(s&&ef(s))return`serves the filesystem root ("${s}")`;n=o===-1;continue}if(n){if(n=!1,ef(r))return`serves the filesystem root ("${r}")`;continue}if(ef(r))return`serves the filesystem root ("${r}")`;if(_O(r))return`serves a path that escapes the workspace ("${r}")`}return null}async function $O(t,e){if(te.resolve(t)===te.resolve(e))return!0;let[n,r]=await Promise.all([hc(t),hc(e)]);return n===r}async function OO(t){let n=(await Xs.readdir(t,{withFileTypes:!0}).catch(()=>[])).filter(o=>o.isDirectory()&&!o.name.startsWith(".")&&o.name!=="node_modules");return(await Promise.all(n.map(async o=>await ik(te.join(t,o.name,of))?`./${o.name}`:null))).filter(Boolean)}async function CO(t,e){let[n,r]=await Promise.all([hc(t),hc(e)]),o=te.relative(n,r);if(o&&(o.startsWith("..")||te.isAbsolute(o)))throw Js(`serve directory escapes the Track workspace: ${e}`)}async function MO(t,e){let n=IO(e);if(n)throw Js(`refusing this view: the command ${n} \u2014 serve a build dir, not the filesystem root`);if(!await RO(t))throw Js(`serve directory does not exist: ${t}`);let r=AO(e);if(!r)return;if(!r.includes("/")&&!await Lh(r,{loginShell:!0,failOpen:!0}))throw Js(`\`${r}\` is not on the box's PATH \u2014 install it in the box first`);if(SO.test(e)||vO.has(r)||!xO.has(r)||!ak(e).includes("run")||TO.test(e))return;let o=EO(t,e);if(await ik(te.join(o,of)))return;let s=await OO(o),a=s.length?` \u2014 found one in ${s.join(", ")}; run bostrat-view from there`:"";throw Js(`no ${of} in ${o}${a}`)}async function en(){return Oe||(nf||=(async()=>{try{Oe=JSON.parse(await Xs.readFile(ok,"utf8"))}catch{Oe={views:[],adoptWatermarks:{}}}finally{nf=null}return Oe.views||=[],Oe.adoptWatermarks||={},Oe})(),nf)}async function Me(){await Yt(ok,Oe)}function tn(t,e,n={}){return I({id:t.trackId,cwd:t.cwd},{type:"view.state.changed",actor:"orchestrator",source:"orchestrator",boxId:t.box||null,payload:{ts:Date.now(),change:e,viewId:t.id,name:t.name,slug:t.slug,port:t.port,cmd:t.cmd||null,...n}}).catch(()=>{})}function uf(t){return Ys.get(t)||null}function lk(t,{name:e,box:n}={}){let r=Ys.get(t);if(r&&!r.finishedAt)throw new Error("a view is already being spun up for this Track");let o={trackId:t,name:e||"preview",box:n||null,step:"spinning-up",startedAt:Date.now(),finishedAt:null,viewId:null,error:null};return Ys.set(t,o),o}function sf(t,e){let n=Ys.get(t);n&&!n.finishedAt&&!n.viewId&&(n.viewId=e,n.step="booting")}function wc(t,{error:e=null}={}){let n=Ys.get(t);return!n||n.finishedAt?null:(n.finishedAt=Date.now(),e&&(n.error=e),n)}function uk(t){let e=[];for(let n of t?.events||[])n.type!=="view-spinup"||!n.box||!n.startedAt||!n.endedAt||e.push({box:n.box,from:n.startedAt,to:n.endedAt});return e}function af(t){return String(t||"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40).replace(/-+$/g,"")||"view"}function NO(t,e){let n=af(e),r=new Set(t.views.map(o=>o.slug));if(!r.has(n)&&!nk.has(n))return n;for(let o=2;;o++){let s=`${n}-${o}`;if(!r.has(s)&&!nk.has(s))return s}}function Zs(t,{timeoutMs:e=1200}={}){return new Promise(n=>{let r=hO.connect({port:t,host:"127.0.0.1"}),o=s=>{r.destroy(),n(s)};r.setTimeout(e,()=>o(!1)),r.once("connect",()=>o(!0)),r.once("error",()=>o(!1))})}async function df(t){if(process.platform!=="darwin"){await Ce("fuser",["-k",`${t}/tcp`]).catch(()=>{});return}let e="";try{({stdout:e}=await Ce("lsof",["-t","-sTCP:LISTEN","-i",`tcp:${t}`]))}catch{return}for(let n of e.split(/\s+/).filter(Boolean)){let r=Number(n);if(!(!r||r===process.pid))try{process.kill(r,"SIGKILL")}catch{}}}function dk(t=process.env){return new Set([Number(t.PORT)||3362,Number(t.BOSTRAT_TLS_PORT)||3443])}async function PO(t,e){let n=new Set(t.views.map(o=>o.port)),r=dk();if(e){let o=Number(e);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=tk;o<=ek;o++)if(!(n.has(o)||r.has(o))&&!await Zs(o,{timeoutMs:250}))return o;throw new Error(`no free view port in ${tk}-${ek}`)}async function DO(t){try{let{stdout:e}=await Ce(L,U("list-sessions","-F","#{session_name}"));return e.split(`
136
+ `).some(n=>n.trim()===Io(t))}catch{return!1}}async function Qs(t){try{await Ce(L,U("kill-session","-t",Io(t)))}catch{}}async function ff(t){if(!await ks())throw new Error("host tmux server not running and auto-start failed \u2014 cannot spawn a view server");let e=Io(t.slug),n=t.serveCwd??t.cwd,r=te.dirname(process.execPath);await Ce(L,U("new-session","-d","-s",e,"-c",n)),await Ce(L,U("send-keys","-t",e,"-l",`export PORT=${t.port} PATH="${r}:$PATH"`)),await Ce(L,U("send-keys","-t",e,"Enter")),await Ce(L,U("send-keys","-t",e,"-l",t.cmd)),await Ce(L,U("send-keys","-t",e,"Enter"))}async function rk(t,e=12){try{let{stdout:n}=await Ce(L,U("capture-pane","-t",Io(t),"-p"));return String(n||"").trimEnd().split(`
137
137
  `).filter(Boolean).slice(-e).join(`
138
- `)}catch{return""}}async function lO(t){if(t.state==="stopped"||t.state==="error")return!1;let e=t.origin!=="detected",n=e?await iO(t.slug):!0;if(e&&!n){let s=t.state==="starting";return t.state=s?"error":"stopped",s&&(t.error=await Db(t.slug)||"server exited before listening"),Xe.delete(t.id),await Ze(t,t.state,t.error?{error:t.error}:{}),!0}if(await Ws(t.port))return Xe.delete(t.id),t.lastHealthyAt=Date.now(),t.state!=="live"?(t.state="live",t.error=null,await Ze(t,"live"),!0):!1;if(t.state==="starting")return Date.now()-t.createdAt>cO?(t.state="error",t.error=await Db(t.slug)||"never started listening",await Ze(t,"error",{error:t.error}),!0):!1;let o=(Xe.get(t.id)||0)+1;return Xe.set(t.id,o),o>=3&&t.state==="live"?(t.state="unhealthy",!0):!1}async function oc(){if(!qd){qd=!0;try{let t=await Qe(),e=!1;for(let n of t.views)await lO(n)&&(e=!0);e&&await Ce()}finally{qd=!1}}}async function Qd({trackId:t}={}){await oc();let e=await Qe();return(t?e.views.filter(r=>r.trackId===t):e.views).map(r=>({...r}))}async function Gb(t){let n=(await Qe()).views.find(r=>r.id===t);return n?{...n}:null}function tf(t){return $e&&$e.views.find(e=>e.slug===t)||null}async function ef({trackId:t,name:e,cmd:n,cwd:r,serveCwd:o,port:s,box:a,origin:i="agent",branch:c=null}){if(!t)throw new Error("trackId required");if(typeof e!="string"||!e.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=Xt.resolve(r,o??"."),d=i==="detected"?null:async()=>{await rO(r,u),await oO(u,n)},f=await Qe();if(i!=="detected"){let w=Vd(e),y=String(n).trim(),k=f.views.find(S=>S.trackId===t&&(S.slug===w||Vd(S.name)===w||S.cmd===y&&Xt.resolve(S.serveCwd??S.cwd)===u));if(k)return uO(f,k,{cmd:y,box:a,branch:c,serveCwd:l?u:void 0,validate:d})}if(d&&await d(),f.views.filter(w=>w.state==="live"||w.state==="starting").length>=Ln)throw new Error(`view cap reached (${Ln} live) \u2014 stop one first`);let m={id:U$().slice(0,8),trackId:t,box:a||null,name:e.trim(),slug:sO(f,e),cmd:n?String(n).trim():null,cwd:r,serveCwd:u,branch:c,port:await aO(f,s),origin:i,state:"starting",error:null,createdAt:Date.now(),lastHealthyAt:null};return i!=="detected"&&await Zd(m),f.views.push(m),await Ce(),await Ze(m,"created",{origin:i}),Gd(t,m.id),i==="detected"&&await Ws(m.port)&&(m.state="live",m.lastHealthyAt=Date.now(),await Ce(),await Ze(m,"live")),{...m}}async function uO(t,e,{cmd:n,box:r,branch:o,serveCwd:s,validate:a}){r&&(e.box=r),o&&(e.branch=o);let i=e.cmd!==n,c=s!==void 0&&!await eO(e.serveCwd??e.cwd,s);if((e.state==="live"||e.state==="starting")&&!i&&!c&&await Ws(e.port))return await Ce(),Gd(e.trackId,e.id),{...e,reused:!0};if(a&&await a(),t.views.filter(d=>d.id!==e.id&&(d.state==="live"||d.state==="starting")).length>=Ln)throw new Error(`view cap reached (${Ln} live) \u2014 stop one first`);return e.origin==="detected"?(await Xd(e.port),e.origin="agent"):await qs(e.slug),e.cmd=n,s!==void 0&&(e.serveCwd=s),e.state="starting",e.error=null,e.createdAt=Date.now(),Xe.delete(e.id),await Zd(e),await Ce(),await Ze(e,"created",{restarted:!0,reused:!0}),Gd(e.trackId,e.id),{...e,reused:!0}}async function Vb(t){let n=(await Qe()).views.find(r=>r.id===t);if(!n)throw new Error("view not found");return n.origin==="detected"?await Xd(n.port):await qs(n.slug),n.state!=="stopped"&&(n.state="stopped",Xe.delete(n.id),await Ce(),await Ze(n,"stopped")),{...n}}async function zb(t){let e=await Qe(),n=e.views.find(o=>o.id===t);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(e.views.filter(o=>o.id!==t&&(o.state==="live"||o.state==="starting")).length>=Ln)throw new Error(`view cap reached (${Ln} live) \u2014 stop one first`);return await qs(n.slug),n.state="starting",n.error=null,n.createdAt=Date.now(),Xe.delete(n.id),await Zd(n),await Ce(),await Ze(n,"created",{restarted:!0}),{...n}}async function Jb(t){let e=await Qe(),n=e.views.findIndex(o=>o.id===t);if(n===-1)throw new Error("view not found");let r=e.views[n];return r.origin==="detected"?await Xd(r.port):await qs(r.slug),e.views.splice(n,1),Xe.delete(r.id),await Ce(),await Ze(r,"deleted"),{ok:!0,id:t,slug:r.slug}}async function Yb(t){let e=await Qe(),n=e.views.filter(r=>r.trackId===t);for(let r of n)r.origin!=="detected"&&await qs(r.slug),Xe.delete(r.id);return n.length&&(e.views=e.views.filter(r=>r.trackId!==t),await Ce()),n.length}async function Xb(t,e){if(!t?.id||!Array.isArray(e)||!e.length)return[];let n=await Qe(),r=n.adoptWatermarks[t.id]??null,o=e.filter(c=>c.role==="assistant"&&c.ts!=null&&(r==null?!1:c.ts>r)),s=e.reduce((c,l)=>l.ts>c?l.ts:c,r??0);if(n.adoptWatermarks[t.id]!==s&&(n.adoptWatermarks[t.id]=s,await Ce()),!o.length)return[];let a=new Set;for(let c of o)for(let l of String(c.text||"").matchAll(dO)){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(!Kb().has(c)&&!n.views.some(l=>l.port===c)&&await Ws(c))try{i.push(await ef({trackId:t.id,name:`${t.name} preview`,cmd:null,cwd:t.cwd,port:c,origin:"detected",branch:t.workspace?.branch??null}))}catch{}return i}var Oe,q$,jb,Pb,Nb,Ln,K$,yo,Bb,Fs,G$,Kd,V$,z$,J$,zd,Lb,Hd,Z$,tO,Ub,nc,$e,Wd,Us,Jd,Hb,Xe,cO,qd,dO,sc=M(()=>{Ht();ct();gn();Oe=W$(H$),q$=process.env.BOSTRAT_STATE_DIR||Xt.join(process.env.HOME||L$.tmpdir(),".bostrat"),jb=Xt.join(q$,"views.json"),[Pb,Nb]=(process.env.BOSTRAT_VIEW_PORTS||"4300-4349").split("-").map(t=>Number(t)||0),Ln=Number(process.env.BOSTRAT_VIEW_MAX)||3,K$="bostrat-view-",yo=t=>`${K$}${t}`,Bb=new Set(["bostrat","www","api","views","app"]),Fs=t=>Object.assign(new Error(t),{status:400}),G$=new Set(["npm","pnpm","yarn","bun"]),Kd="package.json",V$=/[|;&`]|\$\(/,z$=new Set(["sh","bash","zsh","dash","env","exec","nohup","time"]),J$=/(^|\s)(-C|--cwd|--manifest-path|--dir)(=|\s)/,zd=t=>String(t).trim().split(/\s+/).filter(Boolean),Lb=/^[A-Za-z_][A-Za-z0-9_]*=/;Hd=t=>t==="/",Z$=t=>t===".."||t.startsWith("../")||t.includes("/../")||t.endsWith("/..");tO=t=>Hs.stat(t).then(e=>e.isDirectory(),()=>!1),Ub=t=>Hs.stat(t).then(e=>e.isFile(),()=>!1),nc=t=>Hs.realpath(t).catch(()=>Xt.resolve(t));$e=null,Wd=null;Us=new Map,Jd=Number(process.env.BOSTRAT_VIEW_JOB_TIMEOUT)||3e5,Hb=12e3;Xe=new Map,cO=12e4;qd=!1;dO=/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::(\d{2,5}))?(?:\/|\b)/g});import Zb from"node:fs/promises";import Qb from"node:path";import fO from"node:os";function ic({change:t,repo:e=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:t,repo:e,number:n,githubAt:r,observedAt:o,latencyMs:c,lane:s,intervalMs:a,source:i};ac.push(l),ac.length>mO&&ac.shift();let u=nf.get(t)||{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)),nf.set(t,u),hO(l),l}async function hO(t){try{await Zb.mkdir(tk,{recursive:!0}),await Zb.appendFile(pO,JSON.stringify(t)+`
139
- `)}catch{}}function ek(){let t={};for(let[e,n]of nf)t[e]={count:n.count,measured:n.measured,avgMs:n.measured?Math.round(n.totalMs/n.measured):null,maxMs:n.measured?n.maxMs:null};return{byChange:t,recent:ac.slice(-20)}}var tk,pO,mO,ac,nf,cc=M(()=>{tk=process.env.BOSTRAT_STATE_DIR||Qb.join(process.env.HOME||fO.tmpdir(),".bostrat"),pO=Qb.join(tk,"github-latency.ndjson"),mO=100,ac=[],nf=new Map});import{execFile as wO}from"node:child_process";import{promisify as gO}from"node:util";async function yO(t){let e=/workspaces[/\\]([0-9a-f]{8})(?:[/\\]|$)/.exec(t||"")?.[1];if(e)try{let[{stdout:n},{stdout:r}]=await Promise.all([ko("git",["-C",t,"rev-parse","HEAD"]),ko("git",["-C",t,"rev-parse","--abbrev-ref","HEAD"])]);await I({id:e,cwd:t},{type:"code.pushed",actor:"orchestrator",payload:{ref:r.trim(),sha:n.trim(),wip:!1,ts:Date.now()}})}catch{}}async function ie(t,e,n={}){let{caller:r="prs",...o}=n,s=await Ae({cwd:t});ze(r);try{let{stdout:a}=await ko("gh",e,{cwd:t,...bO,...o,env:{...process.env,...s,...o.env||{}}});return String(a||"")}catch(a){throw Cn(a)&&Mn(a),a}}async function sf(){if(lc&&Date.now()-lc.at<6e4)return lc.data;let t;try{ze("auth");let e=await ko("gh",["auth","status"],{timeout:1e4});t={installed:!0,authenticated:!0,login:`${e.stdout||""}${e.stderr||""}`.match(/account\s+(\S+)/)?.[1]??null}}catch(e){t=e?.code==="ENOENT"||e?.code===127?{installed:!1,authenticated:!1,login:null}:{installed:!0,authenticated:!1,login:null}}if(t.installed&&!t.authenticated)try{let e=await rs();e.configured&&(t={installed:!0,authenticated:!0,login:e.username,via:"broker"})}catch{}return lc={at:Date.now(),data:t},t}async function kO(t){try{let{stdout:e}=await ko("git",["-C",t,"config","--get","remote.origin.url"],{timeout:5e3});return/github\.com/.test(e)}catch{return!1}}function rk(t){let e=t.name||t.context||"check",n=t.detailsUrl||t.targetUrl||null,r=t.completedAt||t.createdAt||null,o;return t.__typename==="StatusContext"?o=t.state==="SUCCESS"?"pass":t.state==="PENDING"||t.state==="EXPECTED"?"pending":"fail":t.status&&t.status!=="COMPLETED"?o="pending":["SUCCESS","NEUTRAL","SKIPPED"].includes(t.conclusion)?o="pass":o="fail",{name:e,state:o,url:n,completedAt:r}}function rf(t){let e=(t||[]).map(rk),n=e.filter(s=>s.state==="pending").length,r=e.map(s=>Date.parse(s.completedAt||"")).filter(s=>s>0),o=e.length&&!n&&r.length?Math.max(...r):null;return{total:e.length,passed:e.filter(s=>s.state==="pass").length,failed:e.filter(s=>s.state==="fail").length,pending:n,failing:e.filter(s=>s.state==="fail").map(({name:s,url:a})=>({name:s,url:a})),settledAt:o}}function cf(t){return/Resource not accessible by personal access token/.test(String(t?.stderr||t?.message||""))}async function sk(t,e){if(!e)return null;let n=await st(t);if(!n)return null;try{let r=await ie(t,["api",`repos/${n}/actions/runs?head_sha=${encodeURIComponent(e)}&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 ak(t){return(t||[]).map(e=>({name:e.name,detailsUrl:e.html_url||null,status:String(e.status||"").toUpperCase(),conclusion:e.conclusion?String(e.conclusion).toUpperCase():null,completedAt:e.status==="completed"&&e.updated_at||null}))}async function ik(t,e){let n=await sk(t,e);return n===null?{...rf([]),unavailable:!0}:rf(ak(n))}function uc(t,e=rf(t.statusCheckRollup)){return{number:t.number,title:t.title,url:t.url,author:t.author?.login??null,headRefName:t.headRefName,headSha:t.headRefOid??null,baseRefName:t.baseRefName,isDraft:!!t.isDraft,reviewDecision:t.reviewDecision||null,mergeable:t.mergeable||"UNKNOWN",mergeStateStatus:t.mergeStateStatus||"UNKNOWN",additions:t.additions??0,deletions:t.deletions??0,createdAt:t.createdAt,updatedAt:t.updatedAt,checks:e,green:e.failed===0&&e.pending===0&&t.mergeStateStatus==="CLEAN",autoMergeArmed:!!t.autoMergeRequest,mergeabilityPending:!1}}function SO(t,e,n){let r=new Set;for(let o of e){let s=`${t}#${o.number}`;if(o.mergeable!=="UNKNOWN"&&o.mergeStateStatus!=="UNKNOWN"){bo.delete(s);continue}r.add(s),bo.has(s)||bo.set(s,n),o.mergeabilityPending=n-bo.get(s)<xO}for(let o of bo.keys())o.startsWith(`${t}#`)&&!r.has(o)&&bo.delete(o);return e}async function xo(t,e){let n=await tn(t),r=Number(e);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{let o=await ie(n.path,["pr","view",String(r),"--json",af]);return uc(JSON.parse(o))}catch(o){if(!cf(o))throw o;let s=await ie(n.path,["pr","view",String(r),"--json",ok]),a=JSON.parse(s);return uc(a,await ik(n.path,a.headRefOid))}}async function Sr(t,{caller:e="prs"}={}){try{let n=await ie(t,["pr","list","--json",af,"--limit","50"],{caller:e});return JSON.parse(n||"[]").map(r=>uc(r)).sort(nk)}catch(n){if(!cf(n))throw n;let r=await ie(t,["pr","list","--json",ok,"--limit","50"],{caller:e});return(await Promise.all(JSON.parse(r||"[]").map(async o=>uc(o,await ik(t,o.headRefOid))))).sort(nk)}}function Pe(){Ks.clear()}async function AO(t,e){if(!t)return e;for(let n of e){let r=await Wt(t,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 Ki(t,n.number,{headSha:n.headSha}).catch(()=>{}):n.ciFix={delegatedAt:r.ciFix.delegatedAt,trackId:r.ciFix.trackId??null}),r.reconcile&&(o(r.reconcile)?await Vi(t,n.number,{headSha:n.headSha}).catch(()=>{}):n.reconcile={delegatedAt:r.reconcile.delegatedAt,trackId:r.reconcile.trackId??null})}return e}async function ck(){let t=await sf();if(!t.authenticated)return{auth:t,repos:[]};let e=[];for(let a of await Ue())await kO(a.path)&&e.push(a);let n=Date.now(),r=Wi(n)>0,o=await Promise.all(e.map(async a=>{let i=Ks.get(a.path),c=i?.pending?TO:vO;if(i&&(r||n-i.at<c))return i.entry;try{let l=await st(a.path).catch(()=>null),u=SO(a.path,await Sr(a.path,{caller:"tab"}),n);if(await AO(l,u),i?.entry?.prs)for(let p of u)i.entry.prs.find(w=>w.number===p.number)?.checks?.pending>0&&p.checks.total>0&&p.checks.pending===0&&ic({change:p.checks.failed>0?"checks-failed":"checks-green",repo:l||a.name,number:p.number,githubAt:p.checks.settledAt,source:"tab"});let d={name:a.name,path:a.path,prs:u},f=u.some(p=>p.mergeabilityPending||p.checks.pending>0||p.autoMergeArmed);return Ks.set(a.path,{at:Date.now(),entry:d,pending:f}),d}catch(l){return i?i.entry:{name:a.name,path:a.path,prs:[],error:Me(l)}}})),s=new Set(e.map(a=>a.path));for(let a of Ks.keys())s.has(a)||Ks.delete(a);return{auth:t,repos:o}}async function tn(t){let e=(await Ue()).find(n=>n.path===t);if(!e)throw new Error(`unknown repo: ${t}`);return e}async function vr(t){return es(t)}async function So(t,e,{method:n="squash"}={}){let r=await tn(t);if(!Gs.has(n))throw new Error(`invalid merge method: ${n}`);let o=Number(e);if(!Number.isInteger(o)||o<=0)throw new Error("invalid PR number");let s=["pr","merge",String(o),`--${n}`];if(n!=="rebase"&&(await Ae({cwd:r.path})).GH_TOKEN){let a=await Tl().catch(()=>null);a&&s.push("--body",`Merged by bostrat on behalf of @${a}`)}try{await ie(r.path,s)}catch(a){throw new Error(Me(a))}finally{Pe()}return{ok:!0,number:o}}async function Vs(t,e){let n=await tn(t),r=Number(e);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await ie(n.path,["api","-X","PUT",`repos/{owner}/{repo}/pulls/${r}/update-branch`])}catch(s){throw new Error(Me(s))}finally{Pe()}let o=await st(n.path).catch(()=>null);return o&&await ob(o,r).catch(()=>{}),{ok:!0,number:r}}async function lf(t,e){let n=await tn(t),r=Number(e);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await ie(n.path,["pr","merge",String(r),"--disable-auto"])}catch(o){throw new Error(Me(o))}finally{Pe()}return{ok:!0,number:r}}function uf(t){return t.green&&!t.isDraft}function RO(t){return t.isDraft?"draft":t.mergeable==="CONFLICTING"?`conflicts with ${t.baseRefName}`:t.checks.failed>0?"checks failing":t.checks.pending>0?"checks running":t.mergeable==="UNKNOWN"||t.mergeStateStatus==="UNKNOWN"?"mergeability unresolved":t.mergeStateStatus==="BEHIND"?`behind ${t.baseRefName}`:t.mergeStateStatus==="BLOCKED"?"blocked by branch protection":`not clean (${t.mergeStateStatus})`}function lk(t,{update:e=!0}={}){return t.isDraft?{action:"skip",reason:"draft"}:uf(t)?{action:"merge"}:e&&t.mergeStateStatus==="BEHIND"&&t.mergeable!=="CONFLICTING"&&t.checks.failed===0?{action:"update-arm"}:{action:"arm"}}function uk(t){return[...t.filter(e=>e.plan.action!=="merge"),...t.filter(e=>e.plan.action==="merge")]}function dk(){let t={};for(let[e,n]of of)t[e]={...n};return t}async function fk(t,{method:e="merge",onMerged:n=null}={}){let r=await tn(t);if(!Gs.has(e))throw new Error(`invalid merge method: ${e}`);if(of.get(r.path)?.running)throw new Error("a merge-all is already running for this repo");let o=(await Sr(r.path)).filter(uf).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:e,total:o.length,current:o[0].number,queue:o.map(a=>({number:a.number,title:a.title})),merged:[],skipped:[],failed:[]};return of.set(r.path,s),OO(s,o,{listPrs:()=>Sr(r.path),merge:a=>So(r.path,a,{method:e}),sleep:IO,onMerged:n}).catch(()=>{}),{ok:!0,repo:r.path,total:s.total,queue:o.map(a=>a.number)}}async function $O(t,e){let n=Date.now()+(e.settleMaxMs??_O),r=null;for(;;){let o=null;try{if(o=await e.listPrs(),r=null,!o.some(a=>t.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 e.sleep(EO)}}async function OO(t,e,n){try{let r=e;for(let o=0;o<e.length;o++){let s=e[o];if(t.current=s.number,o>0)try{r=await $O(e.slice(o).map(i=>i.number),n)}catch(i){for(let c of e.slice(o))t.failed.push({number:c.number,title:c.title,reason:`couldn't re-check PR state: ${Me(i)}`});break}let a=r.find(i=>i.number===s.number);if(!a){t.skipped.push({number:s.number,title:s.title,reason:"no longer open"});continue}if(!uf(a)){t.skipped.push({number:a.number,title:a.title,reason:RO(a)});continue}try{await n.merge(a.number),t.merged.push({number:a.number,title:a.title});try{await n.onMerged?.(a)}catch{}}catch(i){t.failed.push({number:a.number,title:a.title,reason:Me(i)})}}}finally{t.current=null,t.running=!1,t.finishedAt=Date.now(),Pe()}}async function df(t,{title:e,body:n="",base:r=null}={}){if(typeof e!="string"||!e.trim())throw new Error("title required");try{await ko("git",["-C",t,"push","-u","origin","HEAD"],{timeout:12e4,maxBuffer:4*1024*1024})}catch(l){throw new Error(`push failed: ${Me(l)}`)}await yO(t);let o=n||"";if((await Ae({cwd:t})).GH_TOKEN){let l=await Tl().catch(()=>null);l&&(o=`${o?`${o}
138
+ `)}catch{return""}}async function jO(t){if(t.state==="stopped"||t.state==="error")return!1;let e=t.origin!=="detected",n=e?await DO(t.slug):!0;if(e&&!n){let s=t.state==="starting";return t.state=s?"error":"stopped",s&&(t.error=await rk(t.slug)||"server exited before listening"),Qe.delete(t.id),await tn(t,t.state,t.error?{error:t.error}:{}),!0}if(await Zs(t.port))return Qe.delete(t.id),t.lastHealthyAt=Date.now(),t.state!=="live"?(t.state="live",t.error=null,await tn(t,"live"),!0):!1;if(t.state==="starting")return Date.now()-t.createdAt>BO?(t.state="error",t.error=await rk(t.slug)||"never started listening",await tn(t,"error",{error:t.error}),!0):!1;let o=(Qe.get(t.id)||0)+1;return Qe.set(t.id,o),o>=3&&t.state==="live"?(t.state="unhealthy",!0):!1}async function gc(){if(!rf){rf=!0;try{let t=await en(),e=!1;for(let n of t.views)await jO(n)&&(e=!0);e&&await Me()}finally{rf=!1}}}async function pf({trackId:t}={}){await gc();let e=await en();return(t?e.views.filter(r=>r.trackId===t):e.views).map(r=>({...r}))}async function fk(t){let n=(await en()).views.find(r=>r.id===t);return n?{...n}:null}function mf(t){return Oe&&Oe.views.find(e=>e.slug===t)||null}async function hf({trackId:t,name:e,cmd:n,cwd:r,serveCwd:o,port:s,box:a,origin:i="agent",branch:c=null}){if(!t)throw new Error("trackId required");if(typeof e!="string"||!e.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=te.resolve(r,o??"."),f=i==="detected"?null:async()=>{await CO(r,u),await MO(u,n)},d=await en();if(i!=="detected"){let w=af(e),y=String(n).trim(),k=d.views.find(x=>x.trackId===t&&(x.slug===w||af(x.name)===w||x.cmd===y&&te.resolve(x.serveCwd??x.cwd)===u));if(k)return LO(d,k,{cmd:y,box:a,branch:c,serveCwd:l?u:void 0,validate:f})}if(f&&await f(),d.views.filter(w=>w.state==="live"||w.state==="starting").length>=Wn)throw new Error(`view cap reached (${Wn} live) \u2014 stop one first`);let h={id:wO().slice(0,8),trackId:t,box:a||null,name:e.trim(),slug:NO(d,e),cmd:n?String(n).trim():null,cwd:r,serveCwd:u,branch:c,port:await PO(d,s),origin:i,state:"starting",error:null,createdAt:Date.now(),lastHealthyAt:null};return i!=="detected"&&await ff(h),d.views.push(h),await Me(),await tn(h,"created",{origin:i}),sf(t,h.id),i==="detected"&&await Zs(h.port)&&(h.state="live",h.lastHealthyAt=Date.now(),await Me(),await tn(h,"live")),{...h}}async function LO(t,e,{cmd:n,box:r,branch:o,serveCwd:s,validate:a}){r&&(e.box=r),o&&(e.branch=o);let i=e.cmd!==n,c=s!==void 0&&!await $O(e.serveCwd??e.cwd,s);if((e.state==="live"||e.state==="starting")&&!i&&!c&&await Zs(e.port))return await Me(),sf(e.trackId,e.id),{...e,reused:!0};if(a&&await a(),t.views.filter(f=>f.id!==e.id&&(f.state==="live"||f.state==="starting")).length>=Wn)throw new Error(`view cap reached (${Wn} live) \u2014 stop one first`);return e.origin==="detected"?(await df(e.port),e.origin="agent"):await Qs(e.slug),e.cmd=n,s!==void 0&&(e.serveCwd=s),e.state="starting",e.error=null,e.createdAt=Date.now(),Qe.delete(e.id),await ff(e),await Me(),await tn(e,"created",{restarted:!0,reused:!0}),sf(e.trackId,e.id),{...e,reused:!0}}async function pk(t){let n=(await en()).views.find(r=>r.id===t);if(!n)throw new Error("view not found");return n.origin==="detected"?await df(n.port):await Qs(n.slug),n.state!=="stopped"&&(n.state="stopped",Qe.delete(n.id),await Me(),await tn(n,"stopped")),{...n}}async function mk(t){let e=await en(),n=e.views.find(o=>o.id===t);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(e.views.filter(o=>o.id!==t&&(o.state==="live"||o.state==="starting")).length>=Wn)throw new Error(`view cap reached (${Wn} live) \u2014 stop one first`);return await Qs(n.slug),n.state="starting",n.error=null,n.createdAt=Date.now(),Qe.delete(n.id),await ff(n),await Me(),await tn(n,"created",{restarted:!0}),{...n}}async function hk(t){let e=await en(),n=e.views.findIndex(o=>o.id===t);if(n===-1)throw new Error("view not found");let r=e.views[n];return r.origin==="detected"?await df(r.port):await Qs(r.slug),e.views.splice(n,1),Qe.delete(r.id),await Me(),await tn(r,"deleted"),{ok:!0,id:t,slug:r.slug}}async function wk(t){let e=await en(),n=e.views.filter(r=>r.trackId===t);for(let r of n)r.origin!=="detected"&&await Qs(r.slug),Qe.delete(r.id);return n.length&&(e.views=e.views.filter(r=>r.trackId!==t),await Me()),n.length}async function gk(t,e){if(!t?.id||!Array.isArray(e)||!e.length)return[];let n=await en(),r=n.adoptWatermarks[t.id]??null,o=e.filter(c=>c.role==="assistant"&&c.ts!=null&&(r==null?!1:c.ts>r)),s=e.reduce((c,l)=>l.ts>c?l.ts:c,r??0);if(n.adoptWatermarks[t.id]!==s&&(n.adoptWatermarks[t.id]=s,await Me()),!o.length)return[];let a=new Set;for(let c of o)for(let l of String(c.text||"").matchAll(FO)){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(!dk().has(c)&&!n.views.some(l=>l.port===c)&&await Zs(c))try{i.push(await hf({trackId:t.id,name:`${t.name} preview`,cmd:null,cwd:t.cwd,port:c,origin:"detected",branch:t.workspace?.branch??null}))}catch{}return i}var Ce,bO,ok,tk,ek,Wn,kO,Io,nk,Js,xO,of,SO,vO,TO,cf,sk,ef,_O,RO,ik,hc,Oe,nf,Ys,lf,ck,Qe,BO,rf,FO,yc=M(()=>{qt();at();kn();Ce=yO(gO),bO=process.env.BOSTRAT_STATE_DIR||te.join(process.env.HOME||mO.tmpdir(),".bostrat"),ok=te.join(bO,"views.json"),[tk,ek]=(process.env.BOSTRAT_VIEW_PORTS||"4300-4349").split("-").map(t=>Number(t)||0),Wn=Number(process.env.BOSTRAT_VIEW_MAX)||3,kO="bostrat-view-",Io=t=>`${kO}${t}`,nk=new Set(["bostrat","www","api","views","app"]),Js=t=>Object.assign(new Error(t),{status:400}),xO=new Set(["npm","pnpm","yarn","bun"]),of="package.json",SO=/[|;&`]|\$\(/,vO=new Set(["sh","bash","zsh","dash","env","exec","nohup","time"]),TO=/(^|\s)(-C|--cwd|--manifest-path|--dir)(=|\s)/,cf=t=>String(t).trim().split(/\s+/).filter(Boolean),sk=/^[A-Za-z_][A-Za-z0-9_]*=/;ef=t=>t==="/",_O=t=>t===".."||t.startsWith("../")||t.includes("/../")||t.endsWith("/..");RO=t=>Xs.stat(t).then(e=>e.isDirectory(),()=>!1),ik=t=>Xs.stat(t).then(e=>e.isFile(),()=>!1),hc=t=>Xs.realpath(t).catch(()=>te.resolve(t));Oe=null,nf=null;Ys=new Map,lf=Number(process.env.BOSTRAT_VIEW_JOB_TIMEOUT)||3e5,ck=12e3;Qe=new Map,BO=12e4;rf=!1;FO=/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::(\d{2,5}))?(?:\/|\b)/g});import yk from"node:fs/promises";import bk from"node:path";import UO from"node:os";function kc({change:t,repo:e=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:t,repo:e,number:n,githubAt:r,observedAt:o,latencyMs:c,lane:s,intervalMs:a,source:i};bc.push(l),bc.length>WO&&bc.shift();let u=wf.get(t)||{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)),wf.set(t,u),qO(l),l}async function qO(t){try{await yk.mkdir(kk,{recursive:!0}),await yk.appendFile(HO,JSON.stringify(t)+`
139
+ `)}catch{}}function xk(){let t={};for(let[e,n]of wf)t[e]={count:n.count,measured:n.measured,avgMs:n.measured?Math.round(n.totalMs/n.measured):null,maxMs:n.measured?n.maxMs:null};return{byChange:t,recent:bc.slice(-20)}}var kk,HO,WO,bc,wf,xc=M(()=>{kk=process.env.BOSTRAT_STATE_DIR||bk.join(process.env.HOME||UO.tmpdir(),".bostrat"),HO=bk.join(kk,"github-latency.ndjson"),WO=100,bc=[],wf=new Map});import{execFile as KO}from"node:child_process";import{promisify as GO}from"node:util";async function VO(t){let e=/workspaces[/\\]([0-9a-f]{8})(?:[/\\]|$)/.exec(t||"")?.[1];if(e)try{let[{stdout:n},{stdout:r}]=await Promise.all([$o("git",["-C",t,"rev-parse","HEAD"]),$o("git",["-C",t,"rev-parse","--abbrev-ref","HEAD"])]);await I({id:e,cwd:t},{type:"code.pushed",actor:"orchestrator",payload:{ref:r.trim(),sha:n.trim(),wip:!1,ts:Date.now()}})}catch{}}async function ue(t,e,n={}){let{caller:r="prs",...o}=n,s=await _e({cwd:t});Ye(r);try{let{stdout:a}=await $o("gh",e,{cwd:t,...zO,...o,env:{...process.env,...s,...o.env||{}}});return String(a||"")}catch(a){throw Dn(a)&&Bn(a),a}}async function bf(){if(Sc&&Date.now()-Sc.at<6e4)return Sc.data;let t;try{Ye("auth");let e=await $o("gh",["auth","status"],{timeout:1e4});t={installed:!0,authenticated:!0,login:`${e.stdout||""}${e.stderr||""}`.match(/account\s+(\S+)/)?.[1]??null}}catch(e){t=e?.code==="ENOENT"||e?.code===127?{installed:!1,authenticated:!1,login:null}:{installed:!0,authenticated:!1,login:null}}if(t.installed&&!t.authenticated)try{let e=await fs();e.configured&&(t={installed:!0,authenticated:!0,login:e.username,via:"broker"})}catch{}return Sc={at:Date.now(),data:t},t}async function JO(t){try{let{stdout:e}=await $o("git",["-C",t,"config","--get","remote.origin.url"],{timeout:5e3});return/github\.com/.test(e)}catch{return!1}}function vk(t){let e=t.name||t.context||"check",n=t.detailsUrl||t.targetUrl||null,r=t.completedAt||t.createdAt||null,o;return t.__typename==="StatusContext"?o=t.state==="SUCCESS"?"pass":t.state==="PENDING"||t.state==="EXPECTED"?"pending":"fail":t.status&&t.status!=="COMPLETED"?o="pending":["SUCCESS","NEUTRAL","SKIPPED"].includes(t.conclusion)?o="pass":o="fail",{name:e,state:o,url:n,completedAt:r}}function gf(t){let e=(t||[]).map(vk),n=e.filter(s=>s.state==="pending").length,r=e.map(s=>Date.parse(s.completedAt||"")).filter(s=>s>0),o=e.length&&!n&&r.length?Math.max(...r):null;return{total:e.length,passed:e.filter(s=>s.state==="pass").length,failed:e.filter(s=>s.state==="fail").length,pending:n,failing:e.filter(s=>s.state==="fail").map(({name:s,url:a})=>({name:s,url:a})),settledAt:o}}function xf(t){return/Resource not accessible by personal access token/.test(String(t?.stderr||t?.message||""))}async function Ak(t,e){if(!e)return null;let n=await lt(t);if(!n)return null;try{let r=await ue(t,["api",`repos/${n}/actions/runs?head_sha=${encodeURIComponent(e)}&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 Ek(t){return(t||[]).map(e=>({name:e.name,detailsUrl:e.html_url||null,status:String(e.status||"").toUpperCase(),conclusion:e.conclusion?String(e.conclusion).toUpperCase():null,completedAt:e.status==="completed"&&e.updated_at||null}))}async function _k(t,e){let n=await Ak(t,e);return n===null?{...gf([]),unavailable:!0}:gf(Ek(n))}function vc(t,e=gf(t.statusCheckRollup)){return{number:t.number,title:t.title,url:t.url,author:t.author?.login??null,headRefName:t.headRefName,headSha:t.headRefOid??null,baseRefName:t.baseRefName,isDraft:!!t.isDraft,reviewDecision:t.reviewDecision||null,mergeable:t.mergeable||"UNKNOWN",mergeStateStatus:t.mergeStateStatus||"UNKNOWN",additions:t.additions??0,deletions:t.deletions??0,createdAt:t.createdAt,updatedAt:t.updatedAt,checks:e,green:e.failed===0&&e.pending===0&&t.mergeStateStatus==="CLEAN",autoMergeArmed:!!t.autoMergeRequest,mergeabilityPending:!1}}function XO(t,e,n){let r=new Set;for(let o of e){let s=`${t}#${o.number}`;if(o.mergeable!=="UNKNOWN"&&o.mergeStateStatus!=="UNKNOWN"){Ro.delete(s);continue}r.add(s),Ro.has(s)||Ro.set(s,n),o.mergeabilityPending=n-Ro.get(s)<YO}for(let o of Ro.keys())o.startsWith(`${t}#`)&&!r.has(o)&&Ro.delete(o);return e}async function Oo(t,e){let n=await nn(t),r=Number(e);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{let o=await ue(n.path,["pr","view",String(r),"--json",kf]);return vc(JSON.parse(o))}catch(o){if(!xf(o))throw o;let s=await ue(n.path,["pr","view",String(r),"--json",Tk]),a=JSON.parse(s);return vc(a,await _k(n.path,a.headRefOid))}}async function $r(t,{caller:e="prs"}={}){try{let n=await ue(t,["pr","list","--json",kf,"--limit","50"],{caller:e});return JSON.parse(n||"[]").map(r=>vc(r)).sort(Sk)}catch(n){if(!xf(n))throw n;let r=await ue(t,["pr","list","--json",Tk,"--limit","50"],{caller:e});return(await Promise.all(JSON.parse(r||"[]").map(async o=>vc(o,await _k(t,o.headRefOid))))).sort(Sk)}}function Pe(){ta.clear()}async function tC(t,e){if(!t)return e;for(let n of e){let r=await Kt(t,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 oc(t,n.number,{headSha:n.headSha}).catch(()=>{}):n.ciFix={delegatedAt:r.ciFix.delegatedAt,trackId:r.ciFix.trackId??null}),r.reconcile&&(o(r.reconcile)?await ac(t,n.number,{headSha:n.headSha}).catch(()=>{}):n.reconcile={delegatedAt:r.reconcile.delegatedAt,trackId:r.reconcile.trackId??null})}return e}async function Ik(){let t=await bf();if(!t.authenticated)return{auth:t,repos:[]};let e=[];for(let a of await We())await JO(a.path)&&e.push(a);let n=Date.now(),r=nc(n)>0,o=await Promise.all(e.map(async a=>{let i=ta.get(a.path),c=i?.pending?QO:ZO;if(i&&(r||n-i.at<c))return i.entry;try{let l=await lt(a.path).catch(()=>null),u=XO(a.path,await $r(a.path,{caller:"tab"}),n);if(await tC(l,u),i?.entry?.prs)for(let p of u)i.entry.prs.find(w=>w.number===p.number)?.checks?.pending>0&&p.checks.total>0&&p.checks.pending===0&&kc({change:p.checks.failed>0?"checks-failed":"checks-green",repo:l||a.name,number:p.number,githubAt:p.checks.settledAt,source:"tab"});let f={name:a.name,path:a.path,prs:u},d=u.some(p=>p.mergeabilityPending||p.checks.pending>0||p.autoMergeArmed);return ta.set(a.path,{at:Date.now(),entry:f,pending:d}),f}catch(l){return i?i.entry:{name:a.name,path:a.path,prs:[],error:Ne(l)}}})),s=new Set(e.map(a=>a.path));for(let a of ta.keys())s.has(a)||ta.delete(a);return{auth:t,repos:o}}async function nn(t){let e=(await We()).find(n=>n.path===t);if(!e)throw new Error(`unknown repo: ${t}`);return e}async function Or(t){return Gr(t)}async function Co(t,e,{method:n="squash"}={}){let r=await nn(t);if(!ea.has(n))throw new Error(`invalid merge method: ${n}`);let o=Number(e);if(!Number.isInteger(o)||o<=0)throw new Error("invalid PR number");let s=["pr","merge",String(o),`--${n}`];if(n!=="rebase"&&(await _e({cwd:r.path})).GH_TOKEN){let a=await Bl().catch(()=>null);a&&s.push("--body",`Merged by bostrat on behalf of @${a}`)}try{await ue(r.path,s)}catch(a){throw new Error(Ne(a))}finally{Pe()}return{ok:!0,number:o}}async function na(t,e){let n=await nn(t),r=Number(e);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await ue(n.path,["api","-X","PUT",`repos/{owner}/{repo}/pulls/${r}/update-branch`])}catch(s){throw new Error(Ne(s))}finally{Pe()}let o=await lt(n.path).catch(()=>null);return o&&await Tb(o,r).catch(()=>{}),{ok:!0,number:r}}async function Sf(t,e){let n=await nn(t),r=Number(e);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await ue(n.path,["pr","merge",String(r),"--disable-auto"])}catch(o){throw new Error(Ne(o))}finally{Pe()}return{ok:!0,number:r}}function vf(t){return t.green&&!t.isDraft}function oC(t){return t.isDraft?"draft":t.mergeable==="CONFLICTING"?`conflicts with ${t.baseRefName}`:t.checks.failed>0?"checks failing":t.checks.pending>0?"checks running":t.mergeable==="UNKNOWN"||t.mergeStateStatus==="UNKNOWN"?"mergeability unresolved":t.mergeStateStatus==="BEHIND"?`behind ${t.baseRefName}`:t.mergeStateStatus==="BLOCKED"?"blocked by branch protection":`not clean (${t.mergeStateStatus})`}function Rk(t,{update:e=!0}={}){return t.isDraft?{action:"skip",reason:"draft"}:vf(t)?{action:"merge"}:e&&t.mergeStateStatus==="BEHIND"&&t.mergeable!=="CONFLICTING"&&t.checks.failed===0?{action:"update-arm"}:{action:"arm"}}function $k(t){return[...t.filter(e=>e.plan.action!=="merge"),...t.filter(e=>e.plan.action==="merge")]}function Ok(){let t={};for(let[e,n]of yf)t[e]={...n};return t}async function Ck(t,{method:e="merge",onMerged:n=null}={}){let r=await nn(t);if(!ea.has(e))throw new Error(`invalid merge method: ${e}`);if(yf.get(r.path)?.running)throw new Error("a merge-all is already running for this repo");let o=(await $r(r.path)).filter(vf).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:e,total:o.length,current:o[0].number,queue:o.map(a=>({number:a.number,title:a.title})),merged:[],skipped:[],failed:[]};return yf.set(r.path,s),aC(s,o,{listPrs:()=>$r(r.path),merge:a=>Co(r.path,a,{method:e}),sleep:rC,onMerged:n}).catch(()=>{}),{ok:!0,repo:r.path,total:s.total,queue:o.map(a=>a.number)}}async function sC(t,e){let n=Date.now()+(e.settleMaxMs??nC),r=null;for(;;){let o=null;try{if(o=await e.listPrs(),r=null,!o.some(a=>t.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 e.sleep(eC)}}async function aC(t,e,n){try{let r=e;for(let o=0;o<e.length;o++){let s=e[o];if(t.current=s.number,o>0)try{r=await sC(e.slice(o).map(i=>i.number),n)}catch(i){for(let c of e.slice(o))t.failed.push({number:c.number,title:c.title,reason:`couldn't re-check PR state: ${Ne(i)}`});break}let a=r.find(i=>i.number===s.number);if(!a){t.skipped.push({number:s.number,title:s.title,reason:"no longer open"});continue}if(!vf(a)){t.skipped.push({number:a.number,title:a.title,reason:oC(a)});continue}try{await n.merge(a.number),t.merged.push({number:a.number,title:a.title});try{await n.onMerged?.(a)}catch{}}catch(i){t.failed.push({number:a.number,title:a.title,reason:Ne(i)})}}}finally{t.current=null,t.running=!1,t.finishedAt=Date.now(),Pe()}}async function Tf(t,{title:e,body:n="",base:r=null}={}){if(typeof e!="string"||!e.trim())throw new Error("title required");try{await $o("git",["-C",t,"push","-u","origin","HEAD"],{timeout:12e4,maxBuffer:4*1024*1024})}catch(l){throw new Error(`push failed: ${Ne(l)}`)}await VO(t);let o=n||"";if((await _e({cwd:t})).GH_TOKEN){let l=await Bl().catch(()=>null);l&&(o=`${o?`${o}
140
140
 
141
- `:""}Opened by bostrat on behalf of @${l}`)}let s=["pr","create","--title",e.trim(),"--body",o];r&&s.push("--base",r);let a;try{a=await ie(t,s)}catch(l){throw new Error(Me(l))}finally{Pe()}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 pk(t,e){let n=await tn(t),r=Number(e);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");let o;try{let i;try{i=await ie(n.path,["pr","checks",String(r),"--json","name,state,link,bucket"])}catch(c){if(i=String(c?.stdout||""),!i.trim())throw new Error(Me(c))}o=JSON.parse(i||"[]").filter(c=>c.bucket==="fail")}catch(i){if(!cf(i))throw i;let c=await ie(n.path,["pr","view",String(r),"--json","headRefOid"]),l=await sk(n.path,JSON.parse(c).headRefOid);if(l===null)throw new Error(Me(i));o=ak(l).map(rk).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=CO(i.link),l=null;c&&!s.has(c)&&(s.add(c),l=await ie(n.path,["run","view",c,"--log-failed"]).then(u=>MO(u)).catch(()=>null)),a.push({name:i.name,link:i.link||null,log:l})}return a}function CO(t){return String(t||"").match(/\/actions\/runs\/(\d+)/)?.[1]??null}function MO(t,{maxLines:e=400,maxBytes:n=64*1024}={}){let r=String(t||""),o=r.split(`
141
+ `:""}Opened by bostrat on behalf of @${l}`)}let s=["pr","create","--title",e.trim(),"--body",o];r&&s.push("--base",r);let a;try{a=await ue(t,s)}catch(l){throw new Error(Ne(l))}finally{Pe()}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 Mk(t,e){let n=await nn(t),r=Number(e);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");let o;try{let i;try{i=await ue(n.path,["pr","checks",String(r),"--json","name,state,link,bucket"])}catch(c){if(i=String(c?.stdout||""),!i.trim())throw new Error(Ne(c))}o=JSON.parse(i||"[]").filter(c=>c.bucket==="fail")}catch(i){if(!xf(i))throw i;let c=await ue(n.path,["pr","view",String(r),"--json","headRefOid"]),l=await Ak(n.path,JSON.parse(c).headRefOid);if(l===null)throw new Error(Ne(i));o=Ek(l).map(vk).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=iC(i.link),l=null;c&&!s.has(c)&&(s.add(c),l=await ue(n.path,["run","view",c,"--log-failed"]).then(u=>cC(u)).catch(()=>null)),a.push({name:i.name,link:i.link||null,log:l})}return a}function iC(t){return String(t||"").match(/\/actions\/runs\/(\d+)/)?.[1]??null}function cC(t,{maxLines:e=400,maxBytes:n=64*1024}={}){let r=String(t||""),o=r.split(`
142
142
  `);return o.length>e&&(r=`\u2026 (${o.length-e} earlier lines truncated)
143
143
  `+o.slice(-e).join(`
144
144
  `)),Buffer.byteLength(r)>n&&(r=`\u2026 (truncated)
145
- `+r.slice(-n)),r}function Me(t){return String(t?.stderr||t?.message||t||"").trim().split(`
146
- `).find(n=>n.trim())||"gh failed"}var ko,bO,lc,af,ok,xO,bo,nk,vO,TO,Ks,Gs,EO,_O,IO,of,zs=M(()=>{Qn();Qt();Bn();Cs();cc();ct();ko=gO(wO),bO={timeout:3e4,maxBuffer:8*1024*1024};lc=null;af="number,title,url,headRefName,headRefOid,baseRefName,isDraft,author,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup,autoMergeRequest,additions,deletions,createdAt,updatedAt",ok=af.replace("statusCheckRollup,","");xO=9e4,bo=new Map;nk=(t,e)=>t.number-e.number;vO=3e4,TO=1500,Ks=new Map;Gs=new Set(["squash","merge","rebase"]);EO=2500,_O=9e4,IO=t=>new Promise(e=>setTimeout(e,t));of=new Map});function dc(t,e=Date.now()){let n=null;for(let r of t||[]){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&&e-n.ts>NO?null:n}function BO(t,e){return t?.firstSeen==null||e?.ts==null||t.firstSeen<e.ts}async function mk(t){let e=t?.workspace?.branch;if(!e)return;let n;try{n=await L(t)}catch{return}let r=dc(n);if(r==null)return;let o=(t.boxes||[]).find(l=>l.name===t.leadBox);if(await Yi(t.leadBox,o?.agent).catch(()=>!1))return;let s=Date.now();if(s-(ff.get(t.id)||0)<PO)return;ff.set(t.id,s);let a;try{a=await Sr(t.cwd,{caller:"reconcile"})}catch{return}let i=(a||[]).find(l=>l.headRefName===e);if(!i)return;let c=await st(t.cwd).catch(()=>null);if(c){let{link:l,created:u}=await ne({repo:c,number:i.number,trackId:t.id,url:i.url,headRef:e,title:i.title,source:"reconciled"});if(!u&&!(l?.trackId===t.id&&await Ms(c,i.number))){if(!BO(l,r))return;let d=await L(t).catch(()=>null);if(d&&dc(d)==null)return;await I(t,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:t.leadBox,payload:{ts:Date.now(),change:"pushed",number:i.number,url:i.url,title:i.title,branch:e,repo:c}});return}}await I(t,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:t.leadBox,payload:{ts:Date.now(),change:"opened",number:i.number,url:i.url,title:i.title,branch:e,...c?{repo:c}:{}}}).catch(()=>{}),ff.delete(t.id)}var PO,ff,NO,pf=M(()=>{ct();zs();Qn();Bn();Xi();PO=6e3,ff=new Map,NO=30*6e4});import mf from"node:os";import{execFile as DO}from"node:child_process";import{promisify as jO}from"node:util";async function fc(){if(process.platform!=="darwin")return mf.freemem();try{let{stdout:t}=await LO("vm_stat",[],{timeout:3e3}),e=Number(/page size of (\d+) bytes/.exec(t)?.[1])||4096,n=o=>Number(new RegExp(`Pages ${o}:\\s+(\\d+)\\.`).exec(t)?.[1])||0,r=(n("free")+n("inactive")+n("speculative"))*e;return r>0?r:mf.freemem()}catch{return mf.freemem()}}var LO,hf=M(()=>{LO=jO(DO)});import _t from"node:fs/promises";import Rt from"node:path";import gk from"node:os";import{randomUUID as FO}from"node:crypto";import{execFile as UO}from"node:child_process";import{promisify as HO}from"node:util";import{chromium as WO}from"playwright-core";async function De(){return Tr||(wf||=(async()=>{try{Tr=JSON.parse(await _t.readFile(bk,"utf8"))}catch{Tr={mocks:[]}}finally{wf=null}return Tr.mocks||=[],Tr})(),wf)}async function ce(){await zt(bk,Tr)}function Sk(t,e){Be(t,e.v,e.videoRel?.endsWith(".webm")?"webm":"mp4"),e.posterRel&&Be(t,e.v,"png")}function qt(t,e,n={}){return I({id:t.trackId,cwd:t.cwd},{type:"mock.state.changed",actor:"orchestrator",source:"orchestrator",boxId:t.box||null,provider:t.agent||null,payload:{ts:Date.now(),change:e,mockId:t.id,name:t.name,...t.group?{group:t.group}:{},...t.kind==="video"?{kind:"video"}:{},...n}}).catch(()=>{})}function le(t,e){let n=Ys(t.cwd);return{html:Rt.join(n,`${t.id}.v${e}.html`),png:Rt.join(n,`${t.id}.v${e}.png`)}}function Js(t,e,n){if(!e)return null;let r=n==="html"?e.htmlRel:n==="png"?e.pngRel??e.posterRel??null:n==="video"?e.videoRel??null:null;return r?Rt.join(t.cwd,r):null}function ke(t,e=null){let n=t.versions||[];return e!=null?n.find(r=>r.v===Number(e))||null:n.length?n[n.length-1]:null}function bf(t){return t.length<24||t.readUInt32BE(12)!==1229472850?null:{width:t.readUInt32BE(16),height:t.readUInt32BE(20)}}function pc(t){return Buffer.isBuffer(t)&&t.length>24&&t.subarray(0,8).equals(ZO)}function QO(t){return!Buffer.isBuffer(t)||t.length<32?null:t.subarray(4,8).toString("latin1")==="ftyp"?{ext:"mp4",mime:"video/mp4"}:t.readUInt32BE(0)===440786851?{ext:"webm",mime:"video/webm"}:null}async function tC(t){let e=Buffer.alloc(24),n=await _t.open(t,"r");try{await n.read(e,0,24,0)}finally{await n.close()}return e}function eC({imgW:t,imgH:e,bbox:n,pad:r,align:o=1}){if(!n||!(t>0)||!(e>0))return null;let s=n.right-n.left+1,a=n.bottom-n.top+1;if(s<=0||a<=0||s>=t*.9&&a>=e*.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 nC(t,e){return t.evaluate(async n=>{let r=new Image;await new Promise((m,w)=>{r.onload=m,r.onerror=()=>w(new Error("decode failed")),r.src=`data:image/png;base64,${n}`});let o=r.naturalWidth,s=r.naturalHeight;if(!o||!s||o*s>24e6)return null;let a=document.createElement("canvas");a.width=o,a.height=s;let i=a.getContext("2d",{willReadFrequently:!0});i.drawImage(r,0,0);let c=i.getImageData(0,0,o,s).data,l=[c[0],c[1],c[2]],u=o,d=s,f=-1,p=-1;for(let m=0;m<s;m++)for(let w=m*o*4,y=0;y<o;y++,w+=4)Math.abs(c[w]-l[0])+Math.abs(c[w+1]-l[1])+Math.abs(c[w+2]-l[2])>24&&(y<u&&(u=y),y>f&&(f=y),m<d&&(d=m),p=m);return f<0?null:{imgW:o,imgH:s,bg:l,bbox:{left:u,top:d,right:f,bottom:p}}},e.toString("base64"))}async function rC(t,e,{bg:n,crop:r}){let o=await t.evaluate(async({b64:s,bg:a,crop:i})=>{let c=new Image;await new Promise((d,f)=>{c.onload=d,c.onerror=()=>f(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:e.toString("base64"),bg:n,crop:r});return Buffer.from(o,"base64")}async function oC({htmlPath:t,outPath:e,width:n}){let r=Date.now(),o;try{o=await WO.launch({executablePath:KO,args:["--disable-gpu"],timeout:3e4})}catch(s){throw new be("chromium failed to launch",s?.message||"")}try{let a=await(await o.newContext({viewport:{width:n,height:800},deviceScaleFactor:vo})).newPage();a.setDefaultTimeout(To),await a.goto(`file://${t}`,{waitUntil:"load",timeout:To}),await a.waitForTimeout(250);let i;for(let l=1;;l++)try{i=await a.screenshot({fullPage:!0,timeout:To});break}catch(u){if(l>=3||!/captureScreenshot|Unable to capture/i.test(u?.message||""))throw u;await a.waitForTimeout(500)}try{let l=await nC(a,i),u=l&&eC({...l,pad:zO*vo,align:vo});u&&(i=await rC(a,i,{bg:l.bg,crop:u}))}catch{}if(i.length<kk)throw new be(`capture produced a ${i.length}-byte image`);let c=bf(i);if(!c)throw new be("output is not a PNG");return await _t.writeFile(e,i),{width:Math.round(c.width/vo),height:Math.round(c.height/vo),dpr:vo,renderMs:Date.now()-r}}catch(s){throw s instanceof be?s:new be(/timeout/i.test(s?.message||"")?`render timed out after ${To}ms`:"chromium render failed",s?.message||"")}finally{await o.close().catch(()=>{})}}async function wk({htmlPath:t,outPath:e,width:n}){let r=await _t.mkdtemp(Rt.join(gk.tmpdir(),"bostrat-mock-profile-")),o=Date.now(),s="";try{try{s=(await yf(GO,["--headless","--no-remote","--profile",r,`--window-size=${n}`,"--screenshot",e,`file://${t}`],{env:{...process.env,MOZ_HEADLESS:"1"},timeout:To,killSignal:"SIGKILL",maxBuffer:4194304})).stderr||""}catch(c){throw s=c?.stderr||"",new be(c?.killed?`render timed out after ${To}ms`:"firefox exited non-zero",s)}let a=await _t.stat(e).catch(()=>null);if(!a||a.size<kk)throw new be(`render produced ${a?`a ${a.size}-byte file`:"no file"} (silent no-op \u2014 another firefox holding the profile?)`,s);let i=bf(await tC(e));if(!i)throw new be("output is not a PNG",s);return{width:i.width,height:i.height,dpr:1,renderMs:Date.now()-o}}finally{await _t.rm(r,{recursive:!0,force:!0}).catch(()=>{})}}async function sC(t){if(qO==="firefox")return wk(t);try{return await oC(t)}catch(e){if(/failed to launch/i.test(e?.message||""))return wk(t);throw e}}function vk(t){return gf=gf.then(t,t),gf}async function Tk(t,e){let n=await De(),r=n.mocks.find(o=>o.id===t);if(r){r.state="rendering",await ce(),await qt(r,"rendering",{version:e});try{let o=await fc();if(o<JO)throw new be(`box is low on memory (${Math.round(o/1e6)} MB available) \u2014 not spawning a browser`);let s=le(r,e),a=await aC({htmlPath:s.html,outPath:s.png,width:r.width});if(!n.mocks.some(i=>i.id===t)){await _t.rm(s.png,{force:!0}).catch(()=>{});return}kf(r,{v:e,source:"html",htmlRel:Rt.relative(r.cwd,s.html),pngRel:Rt.relative(r.cwd,s.png),width:a.width,height:a.height,dpr:a.dpr,renderMs:a.renderMs,createdAt:Date.now()}),await ce(),await qt(r,"ready",{version:e,width:a.width,height:a.height,dpr:a.dpr}),Ne(r),Be(r,e,"png")}catch(o){if(!n.mocks.some(s=>s.id===t))return;r.state="error",r.error=o?.message||String(o),await ce(),await qt(r,"error",{version:e,error:r.error}),Ne(r)}}}function kf(t,e){t.versions=(t.versions||[]).filter(r=>r.v!==e.v).concat(e),t.versions.sort((r,o)=>r.v-o.v);let n=t.versions[t.versions.length-1];t.readyVersion=n.v,t.height=n.height,t.dpr=n.dpr,t.renderMs=n.renderMs??null,n.v===t.version&&(t.state="ready",t.error=null)}function iC({trackId:t,name:e,cwd:n,width:r}){if(!t)throw new Error("trackId required");if(typeof e!="string"||!e.trim())throw new Error("name (string) required");if(!n)throw new Error("cwd required");let o=r==null?VO:Number(r);if(!Number.isInteger(o)||o<320||o>4e3)throw new Error("invalid width (320-4000)");return o}async function Xs({trackId:t,group:e}={}){let n=await De(),r=t?n.mocks.filter(o=>o.trackId===t):n.mocks;return e&&(r=r.filter(o=>o.group===e)),r.map(o=>({...o}))}async function en(t){let n=(await De()).mocks.find(r=>r.id===t);return n?{...n}:null}function Ak({html:t,image:e,video:n}){if([typeof t=="string"&&t.trim(),!!e,!!n].filter(Boolean).length!==1)throw new Error("exactly one of html (string), image (png) or video (mp4/webm) required");if(e&&!pc(e))throw new Error("image must be a PNG");if(n){let o=QO(n);if(!o)throw new Error("video must be an mp4 or webm (magic-byte check failed)");if(n.length>hk)throw new Error(`video must be ${hk/(1024*1024)} MB or smaller (got ${Math.round(n.length/(1024*1024))} MB)`);return o}return null}async function Ek({trackId:t,name:e,html:n,image:r,video:o,cwd:s,width:a,group:i,box:c,agent:l,prompt:u}){let d=iC({trackId:t,name:e,cwd:s,width:a}),f=typeof n=="string"&&n.trim(),p=Ak({html:n,image:r,video:o}),m=await De(),w={id:FO().slice(0,8),trackId:t,box:c||null,agent:l||null,name:e.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:f?"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 _t.mkdir(Ys(s),{recursive:!0}),m.mocks.push(w),f?(await _t.writeFile(le(w,1).html,n),await ce(),await qt(w,"created"),Ne(w),Be(w,1,"html"),vk(()=>Tk(w.id,1))):o?(await Ik(w,1,o,p),await ce(),await qt(w,"created"),await qt(w,"ready",{version:1,width:w.width,height:w.height,dpr:w.dpr,durationS:w.versions[0]?.durationS??null}),Ne(w),Sk(w,w.versions[0])):(await Rk(w,1,r),await ce(),await qt(w,"created"),await qt(w,"ready",{version:1,width:w.width,height:w.height,dpr:w.dpr}),Ne(w),Be(w,1,"png")),{...w}}async function _k(t,{html:e,image:n,video:r,width:o}={}){let a=(await De()).mocks.find(u=>u.id===t);if(!a)throw new Error("mock not found");let i=typeof e=="string"&&e.trim(),c=Ak({html:e,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 _t.mkdir(Ys(a.cwd),{recursive:!0}),i?(a.state="queued",await _t.writeFile(le(a,l).html,e),await ce(),await qt(a,"updated",{version:l}),Ne(a),Be(a,l,"html"),vk(()=>Tk(a.id,l))):r?(await Ik(a,l,r,c),await ce(),await qt(a,"updated",{version:l}),await qt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr,durationS:ke(a)?.durationS??null}),Ne(a),Sk(a,a.versions.find(u=>u.v===l))):(await Rk(a,l,n),await ce(),await qt(a,"updated",{version:l}),await qt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr}),Ne(a),Be(a,l,"png")),{...a}}async function cC(t){try{let{stdout:e}=await yf(YO,["-v","error","-print_format","json","-show_format","-show_streams",t],{timeout:xk,killSignal:"SIGKILL",maxBuffer:4194304}),n=JSON.parse(e),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 lC(t,e){try{await yf(XO,["-y","-v","error","-i",t,"-frames:v","1","-f","image2",e],{timeout:xk,killSignal:"SIGKILL",maxBuffer:4*1024*1024});let n=await _t.stat(e).catch(()=>null);return!!n&&n.size>0}catch{return!1}}async function Ik(t,e,n,r){let o=Ys(t.cwd),s=Rt.join(o,`${t.id}.v${e}.${r.ext}`),a=Rt.join(o,`${t.id}.v${e}.poster.png`);await _t.writeFile(s,n);let i=await cC(s),c=await lC(s,a);kf(t,{v:e,source:"video",htmlRel:null,pngRel:null,videoRel:Rt.relative(t.cwd,s),posterRel:c?Rt.relative(t.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&&(t.width=i.width)}async function Rk(t,e,n){let r=bf(n);if(!r)throw new Error("image must be a PNG");let o=le(t,e);await _t.writeFile(o.png,n),kf(t,{v:e,source:"image",htmlRel:null,pngRel:Rt.relative(t.cwd,o.png),width:r.width,height:r.height,dpr:1,renderMs:null,createdAt:Date.now()}),t.width=r.width}async function $k(t){let e=await De(),n=e.mocks.find(o=>o.id===t);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?e.mocks.filter(o=>o.trackId===n.trackId&&o.group===n.group&&o.id!==t&&o.readyVersion!=null).map(o=>({mockId:o.id,name:o.name})):[];return await qt(n,"picked",{version:n.readyVersion,siblings:r}),{mock:{...n},siblings:r}}async function Ok(t){let e=await De(),n=e.mocks.findIndex(o=>o.id===t);if(n===-1)throw new Error("mock not found");let r=e.mocks[n];e.mocks.splice(n,1);for(let o=1;o<=r.version;o++){let s=le(r,o);await _t.rm(s.html,{force:!0}).catch(()=>{}),await _t.rm(s.png,{force:!0}).catch(()=>{})}for(let o of r.versions||[])for(let s of[o.videoRel,o.posterRel])s&&await _t.rm(Rt.join(r.cwd,s),{force:!0}).catch(()=>{});return await ce(),await qt(r,"deleted"),me("mocks",r.id).catch(()=>{}),{ok:!0,id:t,name:r.name}}async function Ck(t){let n=(await De()).mocks.filter(i=>i.trackId===t.id);if(!n.length)return 0;let r=Rt.join(yk,"mock-archive",t.id),o=Ys(t.cwd),s=Rt.join(r,".bostrat","mocks");await _t.mkdir(s,{recursive:!0});let a=await _t.readdir(o).catch(()=>[]);for(let i of a)await _t.copyFile(Rt.join(o,i),Rt.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 _t.stat(Rt.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=t.name||t.id,i.updatedAt=Date.now(),Ne(i)}return await ce(),n.length}async function Mk(t){let e=await De(),n=e.mocks.filter(r=>r.trackId===t);if(n.length){e.mocks=e.mocks.filter(r=>r.trackId!==t),await ce();for(let r of n)me("mocks",r.id).catch(()=>{})}return n.length}async function Pk(){if(!wt())return{pushed:0,source:"unconfigured"};let{records:t,source:e}=await $t("mocks");if(e!=="plane"||t.length)return{pushed:0,source:e};let n=await De();for(let r of n.mocks){await Ne(r);for(let o of r.versions||[])o.htmlRel&&await Be(r,o.v,"html"),(o.pngRel||o.posterRel)&&await Be(r,o.v,"png"),o.videoRel&&await Be(r,o.v,o.videoRel.endsWith(".webm")?"webm":"mp4")}return{pushed:n.mocks.length,source:"plane"}}var yf,yk,bk,qO,KO,GO,VO,vo,zO,kk,To,JO,hk,YO,XO,xk,be,Tr,wf,Ne,Be,Ys,ZO,aC,gf,Ao=M(()=>{ct();gn();hf();bn();yf=HO(UO),yk=process.env.BOSTRAT_STATE_DIR||Rt.join(process.env.HOME||gk.tmpdir(),".bostrat"),bk=Rt.join(yk,"mocks.json"),qO=process.env.BOSTRAT_MOCK_ENGINE||"chromium",KO=process.env.BOSTRAT_CHROMIUM_BIN||"/usr/bin/chromium",GO=process.env.BOSTRAT_FIREFOX_BIN||"firefox",VO=1300,vo=2,zO=32,kk=1500,To=Number(process.env.BOSTRAT_MOCK_TIMEOUT_MS)||75e3,JO=700*1024*1024,hk=100*1024*1024,YO=process.env.BOSTRAT_FFPROBE_BIN||"ffprobe",XO=process.env.BOSTRAT_FFMPEG_BIN||"ffmpeg",xk=2e4,be=class extends Error{constructor(e,n=""){super(n?`${e}
145
+ `+r.slice(-n)),r}function Ne(t){return String(t?.stderr||t?.message||t||"").trim().split(`
146
+ `).find(n=>n.trim())||"gh failed"}var $o,zO,Sc,kf,Tk,YO,Ro,Sk,ZO,QO,ta,ea,eC,nC,rC,yf,ra=M(()=>{ar();Jt();Fn();Us();xc();at();$o=GO(KO),zO={timeout:3e4,maxBuffer:8*1024*1024};Sc=null;kf="number,title,url,headRefName,headRefOid,baseRefName,isDraft,author,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup,autoMergeRequest,additions,deletions,createdAt,updatedAt",Tk=kf.replace("statusCheckRollup,","");YO=9e4,Ro=new Map;Sk=(t,e)=>t.number-e.number;ZO=3e4,QO=1500,ta=new Map;ea=new Set(["squash","merge","rebase"]);eC=2500,nC=9e4,rC=t=>new Promise(e=>setTimeout(e,t));yf=new Map});function Tc(t,e=Date.now()){let n=null;for(let r of t||[]){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&&e-n.ts>uC?null:n}function dC(t,e){return t?.firstSeen==null||e?.ts==null||t.firstSeen<e.ts}async function Nk(t){let e=t?.workspace?.branch;if(!e)return;let n;try{n=await F(t)}catch{return}let r=Tc(n);if(r==null)return;let o=(t.boxes||[]).find(l=>l.name===t.leadBox);if(await lc(t.leadBox,o?.agent).catch(()=>!1))return;let s=Date.now();if(s-(Af.get(t.id)||0)<lC)return;Af.set(t.id,s);let a;try{a=await $r(t.cwd,{caller:"reconcile"})}catch{return}let i=(a||[]).find(l=>l.headRefName===e);if(!i)return;let c=await lt(t.cwd).catch(()=>null);if(c){let{link:l,created:u}=await oe({repo:c,number:i.number,trackId:t.id,url:i.url,headRef:e,title:i.title,source:"reconciled"});if(!u&&!(l?.trackId===t.id&&await Hs(c,i.number))){if(!dC(l,r))return;let f=await F(t).catch(()=>null);if(f&&Tc(f)==null)return;await I(t,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:t.leadBox,payload:{ts:Date.now(),change:"pushed",number:i.number,url:i.url,title:i.title,branch:e,repo:c}});return}}await I(t,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:t.leadBox,payload:{ts:Date.now(),change:"opened",number:i.number,url:i.url,title:i.title,branch:e,...c?{repo:c}:{}}}).catch(()=>{}),Af.delete(t.id)}var lC,Af,uC,Ef=M(()=>{at();ra();ar();Fn();uc();lC=6e3,Af=new Map,uC=30*6e4});import _f from"node:os";import{execFile as fC}from"node:child_process";import{promisify as pC}from"node:util";async function Ac(){if(process.platform!=="darwin")return _f.freemem();try{let{stdout:t}=await mC("vm_stat",[],{timeout:3e3}),e=Number(/page size of (\d+) bytes/.exec(t)?.[1])||4096,n=o=>Number(new RegExp(`Pages ${o}:\\s+(\\d+)\\.`).exec(t)?.[1])||0,r=(n("free")+n("inactive")+n("speculative"))*e;return r>0?r:_f.freemem()}catch{return _f.freemem()}}var mC,If=M(()=>{mC=pC(fC)});import $t from"node:fs/promises";import Ct from"node:path";import Bk from"node:os";import{randomUUID as hC}from"node:crypto";import{execFile as wC}from"node:child_process";import{promisify as gC}from"node:util";import{chromium as yC}from"playwright-core";async function je(){return Cr||(Rf||=(async()=>{try{Cr=JSON.parse(await $t.readFile(Lk,"utf8"))}catch{Cr={mocks:[]}}finally{Rf=null}return Cr.mocks||=[],Cr})(),Rf)}async function de(){await Yt(Lk,Cr)}function Hk(t,e){Be(t,e.v,e.videoRel?.endsWith(".webm")?"webm":"mp4"),e.posterRel&&Be(t,e.v,"png")}function Gt(t,e,n={}){return I({id:t.trackId,cwd:t.cwd},{type:"mock.state.changed",actor:"orchestrator",source:"orchestrator",boxId:t.box||null,provider:t.agent||null,payload:{ts:Date.now(),change:e,mockId:t.id,name:t.name,...t.group?{group:t.group}:{},...t.kind==="video"?{kind:"video"}:{},...n}}).catch(()=>{})}function fe(t,e){let n=sa(t.cwd);return{html:Ct.join(n,`${t.id}.v${e}.html`),png:Ct.join(n,`${t.id}.v${e}.png`)}}function oa(t,e,n){if(!e)return null;let r=n==="html"?e.htmlRel:n==="png"?e.pngRel??e.posterRel??null:n==="video"?e.videoRel??null:null;return r?Ct.join(t.cwd,r):null}function ve(t,e=null){let n=t.versions||[];return e!=null?n.find(r=>r.v===Number(e))||null:n.length?n[n.length-1]:null}function Cf(t){return t.length<24||t.readUInt32BE(12)!==1229472850?null:{width:t.readUInt32BE(16),height:t.readUInt32BE(20)}}function Ec(t){return Buffer.isBuffer(t)&&t.length>24&&t.subarray(0,8).equals(_C)}function IC(t){return!Buffer.isBuffer(t)||t.length<32?null:t.subarray(4,8).toString("latin1")==="ftyp"?{ext:"mp4",mime:"video/mp4"}:t.readUInt32BE(0)===440786851?{ext:"webm",mime:"video/webm"}:null}async function RC(t){let e=Buffer.alloc(24),n=await $t.open(t,"r");try{await n.read(e,0,24,0)}finally{await n.close()}return e}function $C({imgW:t,imgH:e,bbox:n,pad:r,align:o=1}){if(!n||!(t>0)||!(e>0))return null;let s=n.right-n.left+1,a=n.bottom-n.top+1;if(s<=0||a<=0||s>=t*.9&&a>=e*.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 OC(t,e){return t.evaluate(async n=>{let r=new Image;await new Promise((h,w)=>{r.onload=h,r.onerror=()=>w(new Error("decode failed")),r.src=`data:image/png;base64,${n}`});let o=r.naturalWidth,s=r.naturalHeight;if(!o||!s||o*s>24e6)return null;let a=document.createElement("canvas");a.width=o,a.height=s;let i=a.getContext("2d",{willReadFrequently:!0});i.drawImage(r,0,0);let c=i.getImageData(0,0,o,s).data,l=[c[0],c[1],c[2]],u=o,f=s,d=-1,p=-1;for(let h=0;h<s;h++)for(let w=h*o*4,y=0;y<o;y++,w+=4)Math.abs(c[w]-l[0])+Math.abs(c[w+1]-l[1])+Math.abs(c[w+2]-l[2])>24&&(y<u&&(u=y),y>d&&(d=y),h<f&&(f=h),p=h);return d<0?null:{imgW:o,imgH:s,bg:l,bbox:{left:u,top:f,right:d,bottom:p}}},e.toString("base64"))}async function CC(t,e,{bg:n,crop:r}){let o=await t.evaluate(async({b64:s,bg:a,crop:i})=>{let c=new Image;await new Promise((f,d)=>{c.onload=f,c.onerror=()=>d(new Error("decode failed")),c.src=`data:image/png;base64,${s}`});let l=document.createElement("canvas");l.width=i.outW,l.height=i.outH;let u=l.getContext("2d");return u.fillStyle=`rgb(${a[0]},${a[1]},${a[2]})`,u.fillRect(0,0,i.outW,i.outH),u.drawImage(c,i.sx,i.sy,i.sw,i.sh,i.dx,i.dy,i.sw,i.sh),l.toDataURL("image/png").split(",")[1]},{b64:e.toString("base64"),bg:n,crop:r});return Buffer.from(o,"base64")}async function MC({htmlPath:t,outPath:e,width:n}){let r=Date.now(),o;try{o=await yC.launch({executablePath:kC,args:["--disable-gpu"],timeout:3e4})}catch(s){throw new Se("chromium failed to launch",s?.message||"")}try{let a=await(await o.newContext({viewport:{width:n,height:800},deviceScaleFactor:Mo})).newPage();a.setDefaultTimeout(No),await a.goto(`file://${t}`,{waitUntil:"load",timeout:No}),await a.waitForTimeout(250);let i;for(let l=1;;l++)try{i=await a.screenshot({fullPage:!0,timeout:No});break}catch(u){if(l>=3||!/captureScreenshot|Unable to capture/i.test(u?.message||""))throw u;await a.waitForTimeout(500)}try{let l=await OC(a,i),u=l&&$C({...l,pad:vC*Mo,align:Mo});u&&(i=await CC(a,i,{bg:l.bg,crop:u}))}catch{}if(i.length<Fk)throw new Se(`capture produced a ${i.length}-byte image`);let c=Cf(i);if(!c)throw new Se("output is not a PNG");return await $t.writeFile(e,i),{width:Math.round(c.width/Mo),height:Math.round(c.height/Mo),dpr:Mo,renderMs:Date.now()-r}}catch(s){throw s instanceof Se?s:new Se(/timeout/i.test(s?.message||"")?`render timed out after ${No}ms`:"chromium render failed",s?.message||"")}finally{await o.close().catch(()=>{})}}async function Dk({htmlPath:t,outPath:e,width:n}){let r=await $t.mkdtemp(Ct.join(Bk.tmpdir(),"bostrat-mock-profile-")),o=Date.now(),s="";try{try{s=(await Of(xC,["--headless","--no-remote","--profile",r,`--window-size=${n}`,"--screenshot",e,`file://${t}`],{env:{...process.env,MOZ_HEADLESS:"1"},timeout:No,killSignal:"SIGKILL",maxBuffer:4194304})).stderr||""}catch(c){throw s=c?.stderr||"",new Se(c?.killed?`render timed out after ${No}ms`:"firefox exited non-zero",s)}let a=await $t.stat(e).catch(()=>null);if(!a||a.size<Fk)throw new Se(`render produced ${a?`a ${a.size}-byte file`:"no file"} (silent no-op \u2014 another firefox holding the profile?)`,s);let i=Cf(await RC(e));if(!i)throw new Se("output is not a PNG",s);return{width:i.width,height:i.height,dpr:1,renderMs:Date.now()-o}}finally{await $t.rm(r,{recursive:!0,force:!0}).catch(()=>{})}}async function NC(t){if(bC==="firefox")return Dk(t);try{return await MC(t)}catch(e){if(/failed to launch/i.test(e?.message||""))return Dk(t);throw e}}function Wk(t){return $f=$f.then(t,t),$f}async function qk(t,e){let n=await je(),r=n.mocks.find(o=>o.id===t);if(r){r.state="rendering",await de(),await Gt(r,"rendering",{version:e});try{let o=await Ac();if(o<TC)throw new Se(`box is low on memory (${Math.round(o/1e6)} MB available) \u2014 not spawning a browser`);let s=fe(r,e),a=await PC({htmlPath:s.html,outPath:s.png,width:r.width});if(!n.mocks.some(i=>i.id===t)){await $t.rm(s.png,{force:!0}).catch(()=>{});return}Mf(r,{v:e,source:"html",htmlRel:Ct.relative(r.cwd,s.html),pngRel:Ct.relative(r.cwd,s.png),width:a.width,height:a.height,dpr:a.dpr,renderMs:a.renderMs,createdAt:Date.now()}),await de(),await Gt(r,"ready",{version:e,width:a.width,height:a.height,dpr:a.dpr}),De(r),Be(r,e,"png")}catch(o){if(!n.mocks.some(s=>s.id===t))return;r.state="error",r.error=o?.message||String(o),await de(),await Gt(r,"error",{version:e,error:r.error}),De(r)}}}function Mf(t,e){t.versions=(t.versions||[]).filter(r=>r.v!==e.v).concat(e),t.versions.sort((r,o)=>r.v-o.v);let n=t.versions[t.versions.length-1];t.readyVersion=n.v,t.height=n.height,t.dpr=n.dpr,t.renderMs=n.renderMs??null,n.v===t.version&&(t.state="ready",t.error=null)}function DC({trackId:t,name:e,cwd:n,width:r}){if(!t)throw new Error("trackId required");if(typeof e!="string"||!e.trim())throw new Error("name (string) required");if(!n)throw new Error("cwd required");let o=r==null?SC:Number(r);if(!Number.isInteger(o)||o<320||o>4e3)throw new Error("invalid width (320-4000)");return o}async function aa({trackId:t,group:e}={}){let n=await je(),r=t?n.mocks.filter(o=>o.trackId===t):n.mocks;return e&&(r=r.filter(o=>o.group===e)),r.map(o=>({...o}))}async function rn(t){let n=(await je()).mocks.find(r=>r.id===t);return n?{...n}:null}function Kk({html:t,image:e,video:n}){if([typeof t=="string"&&t.trim(),!!e,!!n].filter(Boolean).length!==1)throw new Error("exactly one of html (string), image (png) or video (mp4/webm) required");if(e&&!Ec(e))throw new Error("image must be a PNG");if(n){let o=IC(n);if(!o)throw new Error("video must be an mp4 or webm (magic-byte check failed)");if(n.length>Pk)throw new Error(`video must be ${Pk/(1024*1024)} MB or smaller (got ${Math.round(n.length/(1024*1024))} MB)`);return o}return null}async function Gk({trackId:t,name:e,html:n,image:r,video:o,cwd:s,width:a,group:i,box:c,agent:l,prompt:u}){let f=DC({trackId:t,name:e,cwd:s,width:a}),d=typeof n=="string"&&n.trim(),p=Kk({html:n,image:r,video:o}),h=await je(),w={id:hC().slice(0,8),trackId:t,box:c||null,agent:l||null,name:e.trim(),prompt:u?String(u).slice(0,500):null,group:i?String(i).trim():null,cwd:s,width:f,height:null,dpr:null,state:"queued",source:d?"html":o?"video":"image",kind:o?"video":"image",version:1,readyVersion:null,versions:[],error:null,renderMs:null,createdAt:Date.now(),updatedAt:Date.now()};return await $t.mkdir(sa(s),{recursive:!0}),h.mocks.push(w),d?(await $t.writeFile(fe(w,1).html,n),await de(),await Gt(w,"created"),De(w),Be(w,1,"html"),Wk(()=>qk(w.id,1))):o?(await zk(w,1,o,p),await de(),await Gt(w,"created"),await Gt(w,"ready",{version:1,width:w.width,height:w.height,dpr:w.dpr,durationS:w.versions[0]?.durationS??null}),De(w),Hk(w,w.versions[0])):(await Jk(w,1,r),await de(),await Gt(w,"created"),await Gt(w,"ready",{version:1,width:w.width,height:w.height,dpr:w.dpr}),De(w),Be(w,1,"png")),{...w}}async function Vk(t,{html:e,image:n,video:r,width:o}={}){let a=(await je()).mocks.find(u=>u.id===t);if(!a)throw new Error("mock not found");let i=typeof e=="string"&&e.trim(),c=Kk({html:e,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 $t.mkdir(sa(a.cwd),{recursive:!0}),i?(a.state="queued",await $t.writeFile(fe(a,l).html,e),await de(),await Gt(a,"updated",{version:l}),De(a),Be(a,l,"html"),Wk(()=>qk(a.id,l))):r?(await zk(a,l,r,c),await de(),await Gt(a,"updated",{version:l}),await Gt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr,durationS:ve(a)?.durationS??null}),De(a),Hk(a,a.versions.find(u=>u.v===l))):(await Jk(a,l,n),await de(),await Gt(a,"updated",{version:l}),await Gt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr}),De(a),Be(a,l,"png")),{...a}}async function BC(t){try{let{stdout:e}=await Of(AC,["-v","error","-print_format","json","-show_format","-show_streams",t],{timeout:Uk,killSignal:"SIGKILL",maxBuffer:4194304}),n=JSON.parse(e),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 jC(t,e){try{await Of(EC,["-y","-v","error","-i",t,"-frames:v","1","-f","image2",e],{timeout:Uk,killSignal:"SIGKILL",maxBuffer:4*1024*1024});let n=await $t.stat(e).catch(()=>null);return!!n&&n.size>0}catch{return!1}}async function zk(t,e,n,r){let o=sa(t.cwd),s=Ct.join(o,`${t.id}.v${e}.${r.ext}`),a=Ct.join(o,`${t.id}.v${e}.poster.png`);await $t.writeFile(s,n);let i=await BC(s),c=await jC(s,a);Mf(t,{v:e,source:"video",htmlRel:null,pngRel:null,videoRel:Ct.relative(t.cwd,s),posterRel:c?Ct.relative(t.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&&(t.width=i.width)}async function Jk(t,e,n){let r=Cf(n);if(!r)throw new Error("image must be a PNG");let o=fe(t,e);await $t.writeFile(o.png,n),Mf(t,{v:e,source:"image",htmlRel:null,pngRel:Ct.relative(t.cwd,o.png),width:r.width,height:r.height,dpr:1,renderMs:null,createdAt:Date.now()}),t.width=r.width}async function Yk(t){let e=await je(),n=e.mocks.find(o=>o.id===t);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?e.mocks.filter(o=>o.trackId===n.trackId&&o.group===n.group&&o.id!==t&&o.readyVersion!=null).map(o=>({mockId:o.id,name:o.name})):[];return await Gt(n,"picked",{version:n.readyVersion,siblings:r}),{mock:{...n},siblings:r}}async function Xk(t){let e=await je(),n=e.mocks.findIndex(o=>o.id===t);if(n===-1)throw new Error("mock not found");let r=e.mocks[n];e.mocks.splice(n,1);for(let o=1;o<=r.version;o++){let s=fe(r,o);await $t.rm(s.html,{force:!0}).catch(()=>{}),await $t.rm(s.png,{force:!0}).catch(()=>{})}for(let o of r.versions||[])for(let s of[o.videoRel,o.posterRel])s&&await $t.rm(Ct.join(r.cwd,s),{force:!0}).catch(()=>{});return await de(),await Gt(r,"deleted"),we("mocks",r.id).catch(()=>{}),{ok:!0,id:t,name:r.name}}async function Zk(t){let n=(await je()).mocks.filter(i=>i.trackId===t.id);if(!n.length)return 0;let r=Ct.join(jk,"mock-archive",t.id),o=sa(t.cwd),s=Ct.join(r,".bostrat","mocks");await $t.mkdir(s,{recursive:!0});let a=await $t.readdir(o).catch(()=>[]);for(let i of a)await $t.copyFile(Ct.join(o,i),Ct.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 $t.stat(Ct.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=t.name||t.id,i.updatedAt=Date.now(),De(i)}return await de(),n.length}async function Qk(t){let e=await je(),n=e.mocks.filter(r=>r.trackId===t);if(n.length){e.mocks=e.mocks.filter(r=>r.trackId!==t),await de();for(let r of n)we("mocks",r.id).catch(()=>{})}return n.length}async function t0(){if(!vt())return{pushed:0,source:"unconfigured"};let{records:t,source:e}=await Mt("mocks");if(e!=="plane"||t.length)return{pushed:0,source:e};let n=await je();for(let r of n.mocks){await De(r);for(let o of r.versions||[])o.htmlRel&&await Be(r,o.v,"html"),(o.pngRel||o.posterRel)&&await Be(r,o.v,"png"),o.videoRel&&await Be(r,o.v,o.videoRel.endsWith(".webm")?"webm":"mp4")}return{pushed:n.mocks.length,source:"plane"}}var Of,jk,Lk,bC,kC,xC,SC,Mo,vC,Fk,No,TC,Pk,AC,EC,Uk,Se,Cr,Rf,De,Be,sa,_C,PC,$f,Po=M(()=>{at();kn();If();Sn();Of=gC(wC),jk=process.env.BOSTRAT_STATE_DIR||Ct.join(process.env.HOME||Bk.tmpdir(),".bostrat"),Lk=Ct.join(jk,"mocks.json"),bC=process.env.BOSTRAT_MOCK_ENGINE||"chromium",kC=process.env.BOSTRAT_CHROMIUM_BIN||"/usr/bin/chromium",xC=process.env.BOSTRAT_FIREFOX_BIN||"firefox",SC=1300,Mo=2,vC=32,Fk=1500,No=Number(process.env.BOSTRAT_MOCK_TIMEOUT_MS)||75e3,TC=700*1024*1024,Pk=100*1024*1024,AC=process.env.BOSTRAT_FFPROBE_BIN||"ffprobe",EC=process.env.BOSTRAT_FFMPEG_BIN||"ffmpeg",Uk=2e4,Se=class extends Error{constructor(e,n=""){super(n?`${e}
147
147
  ${n.trim().split(`
148
148
  `).slice(-6).join(`
149
- `)}`:e),this.name="MockRenderError"}},Tr=null,wf=null;Ne=t=>Ut("mocks",{...t},{trackId:t.trackId}).catch(()=>{}),Be=(t,e,n)=>{let r=(t.versions||[]).find(s=>s.v===e),o=n==="mp4"||n==="webm"?Js(t,r,"video"):r&&Js(t,r,n)||(n==="html"?le(t,e).html:null);return o?yn("mocks",t.id,e,n,o).catch(()=>{}):Promise.resolve()};Ys=t=>Rt.join(t,".bostrat","mocks");ZO=Buffer.from([137,80,78,71,13,10,26,10]);aC=sC,gf=Promise.resolve()});import uC from"node:fs/promises";import Lk from"node:path";import dC from"node:os";import{randomUUID as Fk}from"node:crypto";async function rn(){return nn||(xf||=(async()=>{let t=!0;try{nn=JSON.parse(await uC.readFile(Uk,"utf8"))}catch{nn={flows:[]},t=!1}finally{xf=null}if(nn.flows||=[],!t&&wt()){let{records:e,source:n}=await $t("flows").catch(()=>({records:[],source:"error"}));if(n==="plane"){for(let r of e)!r.deletedAt&&r.data?.id&&nn.flows.push(r.data);nn.flows.length&&await Eo().catch(()=>{})}}return nn})(),xf)}async function Eo(){await zt(Uk,nn)}function Sf(t,e,n={}){return I({id:t.trackId,cwd:t.cwd},{type:"flow.state.changed",actor:"orchestrator",source:"orchestrator",boxId:t.box||null,provider:t.agent||null,payload:{ts:Date.now(),change:e,flowId:t.id,name:t.name,stepCount:t.steps.length,mockIds:[...new Set(t.steps.map(r=>r.mockId))],...n}}).catch(()=>{})}async function Hk({trackId:t,steps:e,prevSteps:n=[]}){if(!Array.isArray(e)||e.length<1||e.length>Nk)throw new Error(`steps must be an array of 1-${Nk}`);let r=await Xs({trackId:t}),o=[...n],s=[];for(let i=0;i<e.length;i++){let c=e[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>Dk)throw new Error(`${l}: caption over ${Dk} chars`);let d=c.title==null?null:String(c.title).trim()||null;if(d&&d.length>jk)throw new Error(`${l}: title over ${jk} chars`);let f=String(c.mock??"").trim().replace(/^mock:/,"");if(!f)throw new Error(`${l}: mock (name or id) required`);let p=r.filter(S=>S.id===f);if(p.length||(p=r.filter(S=>S.name.toLowerCase()===f.toLowerCase())),!p.length)throw new Error(`${l}: no mock matching "${f}" in this Track \u2014 see \`bostrat-mock ls\``);if(p.length>1)throw new Error(`${l}: "${f}" is ambiguous (${p.map(S=>`mock:${S.id}`).join(", ")}) \u2014 use the id`);let m=p[0],w=null;if(c.v!=null&&(w=Number(c.v),!Number.isInteger(w)||!(m.versions||[]).some(S=>S.v===w)))throw new Error(`${l}: "${m.name}" has no captured v${c.v} to pin`);let y=o.findIndex(S=>S.mockId===m.id),k=y>=0?o.splice(y,1)[0].id:Fk().slice(0,8);s.push({id:k,mockId:m.id,caption:u,title:d,v:w})}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 pC(t){if(typeof t!="string"||!t.trim())throw new Error("name (string) required");if(t.trim().length>Bk)throw new Error(`name over ${Bk} chars`);return t.trim()}async function Wk({trackId:t}={}){let e=await rn();return(t?e.flows.filter(r=>r.trackId===t):e.flows).map(r=>({...r}))}async function mC(t){let n=(await rn()).flows.find(r=>r.id===t);return n?{...n}:null}async function qk(t){let e=await mC(t);if(!e)return null;let n=new Map((await Xs({trackId:e.trackId})).map(r=>[r.id,r]));return e.steps=e.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=ke(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}}),e}async function Kk({trackId:t,name:e,steps:n,cwd:r,box:o,agent:s}){if(!t)throw new Error("trackId required");if(!r)throw new Error("cwd required");let a=pC(e),i=await rn(),c=i.flows.find(p=>p.trackId===t&&p.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 Hk({trackId:t,steps:n}),d=Date.now(),f={id:Fk().slice(0,8),trackId:t,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(f),await Eo(),await Sf(f,"created"),mc(f),{...f}}async function Gk(t,{steps:e,note:n}={}){let o=(await rn()).flows.find(i=>i.id===t);if(!o)throw new Error("flow not found");let{steps:s,resolved:a}=await Hk({trackId:o.trackId,steps:e,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 Eo(),await Sf(o,"updated",{version:o.version,...n?{note:String(n).slice(0,200)}:{}}),mc(o),{...o}}async function Vk(t){let e=await rn(),n=e.flows.findIndex(o=>o.id===t);if(n===-1)throw new Error("flow not found");let r=e.flows[n];return e.flows.splice(n,1),await Eo(),await Sf(r,"deleted"),me("flows",r.id).catch(()=>{}),{ok:!0,id:t,name:r.name}}async function zk(t){return(await rn()).flows.filter(n=>n.steps.some(r=>r.mockId===t)).map(n=>({...n}))}async function Jk(t){let n=(await rn()).flows.filter(r=>r.trackId===t.id);for(let r of n)r.trackDeletedAt=Date.now(),r.trackName=t.name||t.id,r.updatedAt=Date.now(),mc(r);return n.length&&await Eo(),n.length}async function Yk(t){let e=await rn(),n=e.flows.filter(r=>r.trackId===t);if(n.length){e.flows=e.flows.filter(r=>r.trackId!==t),await Eo();for(let r of n)me("flows",r.id).catch(()=>{})}return n.length}async function Xk(){if(!wt())return{pushed:0,source:"unconfigured"};let{records:t,source:e}=await $t("flows");if(e!=="plane"||t.length)return{pushed:0,source:e};let n=await rn();for(let r of n.flows)await mc(r);return{pushed:n.flows.length,source:"plane"}}var fC,Uk,Nk,Bk,Dk,jk,nn,xf,mc,vf=M(()=>{ct();gn();Ao();bn();fC=process.env.BOSTRAT_STATE_DIR||Lk.join(process.env.HOME||dC.tmpdir(),".bostrat"),Uk=Lk.join(fC,"flows.json"),Nk=20,Bk=80,Dk=500,jk=80,nn=null,xf=null;mc=t=>Ut("flows",{...t},{trackId:t.trackId}).catch(()=>{})});import an from"node:fs/promises";import cn from"node:path";import hC from"node:os";import{randomUUID as wC}from"node:crypto";function Zs(t){return gC.filter(({re:e})=>e.test(t)).map(({label:e})=>e)}async function je(){return on||(Tf||=(async()=>{let t=!0;try{on=JSON.parse(await an.readFile(Qk,"utf8"))}catch{on={runbooks:[]},t=!1}finally{Tf=null}return on.runbooks||=[],!t&&wt()&&await yC().catch(()=>{}),on})(),Tf)}async function Er(){await zt(Qk,on)}function wc(t){return Qs(Ut("runbooks",{...t},{trackId:t.trackId}))}async function yC(){let{records:t,source:e}=await $t("runbooks");if(!(e!=="plane"||!t.length)){await an.mkdir(hc,{recursive:!0});for(let n of t){if(n.deletedAt||!n.data?.id)continue;let r=n.data;for(let o of r.versions||[]){let s=await ls("runbooks",r.id,o.v,"md");typeof s=="string"&&await an.writeFile(sn(r,o.v),s).catch(()=>{})}on.runbooks.push(r)}on.runbooks.length&&await Er()}}function _o(t,e,n={}){return I({id:t.trackId,cwd:t.cwd},{type:"runbook.state.changed",actor:"orchestrator",source:"orchestrator",boxId:t.box||null,provider:t.agent||null,payload:{ts:Date.now(),change:e,runbookId:t.id,name:t.name,status:t.status,...n}}).catch(()=>{})}function sn(t,e){return cn.join(hc,`${t.id}.v${e}.md`)}function t0(t,e=null){let n=t.versions||[];return e!=null?n.find(r=>r.v===Number(e))||null:n.length?n[n.length-1]:null}function e0(t){if(typeof t!="string"||!t.trim())throw new Error("md (markdown string) required");let e=Buffer.byteLength(t,"utf8");if(e>Zk)throw new Error(`runbook is ${Math.round(e/1024)} KB \u2014 over the ${Zk/1024} KB cap; a doc that size belongs in the repo, not a runbook`);let n=Zs(t);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 e}function bC(t,e){if(t.trackDeletedAt)throw new Error(`runbook is orphaned (its Track was deleted) \u2014 cannot ${e} it`)}async function kC({trackId:t,status:e}={}){let n=await je(),r=t?n.runbooks.filter(o=>o.trackId===t):n.runbooks;return e&&(r=r.filter(o=>o.status===e)),r.map(o=>({...o}))}async function n0({trackId:t,status:e}={}){let n=await je(),r=await kC({trackId:t,status:e});if(!wt())return{runbooks:r,fleetDegraded:!1};let{records:o,source:s}=await $t("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=>(!t||c.trackId===t)&&(!e||c.status===e));return{runbooks:[...r,...i],fleetDegraded:!1}}async function Af(t){let e=await xC(t);if(e)return e;if(!wt())return null;let{records:n,source:r}=await $t("runbooks");if(r!=="plane")return null;let o=n.find(s=>!s.deletedAt&&s.data?.id===t);return o?{...o.data,originNode:o.originNode||null,remote:!0}:null}async function r0(t,e){let n=await ls("runbooks",t.id,e,"md");return typeof n=="string"?n:null}async function xC(t){let n=(await je()).runbooks.find(r=>r.id===t);return n?{...n}:null}async function o0({trackId:t,trackName:e,name:n,md:r,cwd:o,box:s,agent:a}){if(!t)throw new Error("trackId required");if(typeof n!="string"||!n.trim())throw new Error("name (string) required");let i=e0(r),c=await je(),l={id:wC().slice(0,8),trackId:t,trackName:e||t,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 an.mkdir(hc,{recursive:!0}),await an.writeFile(sn(l,1),r),l.versions.push({v:1,mdRel:cn.relative(Ar,sn(l,1)),bytes:i,note:null,createdAt:Date.now()}),c.runbooks.push(l),await Er(),await _o(l,"created",{version:1}),wc(l),Qs(yn("runbooks",l.id,1,"md",sn(l,1))),{...l}}async function s0(t,{md:e,note:n}={}){let o=(await je()).runbooks.find(i=>i.id===t);if(!o)throw new Error("runbook not found");bC(o,"update");let s=e0(e),a=o.version+1;return o.version=a,o.updatedAt=Date.now(),await an.mkdir(hc,{recursive:!0}),await an.writeFile(sn(o,a),e),o.versions.push({v:a,mdRel:cn.relative(Ar,sn(o,a)),bytes:s,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),await Er(),await _o(o,"updated",{version:a,...n?{note:String(n).slice(0,200)}:{}}),wc(o),Qs(yn("runbooks",o.id,a,"md",sn(o,a))),{...o}}async function a0(t,e){if(e!=="open"&&e!=="done")throw new Error('status must be "open" or "done"');let r=(await je()).runbooks.find(o=>o.id===t);if(!r)throw new Error("runbook not found");return r.status===e?{...r}:(r.status=e,r.updatedAt=Date.now(),await Er(),await _o(r,e==="done"?"done":"reopened"),wc(r),{...r})}async function i0(t){let e=await je(),n=e.runbooks.findIndex(o=>o.id===t);if(n===-1)throw new Error("runbook not found");let r=e.runbooks[n];e.runbooks.splice(n,1);for(let o of r.versions||[])await an.rm(cn.join(Ar,o.mdRel),{force:!0}).catch(()=>{});return await Er(),r.trackDeletedAt||await _o(r,"deleted"),Qs(me("runbooks",r.id)),{ok:!0,id:t,name:r.name}}async function c0(t){let n=(await je()).runbooks.filter(r=>r.trackId===t&&!r.trackDeletedAt);for(let r of n)r.trackDeletedAt=Date.now(),r.updatedAt=Date.now(),await _o(r,"orphaned"),r.cwd=null,wc(r);return n.length&&await Er(),n.length}async function l0(t){let e=await je(),n=e.runbooks.filter(r=>r.trackId===t);for(let r of n){await _o(r,"deleted");for(let o of r.versions||[])await an.rm(cn.join(Ar,o.mdRel),{force:!0}).catch(()=>{});Qs(me("runbooks",r.id))}return n.length&&(e.runbooks=e.runbooks.filter(r=>r.trackId!==t),await Er()),n.length}async function u0(){if(!wt())return{pushed:0,source:"unconfigured"};let{records:t,source:e}=await $t("runbooks");if(e!=="plane"||t.length)return{pushed:0,source:e};let n=await je();for(let r of n.runbooks){await Ut("runbooks",{...r},{trackId:r.trackId}).catch(()=>{});for(let o of r.versions||[])await yn("runbooks",r.id,o.v,"md",cn.join(Ar,o.mdRel)).catch(()=>{})}return{pushed:n.runbooks.length,source:"plane"}}var Ar,Qk,hc,Zk,gC,on,Tf,Qs,gc=M(()=>{gn();ct();bn();Ar=process.env.BOSTRAT_STATE_DIR||cn.join(process.env.HOME||hC.tmpdir(),".bostrat"),Qk=cn.join(Ar,"runbooks.json"),hc=cn.join(Ar,"runbooks"),Zk=256*1024,gC=[{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/}];on=null,Tf=null;Qs=t=>Promise.resolve(t).catch(()=>{})});import Ef from"node:fs/promises";import ta from"node:path";import{randomUUID as SC}from"node:crypto";function If(t){let e=String(t||"").toLowerCase().replace(/^\./,"");return vC.has(e)?"image":TC.has(e)?"doc":null}function AC(t){let r=ta.basename(String(t||"")).replace(/[\x00-\x1f]/g,"").replace(/[^A-Za-z0-9._-]+/g,"_").replace(/^_+|_+$/g,"").slice(-80)||"file";return r.startsWith(".")?`f${r}`:r}async function p0(t,{filename:e,buffer:n}){if(!t)throw new Error("cwd required");if(!Buffer.isBuffer(n)||n.length===0)throw new Error("empty upload");if(n.length>d0)throw new Error(`file too large \u2014 max ${Math.floor(d0/(1024*1024))} MB`);let r=AC(e),o=ta.extname(r).slice(1),s=If(o);if(!s)throw new Error(`unsupported file type "${o||"unknown"}" \u2014 attach an image or a document`);let a=SC().slice(0,8),i=_f(t);await Ef.mkdir(i,{recursive:!0});let c=`${a}-${r}`;return await Ef.writeFile(ta.join(i,c),n,{mode:384}),await Ef.chmod(ta.join(i,c),384).catch(()=>{}),{id:a,name:r,rel:`${f0}/${c}`,kind:s,size:n.length}}function m0(t){let e=t.map(r=>`\`${r}\``).join(", ");return`[Attached \u2014 please read ${t.length===1?"this file":`these ${t.length} files`}: ${e}]`}function Rf(t){return t.role==="user"&&EC.test((t.text||"").trim())}var f0,_f,d0,vC,TC,EC,$f=M(()=>{f0=".bostrat/uploads",_f=t=>ta.join(t,f0),d0=Number(process.env.BOSTRAT_MAX_UPLOAD_BYTES)||24*1024*1024,vC=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","tif","tiff","heic","heif","avif","ico"]),TC=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"]);EC=/\[Attached — please read (?:this file|these \d+ files): [^\]]*\]$/});function _r(t,e,n=Date.now()){return e?t.idleSince==null?(t.idleSince=n,!1):n-t.idleSince>=6500:(t.idleSince=null,!1)}var h0=M(()=>{});var J0={};gl(J0,{HANDOFF_LATEST_REL:()=>fa,KNOWN_AGENTS:()=>ua,addTrackRepo:()=>Zf,agentAvailability:()=>xc,answerFullscreenOffer:()=>sp,answerPrompt:()=>Tc,archiveTrack:()=>Rr,archiveTrackForMergedPr:()=>Je,augmentFirstPromptAfterHandoff:()=>S0,buildAgentCmd:()=>x0,canResumeSubtask:()=>G0,cancelQueued:()=>pa,cancelQueuedToDraft:()=>Vf,cancelStopJob:()=>ma,cancelSubtask:()=>Mc,changedRepos:()=>go,createSetupTrack:()=>ep,createTrack:()=>_c,deleteTrack:()=>np,ensureLeadEpochs:()=>ap,forceMergeSubtask:()=>dp,getHandoffJob:()=>No,getSubtaskJob:()=>_M,getTrack:()=>z,interruptLead:()=>Ac,isArchiving:()=>kM,isHandoffNoteEcho:()=>jf,isInterruptEcho:()=>Lf,isModelSwitchEcho:()=>Ff,listSubtaskJobs:()=>$r,listTracks:()=>et,matchTranscriptsToBoxes:()=>A0,mergeNotifyMessage:()=>U0,navigatePrompt:()=>Kf,notifyTrackForMergedPr:()=>Ye,notifyTrackForResolvedPr:()=>Ic,queueShipCompleteNotify:()=>zf,queuedMessages:()=>Co,reapArchivedOrphans:()=>op,reconcileHandoffOutcome:()=>W0,reconcileInterruptedHandoffs:()=>ip,reconcileInterruptedSubtasks:()=>cp,reconcileSubtaskOutcome:()=>K0,refreshStandingInstructions:()=>tp,rehydrateLead:()=>Rc,removeTrackRepo:()=>Qf,reposOf:()=>pe,resolveTrackBox:()=>Ls,resolveTrackBoxByHookToken:()=>Wf,restartLead:()=>$c,resumeAgentCmd:()=>Hf,sayToLead:()=>fe,sendOptionsForAgent:()=>Ie,setTrackDraft:()=>Yf,setTrackModel:()=>Xf,startLeadHandoff:()=>Oc,startSpinUpView:()=>Jf,startSubtask:()=>up,stopJobActive:()=>$0,subtaskMessages:()=>qf,trackMessages:()=>vc,unarchiveTrack:()=>rp});import U from"node:fs/promises";import H from"node:path";import{randomUUID as la}from"node:crypto";import{execFile as _C}from"node:child_process";import{promisify as IC}from"node:util";function x0(t,{skipPermissions:e=!0}={}){let n=kc[t];if(!n)throw new Error(`unknown agent "${t}"`);let r=process.env[n.envVar];return r||(e&&n.skipFlag?`${n.base} ${n.skipFlag}`:n.base)}function Hf(t,e,{skipPermissions:n=!0}={}){let r=kc[t];if(!r)throw new Error(`unknown agent "${t}"`);let o=process.env[r.envVar];if(o)return o;let s=n&&r.skipFlag?` ${r.skipFlag}`:"";switch(t){case"claude":return`${r.base} --resume ${e}${s}`;case"cursor":return`${r.base} --continue${s}`;case"codex":return`${r.base} resume --last${s}`;default:return`${r.base}${s}`}}function da(t){let e=kc[t];if(e)return process.env[e.envVar]||e.base}async function xc({maxAgeMs:t=6e4}={}){if(Fn.value&&Date.now()-Fn.at<t)return Fn.value;let e=Fn.value,n=await Promise.all(ua.map(async r=>{let o=await oi(da(r),{retries:[]});return o===Wr?[r,e?.[r]??!0]:[r,o===ri]}));return Fn.value=Object.fromEntries(n),Fn.at=Date.now(),Fn.value}async function Sc(t,e=!0){let n=x0(t,{skipPermissions:e});if(await oi(n)===Hr){Fn.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.":Kl[r]?`Install it on this node: ${Kl[r]}`:"Its CLI must be installed and on PATH first.";throw new Error(`agent "${t}" isn't available on this box (command not found: ${r}). ${o}`)}return n}function S0(t,e=fa){return`${t.trim()}
149
+ `)}`:e),this.name="MockRenderError"}},Cr=null,Rf=null;De=t=>Wt("mocks",{...t},{trackId:t.trackId}).catch(()=>{}),Be=(t,e,n)=>{let r=(t.versions||[]).find(s=>s.v===e),o=n==="mp4"||n==="webm"?oa(t,r,"video"):r&&oa(t,r,n)||(n==="html"?fe(t,e).html:null);return o?xn("mocks",t.id,e,n,o).catch(()=>{}):Promise.resolve()};sa=t=>Ct.join(t,".bostrat","mocks");_C=Buffer.from([137,80,78,71,13,10,26,10]);PC=NC,$f=Promise.resolve()});import LC from"node:fs/promises";import s0 from"node:path";import FC from"node:os";import{randomUUID as a0}from"node:crypto";async function sn(){return on||(Nf||=(async()=>{let t=!0;try{on=JSON.parse(await LC.readFile(i0,"utf8"))}catch{on={flows:[]},t=!1}finally{Nf=null}if(on.flows||=[],!t&&vt()){let{records:e,source:n}=await Mt("flows").catch(()=>({records:[],source:"error"}));if(n==="plane"){for(let r of e)!r.deletedAt&&r.data?.id&&on.flows.push(r.data);on.flows.length&&await Do().catch(()=>{})}}return on})(),Nf)}async function Do(){await Yt(i0,on)}function Pf(t,e,n={}){return I({id:t.trackId,cwd:t.cwd},{type:"flow.state.changed",actor:"orchestrator",source:"orchestrator",boxId:t.box||null,provider:t.agent||null,payload:{ts:Date.now(),change:e,flowId:t.id,name:t.name,stepCount:t.steps.length,mockIds:[...new Set(t.steps.map(r=>r.mockId))],...n}}).catch(()=>{})}async function c0({trackId:t,steps:e,prevSteps:n=[]}){if(!Array.isArray(e)||e.length<1||e.length>e0)throw new Error(`steps must be an array of 1-${e0}`);let r=await aa({trackId:t}),o=[...n],s=[];for(let i=0;i<e.length;i++){let c=e[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>r0)throw new Error(`${l}: caption over ${r0} chars`);let f=c.title==null?null:String(c.title).trim()||null;if(f&&f.length>o0)throw new Error(`${l}: title over ${o0} chars`);let d=String(c.mock??"").trim().replace(/^mock:/,"");if(!d)throw new Error(`${l}: mock (name or id) required`);let p=r.filter(x=>x.id===d);if(p.length||(p=r.filter(x=>x.name.toLowerCase()===d.toLowerCase())),!p.length)throw new Error(`${l}: no mock matching "${d}" in this Track \u2014 see \`bostrat-mock ls\``);if(p.length>1)throw new Error(`${l}: "${d}" is ambiguous (${p.map(x=>`mock:${x.id}`).join(", ")}) \u2014 use the id`);let h=p[0],w=null;if(c.v!=null&&(w=Number(c.v),!Number.isInteger(w)||!(h.versions||[]).some(x=>x.v===w)))throw new Error(`${l}: "${h.name}" has no captured v${c.v} to pin`);let y=o.findIndex(x=>x.mockId===h.id),k=y>=0?o.splice(y,1)[0].id:a0().slice(0,8);s.push({id:k,mockId:h.id,caption:u,title:f,v:w})}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 HC(t){if(typeof t!="string"||!t.trim())throw new Error("name (string) required");if(t.trim().length>n0)throw new Error(`name over ${n0} chars`);return t.trim()}async function l0({trackId:t}={}){let e=await sn();return(t?e.flows.filter(r=>r.trackId===t):e.flows).map(r=>({...r}))}async function WC(t){let n=(await sn()).flows.find(r=>r.id===t);return n?{...n}:null}async function u0(t){let e=await WC(t);if(!e)return null;let n=new Map((await aa({trackId:e.trackId})).map(r=>[r.id,r]));return e.steps=e.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=ve(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}}),e}async function d0({trackId:t,name:e,steps:n,cwd:r,box:o,agent:s}){if(!t)throw new Error("trackId required");if(!r)throw new Error("cwd required");let a=HC(e),i=await sn(),c=i.flows.find(p=>p.trackId===t&&p.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 c0({trackId:t,steps:n}),f=Date.now(),d={id:a0().slice(0,8),trackId:t,box:o||null,agent:s||null,name:a,cwd:r,version:1,versions:[{v:1,steps:l,resolved:u,note:null,createdAt:f}],steps:l,createdAt:f,updatedAt:f};return i.flows.push(d),await Do(),await Pf(d,"created"),_c(d),{...d}}async function f0(t,{steps:e,note:n}={}){let o=(await sn()).flows.find(i=>i.id===t);if(!o)throw new Error("flow not found");let{steps:s,resolved:a}=await c0({trackId:o.trackId,steps:e,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 Do(),await Pf(o,"updated",{version:o.version,...n?{note:String(n).slice(0,200)}:{}}),_c(o),{...o}}async function p0(t){let e=await sn(),n=e.flows.findIndex(o=>o.id===t);if(n===-1)throw new Error("flow not found");let r=e.flows[n];return e.flows.splice(n,1),await Do(),await Pf(r,"deleted"),we("flows",r.id).catch(()=>{}),{ok:!0,id:t,name:r.name}}async function m0(t){return(await sn()).flows.filter(n=>n.steps.some(r=>r.mockId===t)).map(n=>({...n}))}async function h0(t){let n=(await sn()).flows.filter(r=>r.trackId===t.id);for(let r of n)r.trackDeletedAt=Date.now(),r.trackName=t.name||t.id,r.updatedAt=Date.now(),_c(r);return n.length&&await Do(),n.length}async function w0(t){let e=await sn(),n=e.flows.filter(r=>r.trackId===t);if(n.length){e.flows=e.flows.filter(r=>r.trackId!==t),await Do();for(let r of n)we("flows",r.id).catch(()=>{})}return n.length}async function g0(){if(!vt())return{pushed:0,source:"unconfigured"};let{records:t,source:e}=await Mt("flows");if(e!=="plane"||t.length)return{pushed:0,source:e};let n=await sn();for(let r of n.flows)await _c(r);return{pushed:n.flows.length,source:"plane"}}var UC,i0,e0,n0,r0,o0,on,Nf,_c,Df=M(()=>{at();kn();Po();Sn();UC=process.env.BOSTRAT_STATE_DIR||s0.join(process.env.HOME||FC.tmpdir(),".bostrat"),i0=s0.join(UC,"flows.json"),e0=20,n0=80,r0=500,o0=80,on=null,Nf=null;_c=t=>Wt("flows",{...t},{trackId:t.trackId}).catch(()=>{})});import ln from"node:fs/promises";import un from"node:path";import qC from"node:os";import{randomUUID as KC}from"node:crypto";function ia(t){return GC.filter(({re:e})=>e.test(t)).map(({label:e})=>e)}async function Le(){return an||(Bf||=(async()=>{let t=!0;try{an=JSON.parse(await ln.readFile(b0,"utf8"))}catch{an={runbooks:[]},t=!1}finally{Bf=null}return an.runbooks||=[],!t&&vt()&&await VC().catch(()=>{}),an})(),Bf)}async function Nr(){await Yt(b0,an)}function Rc(t){return ca(Wt("runbooks",{...t},{trackId:t.trackId}))}async function VC(){let{records:t,source:e}=await Mt("runbooks");if(!(e!=="plane"||!t.length)){await ln.mkdir(Ic,{recursive:!0});for(let n of t){if(n.deletedAt||!n.data?.id)continue;let r=n.data;for(let o of r.versions||[]){let s=await ys("runbooks",r.id,o.v,"md");typeof s=="string"&&await ln.writeFile(cn(r,o.v),s).catch(()=>{})}an.runbooks.push(r)}an.runbooks.length&&await Nr()}}function Bo(t,e,n={}){return I({id:t.trackId,cwd:t.cwd},{type:"runbook.state.changed",actor:"orchestrator",source:"orchestrator",boxId:t.box||null,provider:t.agent||null,payload:{ts:Date.now(),change:e,runbookId:t.id,name:t.name,status:t.status,...n}}).catch(()=>{})}function cn(t,e){return un.join(Ic,`${t.id}.v${e}.md`)}function k0(t,e=null){let n=t.versions||[];return e!=null?n.find(r=>r.v===Number(e))||null:n.length?n[n.length-1]:null}function x0(t){if(typeof t!="string"||!t.trim())throw new Error("md (markdown string) required");let e=Buffer.byteLength(t,"utf8");if(e>y0)throw new Error(`runbook is ${Math.round(e/1024)} KB \u2014 over the ${y0/1024} KB cap; a doc that size belongs in the repo, not a runbook`);let n=ia(t);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 e}function zC(t,e){if(t.trackDeletedAt)throw new Error(`runbook is orphaned (its Track was deleted) \u2014 cannot ${e} it`)}async function JC({trackId:t,status:e}={}){let n=await Le(),r=t?n.runbooks.filter(o=>o.trackId===t):n.runbooks;return e&&(r=r.filter(o=>o.status===e)),r.map(o=>({...o}))}async function S0({trackId:t,status:e}={}){let n=await Le(),r=await JC({trackId:t,status:e});if(!vt())return{runbooks:r,fleetDegraded:!1};let{records:o,source:s}=await Mt("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=>(!t||c.trackId===t)&&(!e||c.status===e));return{runbooks:[...r,...i],fleetDegraded:!1}}async function jf(t){let e=await YC(t);if(e)return e;if(!vt())return null;let{records:n,source:r}=await Mt("runbooks");if(r!=="plane")return null;let o=n.find(s=>!s.deletedAt&&s.data?.id===t);return o?{...o.data,originNode:o.originNode||null,remote:!0}:null}async function v0(t,e){let n=await ys("runbooks",t.id,e,"md");return typeof n=="string"?n:null}async function YC(t){let n=(await Le()).runbooks.find(r=>r.id===t);return n?{...n}:null}async function T0({trackId:t,trackName:e,name:n,md:r,cwd:o,box:s,agent:a}){if(!t)throw new Error("trackId required");if(typeof n!="string"||!n.trim())throw new Error("name (string) required");let i=x0(r),c=await Le(),l={id:KC().slice(0,8),trackId:t,trackName:e||t,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 ln.mkdir(Ic,{recursive:!0}),await ln.writeFile(cn(l,1),r),l.versions.push({v:1,mdRel:un.relative(Mr,cn(l,1)),bytes:i,note:null,createdAt:Date.now()}),c.runbooks.push(l),await Nr(),await Bo(l,"created",{version:1}),Rc(l),ca(xn("runbooks",l.id,1,"md",cn(l,1))),{...l}}async function A0(t,{md:e,note:n}={}){let o=(await Le()).runbooks.find(i=>i.id===t);if(!o)throw new Error("runbook not found");zC(o,"update");let s=x0(e),a=o.version+1;return o.version=a,o.updatedAt=Date.now(),await ln.mkdir(Ic,{recursive:!0}),await ln.writeFile(cn(o,a),e),o.versions.push({v:a,mdRel:un.relative(Mr,cn(o,a)),bytes:s,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),await Nr(),await Bo(o,"updated",{version:a,...n?{note:String(n).slice(0,200)}:{}}),Rc(o),ca(xn("runbooks",o.id,a,"md",cn(o,a))),{...o}}async function E0(t,e){if(e!=="open"&&e!=="done")throw new Error('status must be "open" or "done"');let r=(await Le()).runbooks.find(o=>o.id===t);if(!r)throw new Error("runbook not found");return r.status===e?{...r}:(r.status=e,r.updatedAt=Date.now(),await Nr(),await Bo(r,e==="done"?"done":"reopened"),Rc(r),{...r})}async function _0(t){let e=await Le(),n=e.runbooks.findIndex(o=>o.id===t);if(n===-1)throw new Error("runbook not found");let r=e.runbooks[n];e.runbooks.splice(n,1);for(let o of r.versions||[])await ln.rm(un.join(Mr,o.mdRel),{force:!0}).catch(()=>{});return await Nr(),r.trackDeletedAt||await Bo(r,"deleted"),ca(we("runbooks",r.id)),{ok:!0,id:t,name:r.name}}async function I0(t){let n=(await Le()).runbooks.filter(r=>r.trackId===t&&!r.trackDeletedAt);for(let r of n)r.trackDeletedAt=Date.now(),r.updatedAt=Date.now(),await Bo(r,"orphaned"),r.cwd=null,Rc(r);return n.length&&await Nr(),n.length}async function R0(t){let e=await Le(),n=e.runbooks.filter(r=>r.trackId===t);for(let r of n){await Bo(r,"deleted");for(let o of r.versions||[])await ln.rm(un.join(Mr,o.mdRel),{force:!0}).catch(()=>{});ca(we("runbooks",r.id))}return n.length&&(e.runbooks=e.runbooks.filter(r=>r.trackId!==t),await Nr()),n.length}async function $0(){if(!vt())return{pushed:0,source:"unconfigured"};let{records:t,source:e}=await Mt("runbooks");if(e!=="plane"||t.length)return{pushed:0,source:e};let n=await Le();for(let r of n.runbooks){await Wt("runbooks",{...r},{trackId:r.trackId}).catch(()=>{});for(let o of r.versions||[])await xn("runbooks",r.id,o.v,"md",un.join(Mr,o.mdRel)).catch(()=>{})}return{pushed:n.runbooks.length,source:"plane"}}var Mr,b0,Ic,y0,GC,an,Bf,ca,$c=M(()=>{kn();at();Sn();Mr=process.env.BOSTRAT_STATE_DIR||un.join(process.env.HOME||qC.tmpdir(),".bostrat"),b0=un.join(Mr,"runbooks.json"),Ic=un.join(Mr,"runbooks"),y0=256*1024,GC=[{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/}];an=null,Bf=null;ca=t=>Promise.resolve(t).catch(()=>{})});import Lf from"node:fs/promises";import la from"node:path";import{randomUUID as XC}from"node:crypto";function Uf(t){let e=String(t||"").toLowerCase().replace(/^\./,"");return ZC.has(e)?"image":QC.has(e)?"doc":null}function tM(t){let r=la.basename(String(t||"")).replace(/[\x00-\x1f]/g,"").replace(/[^A-Za-z0-9._-]+/g,"_").replace(/^_+|_+$/g,"").slice(-80)||"file";return r.startsWith(".")?`f${r}`:r}async function M0(t,{filename:e,buffer:n}){if(!t)throw new Error("cwd required");if(!Buffer.isBuffer(n)||n.length===0)throw new Error("empty upload");if(n.length>O0)throw new Error(`file too large \u2014 max ${Math.floor(O0/(1024*1024))} MB`);let r=tM(e),o=la.extname(r).slice(1),s=Uf(o);if(!s)throw new Error(`unsupported file type "${o||"unknown"}" \u2014 attach an image or a document`);let a=XC().slice(0,8),i=Ff(t);await Lf.mkdir(i,{recursive:!0});let c=`${a}-${r}`;return await Lf.writeFile(la.join(i,c),n,{mode:384}),await Lf.chmod(la.join(i,c),384).catch(()=>{}),{id:a,name:r,rel:`${C0}/${c}`,kind:s,size:n.length}}function N0(t){let e=t.map(r=>`\`${r}\``).join(", ");return`[Attached \u2014 please read ${t.length===1?"this file":`these ${t.length} files`}: ${e}]`}function Hf(t){return t.role==="user"&&eM.test((t.text||"").trim())}var C0,Ff,O0,ZC,QC,eM,Wf=M(()=>{C0=".bostrat/uploads",Ff=t=>la.join(t,C0),O0=Number(process.env.BOSTRAT_MAX_UPLOAD_BYTES)||24*1024*1024,ZC=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","tif","tiff","heic","heif","avif","ico"]),QC=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"]);eM=/\[Attached — please read (?:this file|these \d+ files): [^\]]*\]$/});function Pr(t,e,n=Date.now()){return e?t.idleSince==null?(t.idleSince=n,!1):n-t.idleSince>=6500:(t.idleSince=null,!1)}var P0=M(()=>{});import{execFile as nM}from"node:child_process";import{promisify as rM}from"node:util";function qf(t){return`refs/bostrat/wip/${t}`}function aM(t,e=Date.now()){return`refs/bostrat/rescue/${t}-${e}`}function j0(t=process.env){let e=String(t.BOSTRAT_WIP_SYNC_MS??"").trim().toLowerCase();return e!=="0"&&e!=="off"&&e!=="false"}function iM(t=process.env){let e=Number(t.BOSTRAT_WIP_SYNC_MS);return Number.isFinite(e)&&e>0?e:sM}async function Kf(t,{log:e=console}={}){let{id:n,cwd:r}=t??{};if(!n||!r)return{pushed:!1,reason:"no-workspace"};try{await qn(r,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await qn(r,["remote","get-url","origin"])}catch{return D0.has(r)||(D0.add(r),e.log?.(`[wip-sync] ${n}: no origin remote \u2014 durable code fidelity is chat/memory-only for this Track`)),{pushed:!1,reason:"no-origin"}}try{let o=await bo(r,"bostrat: wip snapshot"),{stdout:s}=await qn(r,["rev-parse",`${o}^{tree}`]),a=s.trim();if(Oc.get(r)===a)return{pushed:!1,reason:"unchanged"};let i=qf(n);return await qn(r,["push","--force","origin",`${o}:${i}`],B0),Oc.set(r,a),await I({id:n,cwd:r},{type:"code.pushed",actor:"orchestrator",payload:{ref:i,sha:o,wip:!0,ts:Date.now()}}).catch(()=>{}),e.log?.(`[wip-sync] ${n}: pushed ${o.slice(0,7)} \u2192 ${i}`),{pushed:!0,sha:o,ref:i}}catch(o){return e.log?.(`[wip-sync] ${n}: push failed (will retry): ${String(o?.message||o).split(`
150
+ `)[0]}`),{pushed:!1,reason:"push-failed"}}}async function Gf(t,{log:e=console}={}){let{id:n,cwd:r}=t??{};if(!n||!r)return{pushed:!1,reason:"no-workspace"};try{await qn(r,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await qn(r,["remote","get-url","origin"])}catch{return{pushed:!1,reason:"no-origin"}}try{let o=await bo(r,"bostrat: transfer rescue snapshot"),{stdout:s}=await qn(r,["rev-parse",`${o}^{tree}`]),a=s.trim();if(Oc.get(r)===a)return{pushed:!1,reason:"unchanged"};let i=aM(n);return await qn(r,["push","origin",`${o}:${i}`],B0),Oc.set(r,a),await I({id:n,cwd:r},{type:"code.pushed",actor:"orchestrator",payload:{ref:i,sha:o,rescue:!0,ts:Date.now()}}).catch(()=>{}),e.log?.(`[wip-sync] ${n}: rescued stranded work ${o.slice(0,7)} \u2192 ${i}`),{pushed:!0,sha:o,ref:i}}catch(o){return e.log?.(`[wip-sync] ${n}: rescue push failed: ${String(o?.message||o).split(`
151
+ `)[0]}`),{pushed:!1,reason:"push-failed"}}}function L0({listTracks:t,sweepMs:e=iM(),log:n=console}){let r=!1,o=async()=>{if(!r){r=!0;try{let a=await t()??[];for(let i of a)i?.archivedAt||i?.kind==="setup"||i?.transferredTo||await Kf(i,{log:n})}catch(a){n.log?.(`[wip-sync] sweep failed: ${a?.message||a}`)}finally{r=!1}}},s=setInterval(o,e);return s.unref?.(),o(),{stop:()=>clearInterval(s),cycle:o}}var oM,sM,B0,qn,Oc,D0,Vf=M(()=>{Rd();at();oM=rM(nM),sM=12e4,B0=6e4;qn=(t,e,n=15e3)=>oM("git",["-C",t,...e],{timeout:n,maxBuffer:4*1024*1024}),Oc=new Map,D0=new Set});import cM from"node:fs";import zf from"node:fs/promises";import lM from"node:path";function pM(t=process.env){return!!(St(t)&&t.BOSTRAT_PLANE_TOKEN)}async function F0(t,{env:e=process.env,fetchImpl:n=(...o)=>fetch(...o),log:r=console}={}){let o=t?.id;if(!o)return{restored:!1,reason:"no track id"};if(!pM(e))return{restored:!1,reason:"plane not configured"};let s=oo(t),a=lM.join(s,`${o}.ndjson`);try{if(cM.statSync(a).size>0)return{restored:!1,reason:"log not empty"}}catch{}let i=St(e),c={authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`},l=[],u=0;for(;;){let d=new AbortController,p=setTimeout(()=>d.abort(),fM),h;try{h=await n(`${i}/v1/spine/${encodeURIComponent(o)}?after=${u}&limit=${uM}`,{headers:c,signal:d.signal})}finally{clearTimeout(p)}if(h.status===404)return{restored:!1,reason:"unknown to plane"};if(!h.ok)return{restored:!1,reason:`plane ${h.status}`};let w=await h.json();for(let y of w.events||[])l.push(JSON.stringify(y));if(l.length>dM)return{restored:!1,reason:"event count over safety cap"};if(w.next==null)break;u=w.next}if(!l.length)return{restored:!1,reason:"unknown to plane"};await zf.mkdir(s,{recursive:!0});let f=`${a}.pull-${process.pid}-${Date.now()}`;return await zf.writeFile(f,l.join(`
152
+ `)+`
153
+ `),await zf.rename(f,a),r.log?.(`[spine-pull] rehydrated ${o}: ${l.length} event(s) \u2192 ${a}`),{restored:!0,rows:l.length}}var uM,dM,fM,U0=M(()=>{Jt();at();uM=1e3,dM=5e5,fM=3e4});var Sx={};$l(Sx,{HANDOFF_LATEST_REL:()=>Dr,KNOWN_AGENTS:()=>ka,addTrackRepo:()=>yp,adoptTrack:()=>Cp,agentAvailability:()=>Pc,answerFullscreenOffer:()=>Ep,answerPrompt:()=>Bc,archiveTrack:()=>Br,archiveTrackForMergedPr:()=>Xe,augmentFirstPromptAfterHandoff:()=>X0,buildAgentCmd:()=>J0,canResumeSubtask:()=>bx,cancelQueued:()=>va,cancelQueuedToDraft:()=>fp,cancelStopJob:()=>Ta,cancelSubtask:()=>Vc,changedRepos:()=>_o,commitTransferOut:()=>Kc,createSetupTrack:()=>xp,createTrack:()=>Lc,deleteTrack:()=>vp,demoteTransferredTracks:()=>Op,ensureLeadEpochs:()=>Wc,forceMergeSubtask:()=>Dp,getHandoffJob:()=>Go,getSubtaskJob:()=>pN,getTrack:()=>Y,getTransferOutJob:()=>Rp,interruptLead:()=>jc,isArchiving:()=>oN,isHandoffNoteEcho:()=>np,isInterruptEcho:()=>rp,isModelSwitchEcho:()=>op,listSubtaskJobs:()=>jr,listTracks:()=>nt,matchTranscriptsToBoxes:()=>tx,mergeNotifyMessage:()=>hx,navigatePrompt:()=>up,notifyTrackForMergedPr:()=>Ze,notifyTrackForResolvedPr:()=>Fc,queueShipCompleteNotify:()=>pp,queuedMessages:()=>Ho,reapArchivedOrphans:()=>Ap,reconcileHandoffOutcome:()=>wx,reconcileInterruptedHandoffs:()=>Ip,reconcileInterruptedSubtasks:()=>Mp,reconcileSubtaskOutcome:()=>yx,refreshStandingInstructions:()=>kp,rehydrateLead:()=>Uc,removeTrackRepo:()=>bp,reposOf:()=>ae,resolveTrackBox:()=>zs,resolveTrackBoxByHookToken:()=>cp,restartLead:()=>Hc,resumeAgentCmd:()=>ip,sayToLead:()=>me,sendOptionsForAgent:()=>$e,setTrackDraft:()=>wp,setTrackModel:()=>gp,startLeadHandoff:()=>qc,startSpinUpView:()=>mp,startSubtask:()=>Pp,startTransferOut:()=>$p,stopJobActive:()=>sx,subtaskMessages:()=>lp,trackMessages:()=>Dc,unarchiveTrack:()=>Tp});import H from"node:fs/promises";import W from"node:path";import{randomUUID as ba}from"node:crypto";import{execFile as mM}from"node:child_process";import{promisify as hM}from"node:util";function J0(t,{skipPermissions:e=!0}={}){let n=Nc[t];if(!n)throw new Error(`unknown agent "${t}"`);let r=process.env[n.envVar];return r||(e&&n.skipFlag?`${n.base} ${n.skipFlag}`:n.base)}function ip(t,e,{skipPermissions:n=!0}={}){let r=Nc[t];if(!r)throw new Error(`unknown agent "${t}"`);let o=process.env[r.envVar];if(o)return o;let s=n&&r.skipFlag?` ${r.skipFlag}`:"";switch(t){case"claude":return`${r.base} --resume ${e}${s}`;case"cursor":return`${r.base} --continue${s}`;case"codex":return`${r.base} resume --last${s}`;default:return`${r.base}${s}`}}function xa(t){let e=Nc[t];if(e)return process.env[e.envVar]||e.base}async function Pc({maxAgeMs:t=6e4}={}){if(Kn.value&&Date.now()-Kn.at<t)return Kn.value;let e=Kn.value,n=await Promise.all(ka.map(async r=>{let o=await yi(xa(r),{retries:[]});return o===Zr?[r,e?.[r]??!0]:[r,o===gi]}));return Kn.value=Object.fromEntries(n),Kn.at=Date.now(),Kn.value}async function Sa(t,e=!0){let n=J0(t,{skipPermissions:e});if(await yi(n)===Xr){Kn.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.":nu[r]?`Install it on this node: ${nu[r]}`:"Its CLI must be installed and on PATH first.";throw new Error(`agent "${t}" isn't available on this box (command not found: ${r}). ${o}`)}return n}function X0(t,e=Dr){return`${t.trim()}
150
154
 
151
- (Read ${e} 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 jf(t){return t.role==="user"&&MC.test((t.text||"").trim())}async function q(){return ue||(Of||=(async()=>{try{ue=JSON.parse(await U.readFile(k0,"utf8"))}catch{ue={tracks:[]}}finally{Of=null}return ue})(),Of)}async function Y(){await zt(k0,ue)}function BC(t,e){let n=JSON.stringify({trackId:t,...e})+`
152
- `;return Cf=Cf.then(()=>U.mkdir(ln,{recursive:!0})).then(()=>U.appendFile($C,n)).catch(()=>{}),Cf}function v0(t){if(!t)return null;let e=typeof t=="string"?[t]:Array.isArray(t?.codes)&&t.codes.length?t.codes:t?.code?[t.code]:[],n=[...new Set(e.filter(s=>DC.has(s)))];if(!n.length)return null;let r=typeof t=="object"?t?.note:null,o=r&&String(r).slice(0,500).trim()||null;return{code:n[0],...n.length>1?{codes:n}:{},note:o}}async function T0(t,e,n,{kind:r}={}){let o=await tt(e);if(!o)throw new Error(`box "${e}" is not running`);let s=da(o.agent);await Tn({cwd:o.cwd,sessionId:o.sessionId,sessionName:e,agent:o.agent,agentCmd:s}),await Mt(e,n,{...Ie(o.agent),kind:r||"orchestration"}),await G({flow:"orchestration",phase:"sent",trackId:t,sessionName:e,agent:o.agent,kind:r||"orchestration",promptHead:n.slice(0,160)});let a=await q(),i=Q(a,t);if(!i)return;let c=i.boxes.find(l=>l.name===e);pt(i,"orchestration-prompt",{box:e,agent:c?.agent||o.agent,boxRole:c?.role,prompt:n,kind:r||"orchestration"}),await Y()}async function jC(t){let e=H.join(bi(t),`${t.id}.ndjson`),n;try{n=await U.stat(e)}catch{return null}let r=w0.get(t.id);if(r&&r.mtimeMs===n.mtimeMs)return r.at;let o=null;for(let s of await L(t)){if(s.type!=="turn.agent")continue;let a=s.payload?.ts??s.ts;a&&(!o||a>o)&&(o=a)}return w0.set(t.id,{mtimeMs:n.mtimeMs,at:o}),o}async function LC(t,e){let n=e.find(r=>r.name===t.leadBox);return n?.state!=="live"?{working:!1,prompted:!1}:Rd(n.name,n.agent)}async function un(t,e=null){let n=e??new Map((await he()).map(i=>[i.name,i])),r=t.boxes.map(i=>{let c=n.get(i.name),l=Ir.has(i.state)?i.state:c?i.role==="lead"?"live":i.state:"stopped";return{...i,state:l,cwd:c?.cwd||i.cwd,agent:c?.agent||i.agent,sessionId:c?.sessionId||i.sessionId}}),[o,{working:s,prompted:a}]=await Promise.all([jC(t),LC(t,r)]);return{...t,boxes:r,lastResponseAt:o,working:s,prompted:a,archiving:aa.has(t.id)}}function A0(t,e,n){let r=[...t].sort((l,u)=>l.createdAt-u.createdAt),o=[...e].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-FC,f=r[u+1]?.createdAt??1/0,p=o.find(m=>!s.has(m.id)&&m.birthMs>=d&&m.birthMs<f);p&&(s.add(p.id),c.push({box:l.name,sessionId:p.id}))}return c}async function E0(t){let e=new Map;for(let r of t.tracks)for(let o of r.boxes)o.agent==="claude"&&o.cwd&&(e.has(o.cwd)||e.set(o.cwd,[]),e.get(o.cwd).push({track:r,box:o}));let n=!1;for(let[r,o]of e){let s=o.map(f=>f.box.sessionId),a=_h(r),i=new Set(a.map(f=>f.id)),c=s.every(f=>f&&i.has(f)),l=new Set(s).size===s.length;if(c&&l)continue;let u=o.map(f=>f.box),d=A0(u,a,f=>i.has(f));for(let f of d){let p=u.find(m=>m.name===f.box);p&&(p.sessionId=f.sessionId),await yh(f.box,f.sessionId),n=!0}}return n}async function et(){let t=await q();await E0(t)&&await Y();let e=new Map((await he()).map(n=>[n.name,n]));return Promise.all(t.tracks.map(n=>un(n,e)))}async function Ls(t,e){let n=await q();if(t)for(let r of n.tracks||[]){let o=r.boxes.find(s=>s.sessionId&&s.sessionId===t);if(o)return{track:r,box:o}}if(e)for(let r of n.tracks||[]){let o=r.boxes.find(s=>s.cwd===e);if(o)return{track:r,box:o}}return null}async function Wf(t){let e=Yo(t);if(!e)return null;let n=await q();for(let r of n.tracks||[])for(let o of r.boxes||[])if(o.hookTokenHash&&Sm(o.hookTokenHash,e))return{track:r,box:o};return null}async function z(t){let e=await q(),n=Q(e,t);return n?(await E0(e)&&await Y(),un(n)):null}function Lf(t){if(t.role!=="user")return!1;let e=(t.text||"").trim();return(UC[t.agent]||[]).some(n=>n.test(e))}function Ff(t){let e=(t.text||"").trim();return e?HC.some(n=>n.test(e)):!1}async function vc(t,e={}){let n=await z(t);if(!n)return null;let r=new Set([...n.events.filter(b=>b.type==="orchestration-prompt"&&b.prompt).map(b=>String(b.prompt).trim()),...n.events.filter(b=>b.type==="said"&&b.text).map(b=>String(b.text).trim())]),o=No(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=Yd(n.id),c=!!(i&&!i.finishedAt),l=c&&i.startedAt&&i.box?[{box:i.box,from:i.startedAt,to:Date.now()+1e12}]:[],u=[...qb(n),...l],f={windows:[...Qw(n),...tg(n,Ai),...a,...u]},m=(await Promise.all(n.boxes.map(b=>Yu(b,e)))).flat(),w=m.map(b=>{let v={kind:"message",...b};if(v.role==="assistant"&&(v.text||"").trim()&&v.tools?.length){let P=Is(v.agent).cliTools,mt=v.tools.filter(rt=>!P.has(rt));return{...v,tools:mt.length?mt:void 0}}return v}).map(b=>{if(b.role!=="user")return b;let v=Si(b.text);return v?v.kind==="suppress"?null:{...b,note:v,text:vw(v)}:b}).filter(Boolean).filter(b=>!(b.role==="user"&&r.has((b.text||"").trim()))).filter(b=>!Lf(b)).filter(b=>!Ff(b)).filter(b=>!jf(b)).filter(b=>!Rf(b)).filter(b=>b.role!=="assistant"||!!(b.text||"").trim()||!!b.images?.length).filter(b=>!eg(b,f)),y=w.filter(b=>b.failed&&b.text===ku);if(y.length){let b=new Map;for(let v of y){if(!b.has(v.box)){let rt=[...(await yt(v.box,{lines:Ct}).catch(()=>"")).matchAll(/^\s*■\s+(.+?)\s*$/gm)].map(Ot=>Ot[1]);b.set(v.box,rt.length?rt[rt.length-1]:null)}let P=b.get(v.box);P&&(v.text=`\u25A0 ${P}`)}}let k=await Promise.all(n.boxes.map(b=>Pg(b,e)));await Eb(n,k.flat()),await Tb(n,w),await Oy(n),await Xb(n,w).catch(()=>{});for(let b of n.boxes)b.agent==="codex"&&b.state==="live"&&await Ib(n,b),b.agent==="cursor"&&b.state==="live"&&await Mb(n,b);let S=await Promise.all(n.boxes.map(b=>Mg(b,e)));await Ab(n,S.flat().filter(b=>!Mf(b.box,b.ts,u)));let $=await L(n),R=c&&i.viewId?i.viewId:null,J=Uy($),C=lr($).filter(b=>!(b.kind==="message"&&(Lf(b)||Ff(b)||jf(b)||Rf(b)))&&!(b.kind==="view-card"&&R&&b.viewId===R)),D=Hy(C,J),A=C.filter(b=>!(b.kind==="message"&&b.role==="assistant"&&!D.has(b)&&Mf(b.box,b.ts,J))),N=Mu($,A).map(b=>({kind:"command-batch",id:b.id,ts:b.pending?b.ts:(b.anchorTs??b.ts)-1,anchorTs:b.anchorTs,anchorBox:b.anchorBox,agent:b.agent,boxRole:b.boxRole,commands:b.commands,pending:b.pending})).filter(b=>!Mf(b.anchorBox,b.anchorTs??b.ts,u)),W=$w(Ow([...A,...N].filter(b=>b.ts!=null).sort((b,v)=>b.ts-v.ts))),at=qC(n),it=at.size?W.filter(b=>b.kind==="event"||!at.has(b.box??b.anchorBox)):W,E=n.boxes.find(b=>b.name===n.leadBox)||null,O=E?await ps(E.cwd,E.sessionId,{fallbackNewest:!1}):null;if(!O&&E){let b=[...$].reverse().find(v=>v.type==="context.usage"&&v.boxId===E.name);b?.payload?.window&&(O={pct:b.payload.pct??(b.payload.occupancy!=null?b.payload.occupancy/b.payload.window:null),occupancy:b.payload.occupancy??null,window:b.payload.window,windowKnown:!0,model:b.payload.model||null})}let At=[...m].reverse().find(b=>b.role==="assistant"&&b.model),Gt=At?.model||null,gt=[...n.events||[]].reverse().find(b=>b.type==="model-change"),g=O?.model||Gt;gt&&(!At?.ts||gt.at>=At.ts)&&(g=gt.to);let h=E?await yt(E.name,{lines:Ct}).catch(()=>""):"",T=E&&ao(E.agent,h)?await Sn(E.name).catch(()=>h):h,_=E?wr(E,T):null;if(_&&E){let b=$i(E,_,T);if(b){let v=Yg(E.name,_.promptId);v.action!=="give-up"&&(v.action==="send"&&(Tt(E.name,b.keys,{kind:"auto-reject"}).catch(()=>{}),v.first&&I(n,{type:"prompt.autoRejected",actor:"system",source:"pane",boxId:E.name,provider:E.agent,payload:{ts:Date.now(),promptId:_.promptId,rule:b.id}}).catch(()=>{})),_=null)}}!_&&E&&!ws(E.agent,h)&&!Co(n.id).length&&(_=Ou(it,{leadBoxId:E.name,provider:E.agent,isAnswered:b=>$.some(v=>v.type==="prompt.answered"&&v.payload?.promptId===b)})),_&&Cy(n,E,_);let St=it.filter(b=>!(b.kind==="message"&&b.role==="assistant"&&b.ask&&!String(b.text||"").trim()&&!b.images?.length)),dt=!!E&&Ji(E.name,E.agent,h)&&!_;E&&!E.readyAt&&(dt||_||h&&pi(E.agent,h))&&(E.readyAt=Date.now(),await Y());let Jo=!!E&&!E.readyAt&&Date.now()-(n.createdAt||0)<WC;if(n.kind==="setup"&&n.setup?.provider&&!n.setup.connectedAt&&E&&pi(E.agent,h)&&!_){let b=await q(),v=Q(b,n.id);v?.setup&&!v.setup.connectedAt&&(v.setup.connectedAt=Date.now(),n.setup.connectedAt=v.setup.connectedAt,await I(v,{type:"provider.connected",actor:"system",source:"pane",boxId:E.name,provider:E.agent,payload:{provider:E.agent,ts:v.setup.connectedAt}}).catch(()=>{}),await Y())}let Bt=s?{running:!0,step:o.step,toAgent:o.toAgent||null}:null,K=null;if(c){let b=Date.now()-i.startedAt;if(i.viewId&&!dt){let v=rc(n.id);v&&(pt(n,"view-spinup",{box:i.box,startedAt:i.startedAt,endedAt:v.finishedAt}),await Y())}else if(_||b>Hb&&!dt&&!i.viewId||b>Jd){let v=_?"needs-input":b>Jd?"timeout":"no-view";rc(n.id,{error:v})&&await I(n,{type:"view.spinup.failed",actor:"orchestrator",source:"orchestrator",boxId:i.box,provider:E?.agent||null,payload:{ts:i.startedAt,name:i.name,reason:v}}).catch(()=>{})}else K={running:!0,step:i.step,name:i.name}}return{trackId:n.id,leadBox:n.leadBox,items:St,context:O?{pct:O.pct,occupancy:O.occupancy,window:O.window,windowKnown:O.windowKnown,model:O.model}:null,models:{current:g,options:Ty(E?.agent)},pendingPrompt:_,working:dt,stopping:$0(n.id),leadStarting:Jo,handoff:Bt,view:K,queued:Co(n.id).filter(b=>b.kind!=="ship-notify"&&b.kind!=="prompt-answer"),draft:n.draft||null,draftRev:n.draftRev||0}}function qC(t){let e=new Set;for(let n of t.boxes||[])n.role==="subtask"&&n.name&&e.add(n.name);for(let n of Object.values(t.subtasks||{}))n?.box&&e.add(n.box);return e}async function qf(t,e){let n=await z(t);if(!n)return null;let r=$r(t).find(d=>d.id===e)||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 L(n),a=lr(s).filter(d=>d.box===o&&!(d.kind==="message"&&d.role==="assistant"&&d.ask&&!String(d.text||"").trim()&&!d.images?.length)),i=Mu(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,f)=>d.ts-f.ts),l=n.boxes.find(d=>d.name===o)||null,u=!1;if(l&&l.state==="live"){let d=await yt(o,{lines:Ct}).catch(()=>"");u=Ji(o,l.agent||r.agent,d)}return{items:c,working:u,box:o,agent:r.agent,task:r.task}}async function Tc(t,{promptId:e,answers:n,text:r}={}){let o=Q(await q(),t);if(!o)throw new Error(`track "${t}" not found`);ma(t,"prompt-answer");let s=o.boxes.find(f=>f.name===o.leadBox);if(!s)throw new Error(`track "${t}" has no lead box`);if(!await tt(o.leadBox))throw new Error(`lead box "${o.leadBox}" is not running`);let i=await rd(s);if(i||(i=await KC(o,s)),!i)throw new Error("no pending prompt to answer");if(e&&e!==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 f=typeof r=="string"?r.trim():"";if(!f)throw new Error("this prompt needs a code \u2014 paste it into the card");if(/\s/.test(f)||f.length>2048)throw new Error("that doesn't look like a sign-in code \u2014 paste the code exactly as shown");await Mt(o.leadBox,f,{enter:!0,kind:"answer-prompt"}),c={mode:"text-input",value:"\u2039code\u203A",count:1,redacted:!0}}else if(i.answerMode==="esc")await Tt(o.leadBox,["Escape"],{kind:"answer-prompt"}),c={mode:"keys",value:"Escape",count:1};else if(i.answerMode==="say"){let f=_w(i,n||[],typeof r=="string"?r:"");if(!f)throw new Error("no answer selected \u2014 pick an option or reply in chat");await fe(o.id,f,{kind:"prompt-answer"}),c={mode:"say",value:f,count:1}}else if(i.provider==="claude"||i.answerMode==="keys"){let f=Gg(i,n||[]);await Tt(o.leadBox,f,{kind:"answer-prompt"}),c={mode:"keys",value:f.join(" "),count:f.length}}else{let f=Fh(i,n||[]);await Mt(o.leadBox,f,{enter:!0,kind:"answer-prompt"}),c={mode:"text",value:f,count:1}}if(i.answerMode==="say"){let f=i.questions||[];for(let p=0;p<f.length;p++){let m=f[p],w=(Array.isArray(n?.[p])?n[p]:[]).map(y=>m.options?.[y]).filter(Boolean).map(y=>({label:y.label,description:y.description||""}));Sd(o,s,i,{...c,groupId:i.groupId||i.promptId,questionIndex:p,questionTotal:i.questionTotal??f.length,header:m.header||"",question:m.question||"",multiSelect:!!m.multiSelect,chosen:w})}return await G({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=(Array.isArray(n?.[0])?n[0]:[]).map(f=>l.options?.[f]).filter(Boolean).map(f=>({label:f.label,description:f.description||""})),d=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:u,...d?{control:d}:{}},await G({flow:"prompt",phase:"answered",sessionName:o.leadBox,agent:s.agent,provider:i.provider,promptId:i.promptId,...c}).catch(()=>{}),Sd(o,s,i,c),{ok:!0,promptId:i.promptId,sent:c.count}}async function KC(t,e){if(!e)return null;let n=await L(t).catch(()=>[]);return Ou(lr(n),{leadBoxId:e.name,provider:e.agent,isAnswered:r=>n.some(o=>o.type==="prompt.answered"&&o.payload?.promptId===r)})}async function Kf(t,{promptId:e,questionIndex:n}={}){let r=Q(await q(),t);if(!r)throw new Error(`track "${t}" not found`);let o=r.boxes.find(l=>l.name===r.leadBox);if(!o)throw new Error(`track "${t}" has no lead box`);if(!await tt(r.leadBox))throw new Error(`lead box "${r.leadBox}" is not running`);let a=await rd(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(e&&e!==a.promptId)throw new Error("prompt changed since it was shown \u2014 reload and try again");let c=Vg(a,n);return c.length?(await Tt(r.leadBox,c,{kind:"navigate-prompt"}),await G({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 Gf(t){let e=ra.get(t);return e||(e={items:[],timer:null,flushing:!1,idleSince:null},ra.set(t,e)),e}function Co(t){return(ra.get(t)?.items??[]).map(e=>({...e}))}function pa(t){let e=ra.get(t);if(!e)return[];let n=e.items.splice(0);return e.idleSince=null,e.timer&&(clearInterval(e.timer),e.timer=null),n}async function Vf(t){let e=pa(t),n=e.filter(o=>o.text&&!o.kind).map(o=>o.text),r=null;if(n.length){let o=Q(await q(),t);if(o)return r=Mo(o,n),await Y(),{removed:e,restored:r,draftRev:o.draftRev||0}}return{removed:e,restored:r,draftRev:null}}function _0(t){let e=Gf(t);e.timer||(e.timer=setInterval(()=>VC(t).catch(()=>{}),GC))}async function VC(t){let e=ra.get(t);if(!(!e||e.flushing)){if(!e.items.length){e.timer&&(clearInterval(e.timer),e.timer=null);return}e.flushing=!0;try{let n=Q(await q(),t);if(!n||n.archivedAt){pa(t);return}let r=No(t);if(r&&!r.finishedAt&&r.step!=="done"&&!r.error){_r(e,!1);return}let o=await tt(n.leadBox);if(!o){_r(e,!1);return}let s=n.boxes.find(c=>c.name===n.leadBox);if(fo(s?.agent)){_r(e,!1);return}let a=await yt(n.leadBox,{lines:Ct}).catch(()=>"");if(fi(s?.agent,a)){_r(e,!1);return}if(ao(s?.agent,a)){let c=await Sn(n.leadBox).catch(()=>a);if(wr(s,c)){_r(e,!1);return}}if(!_r(e,!0))return;let i=e.items.shift();e.idleSince=null,await R0(n,s,o,i.text,i.kind??null,i.attachments??null),await Y()}finally{e.flushing=!1}}}async function I0(t,e,n,r){let o=fo(e?.agent);if(!o)return;if(!r&&typeof n=="string"&&n.trim()&&(Mo(t,[n]),await Y()),my(t.id,o))try{await I(t,{type:"usage.cap.hit",actor:"system",provider:e?.agent??null,boxId:t.leadBox,payload:{...o,blockedKind:r??null}})}catch{}let s=new Error(`${e?.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 R0(t,e,n,r,o=null,s=null){await I0(t,e,r,o);let a=oa.get(t.id)||0,i=r,c=!1;t.pendingHandoffHydrate&&(i=S0(r,t.pendingHandoffHydrate.artifact||fa),delete t.pendingHandoffHydrate,c=!0);let l=Array.isArray(s)?s.filter(d=>d&&d.rel):[];if(l.length){let d=m0(l.map(f=>f.rel));i=i.trim()?`${i.trim()}
155
+ (Read ${e} 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 np(t){return t.role==="user"&&yM.test((t.text||"").trim())}async function K(){return pe||(Jf||=(async()=>{try{pe=JSON.parse(await H.readFile(z0,"utf8"))}catch{pe={tracks:[]}}finally{Jf=null}return pe})(),Jf)}async function J(){await Yt(z0,pe)}function xM(t,e){let n=JSON.stringify({trackId:t,...e})+`
156
+ `;return Yf=Yf.then(()=>H.mkdir(fn,{recursive:!0})).then(()=>H.appendFile(wM,n)).catch(()=>{}),Yf}function Z0(t){if(!t)return null;let e=typeof t=="string"?[t]:Array.isArray(t?.codes)&&t.codes.length?t.codes:t?.code?[t.code]:[],n=[...new Set(e.filter(s=>SM.has(s)))];if(!n.length)return null;let r=typeof t=="object"?t?.note:null,o=r&&String(r).slice(0,500).trim()||null;return{code:n[0],...n.length>1?{codes:n}:{},note:o}}async function Q0(t,e,n,{kind:r}={}){let o=await et(e);if(!o)throw new Error(`box "${e}" is not running`);let s=xa(o.agent);await In({cwd:o.cwd,sessionId:o.sessionId,sessionName:e,agent:o.agent,agentCmd:s}),await Pt(e,n,{...$e(o.agent),kind:r||"orchestration"}),await G({flow:"orchestration",phase:"sent",trackId:t,sessionName:e,agent:o.agent,kind:r||"orchestration",promptHead:n.slice(0,160)});let a=await K(),i=Z(a,t);if(!i)return;let c=i.boxes.find(l=>l.name===e);pt(i,"orchestration-prompt",{box:e,agent:c?.agent||o.agent,boxRole:c?.role,prompt:n,kind:r||"orchestration"}),await J()}async function vM(t){let e=W.join(oo(t),`${t.id}.ndjson`),n;try{n=await H.stat(e)}catch{return null}let r=H0.get(t.id);if(r&&r.mtimeMs===n.mtimeMs)return r.at;let o=null;for(let s of await F(t)){if(s.type!=="turn.agent")continue;let a=s.payload?.ts??s.ts;a&&(!o||a>o)&&(o=a)}return H0.set(t.id,{mtimeMs:n.mtimeMs,at:o}),o}async function TM(t,e){let n=e.find(r=>r.name===t.leadBox);return n?.state!=="live"?{working:!1,prompted:!1}:Hd(n.name,n.agent)}async function Fe(t,e=null){let n=e??new Map((await ge()).map(i=>[i.name,i])),r=t.boxes.map(i=>{let c=n.get(i.name),l=Gn.has(i.state)?i.state:c?i.role==="lead"?"live":i.state:"stopped";return{...i,state:l,cwd:c?.cwd||i.cwd,agent:c?.agent||i.agent,sessionId:c?.sessionId||i.sessionId}}),[o,{working:s,prompted:a}]=await Promise.all([vM(t),TM(t,r)]);return{...t,boxes:r,lastResponseAt:o,working:s,prompted:a,archiving:ga.has(t.id)}}function tx(t,e,n){let r=[...t].sort((l,u)=>l.createdAt-u.createdAt),o=[...e].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),f=l.createdAt-AM,d=r[u+1]?.createdAt??1/0,p=o.find(h=>!s.has(h.id)&&h.birthMs>=f&&h.birthMs<d);p&&(s.add(p.id),c.push({box:l.name,sessionId:p.id}))}return c}async function ex(t){let e=new Map;for(let r of t.tracks)for(let o of r.boxes)o.agent==="claude"&&o.cwd&&(e.has(o.cwd)||e.set(o.cwd,[]),e.get(o.cwd).push({track:r,box:o}));let n=!1;for(let[r,o]of e){let s=o.map(d=>d.box.sessionId),a=Xh(r),i=new Set(a.map(d=>d.id)),c=s.every(d=>d&&i.has(d)),l=new Set(s).size===s.length;if(c&&l)continue;let u=o.map(d=>d.box),f=tx(u,a,d=>i.has(d));for(let d of f){let p=u.find(h=>h.name===d.box);p&&(p.sessionId=d.sessionId),await Hh(d.box,d.sessionId),n=!0}}return n}async function nt(){let t=await K();await ex(t)&&await J();let e=new Map((await ge()).map(n=>[n.name,n]));return Promise.all(t.tracks.map(n=>Fe(n,e)))}async function zs(t,e){let n=await K();if(t)for(let r of n.tracks||[]){let o=r.boxes.find(s=>s.sessionId&&s.sessionId===t);if(o)return{track:r,box:o}}if(e)for(let r of n.tracks||[]){let o=r.boxes.find(s=>s.cwd===e);if(o)return{track:r,box:o}}return null}async function cp(t){let e=as(t);if(!e)return null;let n=await K();for(let r of n.tracks||[])for(let o of r.boxes||[])if(o.hookTokenHash&&Vm(o.hookTokenHash,e))return{track:r,box:o};return null}async function Y(t){let e=await K(),n=Z(e,t);return n?(await ex(e)&&await J(),Fe(n)):null}function rp(t){if(t.role!=="user")return!1;let e=(t.text||"").trim();return(EM[t.agent]||[]).some(n=>n.test(e))}function op(t){let e=(t.text||"").trim();return e?_M.some(n=>n.test(e)):!1}async function Dc(t,e={}){let n=await Y(t);if(!n)return null;let r=new Set([...n.events.filter(b=>b.type==="orchestration-prompt"&&b.prompt).map(b=>String(b.prompt).trim()),...n.events.filter(b=>b.type==="said"&&b.text).map(b=>String(b.text).trim())]),o=Go(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=uf(n.id),c=!!(i&&!i.finishedAt),l=c&&i.startedAt&&i.box?[{box:i.box,from:i.startedAt,to:Date.now()+1e12}]:[],u=[...uk(n),...l],d={windows:[...vg(n),...Tg(n,ji),...a,...u]},h=(await Promise.all(n.boxes.map(b=>cd(b,e)))).flat(),w=h.map(b=>{let _={kind:"message",...b};if(_.role==="assistant"&&(_.text||"").trim()&&_.tools?.length){let R=js(_.agent).cliTools,P=_.tools.filter(wt=>!R.has(wt));return{..._,tools:P.length?P:void 0}}return _}).map(b=>{if(b.role!=="user")return b;let _=Pi(b.text);return _?_.kind==="suppress"?null:{...b,note:_,text:Vw(_)}:b}).filter(Boolean).filter(b=>!(b.role==="user"&&r.has((b.text||"").trim()))).filter(b=>!rp(b)).filter(b=>!op(b)).filter(b=>!np(b)).filter(b=>!Hf(b)).filter(b=>b.role!=="assistant"||!!(b.text||"").trim()||!!b.images?.length).filter(b=>!Ag(b,d)),y=w.filter(b=>b.failed&&b.text===$u);if(y.length){let b=new Map;for(let _ of y){if(!b.has(_.box)){let wt=[...(await Tt(_.box,{lines:Nt}).catch(()=>"")).matchAll(/^\s*■\s+(.+?)\s*$/gm)].map(ht=>ht[1]);b.set(_.box,wt.length?wt[wt.length-1]:null)}let R=b.get(_.box);R&&(_.text=`\u25A0 ${R}`)}}let k=await Promise.all(n.boxes.map(b=>ny(b,e)));await Gb(n,k.flat()),await qb(n,w),await Xy(n),await gk(n,w).catch(()=>{});for(let b of n.boxes)b.agent==="codex"&&b.state==="live"&&await zb(n,b),b.agent==="cursor"&&b.state==="live"&&await Qb(n,b);let x=await Promise.all(n.boxes.map(b=>ey(b,e)));await Kb(n,x.flat().filter(b=>!Xf(b.box,b.ts,u)));let E=await F(n),O=c&&i.viewId?i.viewId:null,z=ib(E),C=hr(E).filter(b=>!(b.kind==="message"&&(rp(b)||op(b)||np(b)||Hf(b)))&&!(b.kind==="view-card"&&O&&b.viewId===O)),N=cb(C,z),T=C.filter(b=>!(b.kind==="message"&&b.role==="assistant"&&!N.has(b)&&Xf(b.box,b.ts,z))),D=Wu(E,T).map(b=>({kind:"command-batch",id:b.id,ts:b.pending?b.ts:(b.anchorTs??b.ts)-1,anchorTs:b.anchorTs,anchorBox:b.anchorBox,agent:b.agent,boxRole:b.boxRole,commands:b.commands,pending:b.pending})).filter(b=>!Xf(b.anchorBox,b.anchorTs??b.ts,u)),j=tg(eg([...T,...D].filter(b=>b.ts!=null).sort((b,_)=>b.ts-_.ts))),st=RM(n),rt=st.size?j.filter(b=>b.kind==="event"||!st.has(b.box??b.anchorBox)):j,A=n.boxes.find(b=>b.name===n.leadBox)||null,B=A?await Ss(A.cwd,A.sessionId,{fallbackNewest:!1}):null;if(!B&&A){let b=[...E].reverse().find(_=>_.type==="context.usage"&&_.boxId===A.name);b?.payload?.window&&(B={pct:b.payload.pct??(b.payload.occupancy!=null?b.payload.occupancy/b.payload.window:null),occupancy:b.payload.occupancy??null,window:b.payload.window,windowKnown:!0,model:b.payload.model||null})}let X=[...h].reverse().find(b=>b.role==="assistant"&&b.model),yt=X?.model||null,dt=[...n.events||[]].reverse().find(b=>b.type==="model-change"),bt=B?.model||yt;dt&&(!X?.ts||dt.at>=X.ts)&&(bt=dt.to);let kt=A?await Tt(A.name,{lines:Nt}).catch(()=>""):"",g=A&&go(A.agent,kt)?await En(A.name).catch(()=>kt):kt,m=A?Sr(A,g):null;if(m&&A){let b=Wi(A,m,g);if(b){let _=yy(A.name,m.promptId);_.action!=="give-up"&&(_.action==="send"&&(It(A.name,b.keys,{kind:"auto-reject"}).catch(()=>{}),_.first&&I(n,{type:"prompt.autoRejected",actor:"system",source:"pane",boxId:A.name,provider:A.agent,payload:{ts:Date.now(),promptId:m.promptId,rule:b.id}}).catch(()=>{})),m=null)}}!m&&A&&!As(A.agent,kt)&&!Ho(n.id).length&&(m=Uu(rt,{leadBoxId:A.name,provider:A.agent,isAnswered:b=>E.some(_=>_.type==="prompt.answered"&&_.payload?.promptId===b)})),m&&Zy(n,A,m);let v=rt.filter(b=>!(b.kind==="message"&&b.role==="assistant"&&b.ask&&!String(b.text||"").trim()&&!b.images?.length)),it=!!A&&cc(A.name,A.agent,kt)&&!m;A&&!A.readyAt&&(it||m||kt&&Ii(A.agent,kt))&&(A.readyAt=Date.now(),await J());let ct=!!A&&!A.readyAt&&Date.now()-(n.createdAt||0)<IM;if(n.kind==="setup"&&n.setup?.provider&&!n.setup.connectedAt&&A&&Ii(A.agent,kt)&&!m){let b=await K(),_=Z(b,n.id);_?.setup&&!_.setup.connectedAt&&(_.setup.connectedAt=Date.now(),n.setup.connectedAt=_.setup.connectedAt,await I(_,{type:"provider.connected",actor:"system",source:"pane",boxId:A.name,provider:A.agent,payload:{provider:A.agent,ts:_.setup.connectedAt}}).catch(()=>{}),await J())}let mt=s?{running:!0,step:o.step,toAgent:o.toAgent||null}:null,sr=null;if(c){let b=Date.now()-i.startedAt;if(i.viewId&&!it){let _=wc(n.id);_&&(pt(n,"view-spinup",{box:i.box,startedAt:i.startedAt,endedAt:_.finishedAt}),await J())}else if(m||b>ck&&!it&&!i.viewId||b>lf){let _=m?"needs-input":b>lf?"timeout":"no-view";wc(n.id,{error:_})&&await I(n,{type:"view.spinup.failed",actor:"orchestrator",source:"orchestrator",boxId:i.box,provider:A?.agent||null,payload:{ts:i.startedAt,name:i.name,reason:_}}).catch(()=>{})}else sr={running:!0,step:i.step,name:i.name}}return{trackId:n.id,leadBox:n.leadBox,items:v,context:B?{pct:B.pct,occupancy:B.occupancy,window:B.window,windowKnown:B.windowKnown,model:B.model}:null,models:{current:bt,options:qy(A?.agent)},pendingPrompt:m,working:it,stopping:sx(n.id),leadStarting:ct,handoff:mt,view:sr,queued:Ho(n.id).filter(b=>b.kind!=="ship-notify"&&b.kind!=="prompt-answer"),draft:n.draft||null,draftRev:n.draftRev||0}}function RM(t){let e=new Set;for(let n of t.boxes||[])n.role==="subtask"&&n.name&&e.add(n.name);for(let n of Object.values(t.subtasks||{}))n?.box&&e.add(n.box);return e}async function lp(t,e){let n=await Y(t);if(!n)return null;let r=jr(t).find(f=>f.id===e)||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 F(n),a=hr(s).filter(f=>f.box===o&&!(f.kind==="message"&&f.role==="assistant"&&f.ask&&!String(f.text||"").trim()&&!f.images?.length)),i=Wu(s.filter(f=>f.boxId===o),a.filter(f=>f.kind==="message")).map(f=>({kind:"command-batch",id:f.id,ts:f.pending?f.ts:(f.anchorTs??f.ts)-1,anchorTs:f.anchorTs,anchorBox:f.anchorBox,agent:f.agent,boxRole:f.boxRole,commands:f.commands,pending:f.pending})),c=[...a,...i].filter(f=>f.ts!=null).sort((f,d)=>f.ts-d.ts),l=n.boxes.find(f=>f.name===o)||null,u=!1;if(l&&l.state==="live"){let f=await Tt(o,{lines:Nt}).catch(()=>"");u=cc(o,l.agent||r.agent,f)}return{items:c,working:u,box:o,agent:r.agent,task:r.task}}async function Bc(t,{promptId:e,answers:n,text:r}={}){let o=Z(await K(),t);if(!o)throw new Error(`track "${t}" not found`);Ta(t,"prompt-answer");let s=o.boxes.find(d=>d.name===o.leadBox);if(!s)throw new Error(`track "${t}" has no lead box`);if(!await et(o.leadBox))throw new Error(`lead box "${o.leadBox}" is not running`);let i=await hd(s);if(i||(i=await $M(o,s)),!i)throw new Error("no pending prompt to answer");if(e&&e!==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 d=typeof r=="string"?r.trim():"";if(!d)throw new Error("this prompt needs a code \u2014 paste it into the card");if(/\s/.test(d)||d.length>2048)throw new Error("that doesn't look like a sign-in code \u2014 paste the code exactly as shown");await Pt(o.leadBox,d,{enter:!0,kind:"answer-prompt"}),c={mode:"text-input",value:"\u2039code\u203A",count:1,redacted:!0}}else if(i.answerMode==="esc")await It(o.leadBox,["Escape"],{kind:"answer-prompt"}),c={mode:"keys",value:"Escape",count:1};else if(i.answerMode==="say"){let d=Xw(i,n||[],typeof r=="string"?r:"");if(!d)throw new Error("no answer selected \u2014 pick an option or reply in chat");await me(o.id,d,{kind:"prompt-answer"}),c={mode:"say",value:d,count:1}}else if(i.provider==="claude"||i.answerMode==="keys"){let d=my(i,n||[]);await It(o.leadBox,d,{kind:"answer-prompt"}),c={mode:"keys",value:d.join(" "),count:d.length}}else{let d=uw(i,n||[]);await Pt(o.leadBox,d,{enter:!0,kind:"answer-prompt"}),c={mode:"text",value:d,count:1}}if(i.answerMode==="say"){let d=i.questions||[];for(let p=0;p<d.length;p++){let h=d[p],w=(Array.isArray(n?.[p])?n[p]:[]).map(y=>h.options?.[y]).filter(Boolean).map(y=>({label:y.label,description:y.description||""}));Pd(o,s,i,{...c,groupId:i.groupId||i.promptId,questionIndex:p,questionTotal:i.questionTotal??d.length,header:h.header||"",question:h.question||"",multiSelect:!!h.multiSelect,chosen:w})}return await G({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=(Array.isArray(n?.[0])?n[0]:[]).map(d=>l.options?.[d]).filter(Boolean).map(d=>({label:d.label,description:d.description||""})),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:u,...f?{control:f}:{}},await G({flow:"prompt",phase:"answered",sessionName:o.leadBox,agent:s.agent,provider:i.provider,promptId:i.promptId,...c}).catch(()=>{}),Pd(o,s,i,c),{ok:!0,promptId:i.promptId,sent:c.count}}async function $M(t,e){if(!e)return null;let n=await F(t).catch(()=>[]);return Uu(hr(n),{leadBoxId:e.name,provider:e.agent,isAnswered:r=>n.some(o=>o.type==="prompt.answered"&&o.payload?.promptId===r)})}async function up(t,{promptId:e,questionIndex:n}={}){let r=Z(await K(),t);if(!r)throw new Error(`track "${t}" not found`);let o=r.boxes.find(l=>l.name===r.leadBox);if(!o)throw new Error(`track "${t}" has no lead box`);if(!await et(r.leadBox))throw new Error(`lead box "${r.leadBox}" is not running`);let a=await hd(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(e&&e!==a.promptId)throw new Error("prompt changed since it was shown \u2014 reload and try again");let c=hy(a,n);return c.length?(await It(r.leadBox,c,{kind:"navigate-prompt"}),await G({flow:"prompt",phase:"navigated",sessionName:r.leadBox,agent:o.agent,provider:a.provider,promptId:a.promptId,fromIndex:a.questionIndex??0,toIndex:n,mode:"keys",value:c.join(" "),count:c.length}).catch(()=>{}),{ok:!0,promptId:a.promptId,sent:c.length}):{ok:!0,promptId:a.promptId,sent:0}}function dp(t){let e=pa.get(t);return e||(e={items:[],timer:null,flushing:!1,idleSince:null},pa.set(t,e)),e}function Ho(t){return(pa.get(t)?.items??[]).map(e=>({...e}))}function va(t){let e=pa.get(t);if(!e)return[];let n=e.items.splice(0);return e.idleSince=null,e.timer&&(clearInterval(e.timer),e.timer=null),n}async function fp(t){let e=va(t),n=e.filter(o=>o.text&&!o.kind).map(o=>o.text),r=null;if(n.length){let o=Z(await K(),t);if(o)return r=Wo(o,n),await J(),{removed:e,restored:r,draftRev:o.draftRev||0}}return{removed:e,restored:r,draftRev:null}}function nx(t){let e=dp(t);e.timer||(e.timer=setInterval(()=>CM(t).catch(()=>{}),OM))}async function CM(t){let e=pa.get(t);if(!(!e||e.flushing)){if(!e.items.length){e.timer&&(clearInterval(e.timer),e.timer=null);return}e.flushing=!0;try{let n=Z(await K(),t);if(!n||n.archivedAt){va(t);return}let r=Go(t);if(r&&!r.finishedAt&&r.step!=="done"&&!r.error){Pr(e,!1);return}let o=await et(n.leadBox);if(!o){Pr(e,!1);return}let s=n.boxes.find(c=>c.name===n.leadBox);if(Tr(s?.agent)){Pr(e,!1);return}let a=await Tt(n.leadBox,{lines:Nt}).catch(()=>"");if(_i(s?.agent,a)){Pr(e,!1);return}if(go(s?.agent,a)){let c=await En(n.leadBox).catch(()=>a);if(Sr(s,c)){Pr(e,!1);return}}if(!Pr(e,!0))return;let i=e.items.shift();e.idleSince=null,await ox(n,s,o,i.text,i.kind??null,i.attachments??null),await J()}finally{e.flushing=!1}}}async function rx(t,e,n,r){let o=Tr(e?.agent);if(!o)return;if(!r&&typeof n=="string"&&n.trim()&&(Wo(t,[n]),await J()),Ny(t.id,o))try{await I(t,{type:"usage.cap.hit",actor:"system",provider:e?.agent??null,boxId:t.leadBox,payload:{...o,blockedKind:r??null}})}catch{}let s=new Error(`${e?.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 ox(t,e,n,r,o=null,s=null){await rx(t,e,r,o);let a=ma.get(t.id)||0,i=r,c=!1;t.pendingHandoffHydrate&&(i=X0(r,t.pendingHandoffHydrate.artifact||Dr),delete t.pendingHandoffHydrate,c=!0);let l=Array.isArray(s)?s.filter(f=>f&&f.rel):[];if(l.length){let f=N0(l.map(d=>d.rel));i=i.trim()?`${i.trim()}
153
157
 
154
- ${d}`:d}let u=pt(t,"said",{box:t.leadBox,agent:e?.agent,boxRole:e?.role,text:r,...o?{kind:o}:{},...l.length?{attachments:l}:{}});Oo(t,null);try{if(await Tn({cwd:n.cwd,sessionId:n.sessionId,sessionName:t.leadBox,agent:n.agent,agentCmd:da(n.agent)}),(oa.get(t.id)||0)!==a){!o&&r.trim()&&(Mo(t,[r]),await Y());let d=new Error("delivery stopped \u2014 the message was handed back as the draft");throw d.interrupted=!0,d}await Mt(t.leadBox,i,{...Ie(e?.agent),kind:c?"lead-handoff-first-prompt":"say"})}catch(d){throw pt(t,"unsaid",{box:t.leadBox,agent:e?.agent,boxRole:e?.role,saidTs:u.at,text:r,...d?.interrupted?{reason:"interrupted"}:{}}),d}await cM(t,e,i)||(await C0(t.leadBox,e?.agent,i.length+8).catch(()=>{}),pt(t,"unsaid",{box:t.leadBox,agent:e?.agent,boxRole:e?.role,saidTs:u.at,text:r,reason:"unsubmitted"}),o||Mo(t,[r])),c&&await G({flow:"lead-handoff",phase:"first-prompt",trackId:t.id,sessionName:t.leadBox,agent:e?.agent,userTextLen:r.length})}function zf(t,{actions:e}={}){Gf(t).items.push({id:la(),text:Wy(e),ts:Date.now(),kind:"ship-notify"}),_0(t)}async function fe(t,e,{kind:n=null,attachments:r=null}={}){let o=Array.isArray(r)?r.filter(f=>f&&typeof f.rel=="string"):[];if((typeof e!="string"||!io(e))&&!o.length)throw new Error("text (string) or an attachment required");let s=Q(await q(),t);if(!s)throw new Error(`track "${t}" not found`);if(s.archivedAt)throw new Error(`track "${t}" is archived \u2014 restore it before driving it`);let a=s.boxes.find(f=>f.name===s.leadBox),i=io(e);await I0(s,a,i,n),ma(t,"say");let c=await tt(s.leadBox);if(!c&&await Rc(s)&&(await Y(),c=await tt(s.leadBox)),!c)throw new Error(`lead box "${s.leadBox}" is not running`);let l=Gf(t),u=await yt(s.leadBox,{lines:Ct}).catch(()=>""),d=l.items.length>0||fi(a?.agent,u);if(!d&&ao(a?.agent,u)){let f=await Sn(s.leadBox).catch(()=>u);d=!!wr(a,f)}if(d){let f={id:la(),text:i,ts:Date.now(),...n?{kind:n}:{},...o.length?{attachments:o}:{}};return l.items.push(f),_0(t),Oo(s,null),await Y(),{ok:!0,leadBox:s.leadBox,queued:!0,id:f.id,position:l.items.length}}return await R0(s,a,c,i,n,o),await Y(),{ok:!0,leadBox:s.leadBox}}async function Jf(t,{hint:e}={}){let n=Q(await q(),t);if(!n)throw new Error(`track "${t}" not found`);if(n.archivedAt)throw new Error(`track "${t}" is archived \u2014 restore it first`);let r=Yd(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(e||"").trim()?String(e).trim().slice(0,40):"preview";Wb(n.id,{name:s,box:n.leadBox});let a=String(e||"").trim()?`${g0}
158
+ ${f}`:f}let u=pt(t,"said",{box:t.leadBox,agent:e?.agent,boxRole:e?.role,text:r,...o?{kind:o}:{},...l.length?{attachments:l}:{}});Uo(t,null);try{if(await In({cwd:n.cwd,sessionId:n.sessionId,sessionName:t.leadBox,agent:n.agent,agentCmd:xa(n.agent)}),(ma.get(t.id)||0)!==a){!o&&r.trim()&&(Wo(t,[r]),await J());let f=new Error("delivery stopped \u2014 the message was handed back as the draft");throw f.interrupted=!0,f}await Pt(t.leadBox,i,{...$e(e?.agent),kind:c?"lead-handoff-first-prompt":"say"})}catch(f){throw pt(t,"unsaid",{box:t.leadBox,agent:e?.agent,boxRole:e?.role,saidTs:u.at,text:r,...f?.interrupted?{reason:"interrupted"}:{}}),f}await VM(t,e,i)||(await ax(t.leadBox,e?.agent,i.length+8).catch(()=>{}),pt(t,"unsaid",{box:t.leadBox,agent:e?.agent,boxRole:e?.role,saidTs:u.at,text:r,reason:"unsubmitted"}),o||Wo(t,[r])),c&&await G({flow:"lead-handoff",phase:"first-prompt",trackId:t.id,sessionName:t.leadBox,agent:e?.agent,userTextLen:r.length})}function pp(t,{actions:e}={}){dp(t).items.push({id:ba(),text:lb(e),ts:Date.now(),kind:"ship-notify"}),nx(t)}async function me(t,e,{kind:n=null,attachments:r=null}={}){let o=Array.isArray(r)?r.filter(d=>d&&typeof d.rel=="string"):[];if((typeof e!="string"||!yo(e))&&!o.length)throw new Error("text (string) or an attachment required");let s=Z(await K(),t);if(!s)throw new Error(`track "${t}" not found`);if(s.archivedAt)throw new Error(`track "${t}" is archived \u2014 restore it before driving it`);let a=s.boxes.find(d=>d.name===s.leadBox),i=yo(e);await rx(s,a,i,n),Ta(t,"say");let c=await et(s.leadBox);if(!c&&await Uc(s)&&(await J(),c=await et(s.leadBox)),!c)throw new Error(`lead box "${s.leadBox}" is not running`);let l=dp(t),u=await Tt(s.leadBox,{lines:Nt}).catch(()=>""),f=l.items.length>0||_i(a?.agent,u);if(!f&&go(a?.agent,u)){let d=await En(s.leadBox).catch(()=>u);f=!!Sr(a,d)}if(f){let d={id:ba(),text:i,ts:Date.now(),...n?{kind:n}:{},...o.length?{attachments:o}:{}};return l.items.push(d),nx(t),Uo(s,null),await J(),{ok:!0,leadBox:s.leadBox,queued:!0,id:d.id,position:l.items.length}}return await ox(s,a,c,i,n,o),await J(),{ok:!0,leadBox:s.leadBox}}async function mp(t,{hint:e}={}){let n=Z(await K(),t);if(!n)throw new Error(`track "${t}" not found`);if(n.archivedAt)throw new Error(`track "${t}" is archived \u2014 restore it first`);let r=uf(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(e||"").trim()?String(e).trim().slice(0,40):"preview";lk(n.id,{name:s,box:n.leadBox});let a=String(e||"").trim()?`${W0}
155
159
 
156
- What to preview: ${String(e).trim()}`:g0;try{await fe(t,a,{kind:"spin-up-view"})}catch(i){throw rc(n.id,{error:"drive-failed"}),i}return{ok:!0,running:!0}}async function Ac(t){let e=Q(await q(),t);if(!e)throw new Error(`track "${t}" not found`);if(e.archivedAt)throw new Error(`track "${t}" is archived`);oa.set(t,(oa.get(t)||0)+1);let n=pa(t),r=n.filter(i=>i.text&&!i.kind).map(i=>i.text),o=$o.get(t);if(o&&!o.canceled){o.clicks++;let i=null;return r.length&&(i=Mo(e,r),await Y()),{ok:!0,interrupted:!0,stopped:!1,stopping:!0,dropped:n.length,restored:i,draftRev:e.draftRev||0}}let s=QC(t,{droppedCount:n.length,droppedTexts:r});await Promise.race([s.settled,Un(zC)]);let a=Q(await q(),t)||e;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 $0(t){let e=$o.get(t);return!!e&&!e.canceled}function ma(t,e){let n=$o.get(t);n&&!n.canceled&&(n.canceled=!0,n.cancelReason=e||null)}function O0(t){ma(t,"track-ended"),oa.delete(t),pa(t)}function QC(t,{droppedCount:e,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}),$o.set(t,r),(async()=>{let s=Q(await q(),t),a=s?.boxes.find(y=>y.name===s.leadBox),i=s?await tt(s.leadBox):null,c=!1,l=!1;if(i){t:for(let y=0;y<JC&&!r.canceled;y++){await Tt(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.escSends++;for(let k of YC){await Un(k);let S=await yt(s.leadBox,{lines:Ct}).catch(()=>"");if(!ws(a?.agent,S)){c=!0;break t}}}if(!c){l=!0;for(let y=0;y<ZC&&!r.canceled&&(await Un(XC),!r.canceled);y++){let k=await yt(s.leadBox,{lines:Ct}).catch(()=>"");if(!ws(a?.agent,k)){c=!0;break}await Tt(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.bgSends++}}}let u=Q(await q(),t)||s,d=u?.boxes.find(y=>y.name===u.leadBox)||a,f=null,p=null;u&&d&&i&&c&&!r.canceled&&(f=await rM(u,d).catch(()=>null),f||(p=await aM(u,d).catch(()=>null)));let m=u&&i&&!r.canceled?await eM(u).catch(()=>null):null,w=[f||p,...r.queuedTexts].filter(Boolean);u&&w.length&&(r.restored=Mo(u,w),await Y()),r.result=i?r.canceled?"canceled":c?l?"stopped-late":"stopped":"gave-up":"no-session",await tM(u||s,d,{ts:r.startedAt,result:r.result,dropped:e,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!f,lostRestored:!!p,queuedRestored:r.queuedTexts.length,shipDismissed:!!m,durationMs:Date.now()-r.startedAt,...r.cancelReason?{cancelReason:r.cancelReason}:{}}),await G({flow:"interrupt",phase:r.result==="gave-up"?"failed":"done",trackId:t,sessionName:u?.leadBox,agent:d?.agent,result:r.result,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!f,lostRestored:!!p,queuedRestored:r.queuedTexts.length,shipDismissed:!!m}).catch(()=>{})})().catch(()=>{}).finally(()=>{r.result||(r.result=r.canceled?"canceled":"gave-up"),$o.get(t)===r&&$o.delete(t),o()}),r}async function tM(t,e,n){await I(t,{type:"turn.interrupted",actor:"user",source:"orchestrator",boxId:t.leadBox,provider:e?.agent||null,payload:n}).catch(()=>{})}async function eM(t){let e=dc(await L(t));if(!e?.offerId)return null;let n=e.offerType==="exists";return await I(t,{type:n?"pr.exists.answered":"pr.offer.answered",actor:"user",source:"orchestrator",boxId:e.box,payload:{ts:Date.now(),offerId:e.offerId,...n?{choice:"dismiss"}:{action:"dismiss",actions:null},reason:"interrupt"}}),e.offerId}async function rM(t,e){if(e?.agent!=="claude")return null;let n=[...t.events||[]].reverse().find(r=>r.type==="said"&&r.text);if(!n)return null;for(let r of nM){await Un(r);let o=await yt(t.leadBox,{lines:Ct}).catch(()=>""),s=vs(e.agent,o);if(s&&xu(n.text,s))return await C0(t.leadBox,e.agent,n.text.length+8),pt(t,"unsaid",{box:t.leadBox,agent:e.agent,boxRole:e.role,saidTs:n.at,text:n.text}),n.text}return null}async function aM(t,e){if(e?.agent!=="claude")return null;let n=t.events||[],r=[...n].reverse().find(s=>s.type==="said"&&s.text);if(!r||r.kind||Date.now()-r.at>oM||n.some(s=>s.type==="unsaid"&&s.saidTs===r.at)||!It(r.text))return null;for(let s of sM){await Un(s);let a;try{a=await Yu(e,{})}catch{return null}if(hw(a,r))return null;let i=await yt(t.leadBox,{lines:Ct}).catch(()=>"");if(vs(e.agent,i))return null}return pt(t,"unsaid",{box:t.leadBox,agent:e.agent,boxRole:e.role,saidTs:r.at,text:r.text,reason:"lost"}),r.text}async function cM(t,e,n){if(e?.agent!=="claude")return!0;for(let r=0;r<=Pf;r++){let o=!1;for(let s of iM){await Un(s);let a=await yt(t.leadBox,{lines:Ct}).catch(()=>""),i=ww(e.agent,n,a,{busy:ws(e.agent,a)});if(i==="stuck"){o=!0;break}if(i==="submitted")return!0}if(!o)return!0;r<Pf&&(await Tt(t.leadBox,["Enter"],{kind:"submit-retry"}),G({flow:"say",phase:"submit-retry",trackId:t.id,sessionName:t.leadBox,agent:e.agent,attempt:r+1,textHead:n.slice(0,120)}).catch(()=>{}))}return G({flow:"say",phase:"submit-failed",trackId:t.id,sessionName:t.leadBox,agent:e.agent,retries:Pf,textHead:n.slice(0,120)}).catch(()=>{}),!1}async function C0(t,e,n){for(let r=0;r<3;r++){await Gr(t,n,{kind:"unsend-wipe"}).catch(()=>{}),await Un(200);let o=await yt(t,{lines:Ct}).catch(()=>""),s=vs(e,o);if(!s)return!0;n=s.length+8}return!1}function Oo(t,e,{source:n}={}){t.draftRev=(t.draftRev||0)+1;let r=typeof e=="string"?e:"";return r.trim()?t.draft={text:r,updatedAt:Date.now(),...n?{source:n}:{}}:delete t.draft,t.draft||null}function Mo(t,e){let n=[],r=o=>n.some(s=>It(s).includes(It(o)));for(let o of[t.draft?.text,...e])o&&o.trim()&&!r(o)&&n.push(o);return n.length?Oo(t,n.join(`
160
+ What to preview: ${String(e).trim()}`:W0;try{await me(t,a,{kind:"spin-up-view"})}catch(i){throw wc(n.id,{error:"drive-failed"}),i}return{ok:!0,running:!0}}async function jc(t){let e=Z(await K(),t);if(!e)throw new Error(`track "${t}" not found`);if(e.archivedAt)throw new Error(`track "${t}" is archived`);ma.set(t,(ma.get(t)||0)+1);let n=va(t),r=n.filter(i=>i.text&&!i.kind).map(i=>i.text),o=Fo.get(t);if(o&&!o.canceled){o.clicks++;let i=null;return r.length&&(i=Wo(e,r),await J()),{ok:!0,interrupted:!0,stopped:!1,stopping:!0,dropped:n.length,restored:i,draftRev:e.draftRev||0}}let s=jM(t,{droppedCount:n.length,droppedTexts:r});await Promise.race([s.settled,Vn(MM)]);let a=Z(await K(),t)||e;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 sx(t){let e=Fo.get(t);return!!e&&!e.canceled}function Ta(t,e){let n=Fo.get(t);n&&!n.canceled&&(n.canceled=!0,n.cancelReason=e||null)}function hp(t){Ta(t,"track-ended"),ma.delete(t),va(t)}function jM(t,{droppedCount:e,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}),Fo.set(t,r),(async()=>{let s=Z(await K(),t),a=s?.boxes.find(y=>y.name===s.leadBox),i=s?await et(s.leadBox):null,c=!1,l=!1;if(i){t:for(let y=0;y<NM&&!r.canceled;y++){await It(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.escSends++;for(let k of PM){await Vn(k);let x=await Tt(s.leadBox,{lines:Nt}).catch(()=>"");if(!As(a?.agent,x)){c=!0;break t}}}if(!c){l=!0;for(let y=0;y<BM&&!r.canceled&&(await Vn(DM),!r.canceled);y++){let k=await Tt(s.leadBox,{lines:Nt}).catch(()=>"");if(!As(a?.agent,k)){c=!0;break}await It(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.bgSends++}}}let u=Z(await K(),t)||s,f=u?.boxes.find(y=>y.name===u.leadBox)||a,d=null,p=null;u&&f&&i&&c&&!r.canceled&&(d=await HM(u,f).catch(()=>null),d||(p=await KM(u,f).catch(()=>null)));let h=u&&i&&!r.canceled?await FM(u).catch(()=>null):null,w=[d||p,...r.queuedTexts].filter(Boolean);u&&w.length&&(r.restored=Wo(u,w),await J()),r.result=i?r.canceled?"canceled":c?l?"stopped-late":"stopped":"gave-up":"no-session",await LM(u||s,f,{ts:r.startedAt,result:r.result,dropped:e,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!d,lostRestored:!!p,queuedRestored:r.queuedTexts.length,shipDismissed:!!h,durationMs:Date.now()-r.startedAt,...r.cancelReason?{cancelReason:r.cancelReason}:{}}),await G({flow:"interrupt",phase:r.result==="gave-up"?"failed":"done",trackId:t,sessionName:u?.leadBox,agent:f?.agent,result:r.result,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!d,lostRestored:!!p,queuedRestored:r.queuedTexts.length,shipDismissed:!!h}).catch(()=>{})})().catch(()=>{}).finally(()=>{r.result||(r.result=r.canceled?"canceled":"gave-up"),Fo.get(t)===r&&Fo.delete(t),o()}),r}async function LM(t,e,n){await I(t,{type:"turn.interrupted",actor:"user",source:"orchestrator",boxId:t.leadBox,provider:e?.agent||null,payload:n}).catch(()=>{})}async function FM(t){let e=Tc(await F(t));if(!e?.offerId)return null;let n=e.offerType==="exists";return await I(t,{type:n?"pr.exists.answered":"pr.offer.answered",actor:"user",source:"orchestrator",boxId:e.box,payload:{ts:Date.now(),offerId:e.offerId,...n?{choice:"dismiss"}:{action:"dismiss",actions:null},reason:"interrupt"}}),e.offerId}async function HM(t,e){if(e?.agent!=="claude")return null;let n=[...t.events||[]].reverse().find(r=>r.type==="said"&&r.text);if(!n)return null;for(let r of UM){await Vn(r);let o=await Tt(t.leadBox,{lines:Nt}).catch(()=>""),s=Ms(e.agent,o);if(s&&Ou(n.text,s))return await ax(t.leadBox,e.agent,n.text.length+8),pt(t,"unsaid",{box:t.leadBox,agent:e.agent,boxRole:e.role,saidTs:n.at,text:n.text}),n.text}return null}async function KM(t,e){if(e?.agent!=="claude")return null;let n=t.events||[],r=[...n].reverse().find(s=>s.type==="said"&&s.text);if(!r||r.kind||Date.now()-r.at>WM||n.some(s=>s.type==="unsaid"&&s.saidTs===r.at)||!Ot(r.text))return null;for(let s of qM){await Vn(s);let a;try{a=await cd(e,{})}catch{return null}if(Lw(a,r))return null;let i=await Tt(t.leadBox,{lines:Nt}).catch(()=>"");if(Ms(e.agent,i))return null}return pt(t,"unsaid",{box:t.leadBox,agent:e.agent,boxRole:e.role,saidTs:r.at,text:r.text,reason:"lost"}),r.text}async function VM(t,e,n){if(e?.agent!=="claude")return!0;for(let r=0;r<=Zf;r++){let o=!1;for(let s of GM){await Vn(s);let a=await Tt(t.leadBox,{lines:Nt}).catch(()=>""),i=Fw(e.agent,n,a,{busy:As(e.agent,a)});if(i==="stuck"){o=!0;break}if(i==="submitted")return!0}if(!o)return!0;r<Zf&&(await It(t.leadBox,["Enter"],{kind:"submit-retry"}),G({flow:"say",phase:"submit-retry",trackId:t.id,sessionName:t.leadBox,agent:e.agent,attempt:r+1,textHead:n.slice(0,120)}).catch(()=>{}))}return G({flow:"say",phase:"submit-failed",trackId:t.id,sessionName:t.leadBox,agent:e.agent,retries:Zf,textHead:n.slice(0,120)}).catch(()=>{}),!1}async function ax(t,e,n){for(let r=0;r<3;r++){await eo(t,n,{kind:"unsend-wipe"}).catch(()=>{}),await Vn(200);let o=await Tt(t,{lines:Nt}).catch(()=>""),s=Ms(e,o);if(!s)return!0;n=s.length+8}return!1}function Uo(t,e,{source:n}={}){t.draftRev=(t.draftRev||0)+1;let r=typeof e=="string"?e:"";return r.trim()?t.draft={text:r,updatedAt:Date.now(),...n?{source:n}:{}}:delete t.draft,t.draft||null}function Wo(t,e){let n=[],r=o=>n.some(s=>Ot(s).includes(Ot(o)));for(let o of[t.draft?.text,...e])o&&o.trim()&&!r(o)&&n.push(o);return n.length?Uo(t,n.join(`
157
161
 
158
- `),{source:"restore"})?.text??null:null}function uM(t,e){let n=It(e);if(!n)return!1;if(Co(t.id).some(o=>It(o.text)===n))return!0;let r=t.events||[];for(let o=r.length-1;o>=0;o--){let s=r[o];if(typeof s.at=="number"&&Date.now()-s.at>lM)break;if(!(s.type!=="said"||!s.text||It(s.text)!==n))return!r.some(a=>a.type==="unsaid"&&a.saidTs===s.at)}return!1}async function Yf(t,e,{rev:n=null}={}){if(typeof e!="string")throw new Error("text (string) required");let r=Q(await q(),t);if(!r)throw new Error(`track "${t}" not found`);let o=e,s=io(e);if(typeof n=="number"&&n<(r.draftRev||0)&&s&&uM(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;It(o).includes(It(i))?Oo(r,o):Oo(r,`${i}
162
+ `),{source:"restore"})?.text??null:null}function JM(t,e){let n=Ot(e);if(!n)return!1;if(Ho(t.id).some(o=>Ot(o.text)===n))return!0;let r=t.events||[];for(let o=r.length-1;o>=0;o--){let s=r[o];if(typeof s.at=="number"&&Date.now()-s.at>zM)break;if(!(s.type!=="said"||!s.text||Ot(s.text)!==n))return!r.some(a=>a.type==="unsaid"&&a.saidTs===s.at)}return!1}async function wp(t,e,{rev:n=null}={}){if(typeof e!="string")throw new Error("text (string) required");let r=Z(await K(),t);if(!r)throw new Error(`track "${t}" not found`);let o=e,s=yo(e);if(typeof n=="number"&&n<(r.draftRev||0)&&s&&JM(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;Ot(o).includes(Ot(i))?Uo(r,o):Uo(r,`${i}
159
163
 
160
- ${o}`,{source:"restore"})}else Oo(r,o);return await Y(),{ok:!0,draft:r.draft||null,rev:r.draftRev||0}}async function Xf(t,e){if(typeof e!="string"||!e.trim())throw new Error("model (string) required");let n=e.trim(),r=Q(await q(),t);if(!r)throw new Error(`track "${t}" not found`);let o=await tt(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=Ay(a,n),l=[...r.events||[]].reverse().find(d=>d.type==="model-change")?.to??null;l||(l=(await ps(o.cwd,o.sessionId,{fallbackNewest:!1}).catch(()=>null))?.model??null),await Tn({cwd:o.cwd,sessionId:o.sessionId,sessionName:r.leadBox,agent:o.agent,agentCmd:da(o.agent)});let u=await Ey(a,r.leadBox,i);return pt(r,"model-change",{to:n,from:l,box:r.leadBox,agent:a,verified:!!u.verified}),await Y(),{ok:!0,requested:n,leadBox:r.leadBox,...u}}async function M0(t){for(let e of t){if(!e||!await Oi(e))continue;let n=await ty(e).catch(()=>null);if(!n)continue;if((await U.stat(H.join(n,".git")).catch(()=>null))?.isDirectory())return n}return null}function pe(t){let e=t;return e?e.kind==="multi"?Array.isArray(e.repos)?e.repos.filter(Boolean):[]:e.base?[{name:H.basename(e.base),dir:e.dir??null,base:e.base,baseRef:e.baseRef??null,repo:e.repo??null}]:[]:[]}async function go(t){let e=[];for(let n of pe(t?.workspace)){if(!n?.dir)continue;let r=await ud(n.dir,{ignorePlumbing:!0}).catch(()=>!1),o=await dd(n.dir,n.baseRef).catch(()=>0);(r||o>0)&&e.push({...n,dirty:r,ahead:o})}return e}async function P0(t){let e=t;typeof e=="string"&&!H.isAbsolute(e)&&/^[^/\s]+\/[^/\s]+$/.test(e)&&(e=await es(e)??await El(e));let n=await M0([e]);if(!n)throw new Error(`tagged repo "${t}" is not a usable base (need a primary checkout or a synced owner/name)`);return n}async function dM(t,e,n,r){let o=`track/${lp(e)}-${t}`,s=[];try{await U.mkdir(n,{recursive:!0});let a=new Set([".bostrat"]);for(let i of r){let c=await P0(i);if(s.some(p=>p.base===c))throw new Error(`repo tagged twice: ${i}`);let l=await st(c).catch(()=>null),u=H.basename(c);a.has(u)&&l&&(u=l.replace("/","-"));for(let p=2;a.has(u);p++)u=`${H.basename(c)}-${p}`;a.add(u);let d=H.join(n,u),f=await Ci(c);await co(c,d,o,f),s.push({name:u,dir:d,base:c,baseRef:f,repo:l})}return await Ec(n,s,o),{dir:n,kind:"multi",branch:o,repos:s}}catch(a){for(let i of s)await ae(i.base,i.dir).catch(()=>{});throw await U.rm(n,{recursive:!0,force:!0}).catch(()=>{}),a}}async function Zf(t,e){let n=await q(),r=Q(n,t);if(!r)throw new Error(`track "${t}" 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 P0(typeof e=="string"?e.trim():e);if((o.repos??[]).some(f=>f?.base===s))throw new Error(`repo already tagged: ${e}`);let a=await st(s).catch(()=>null),i=new Set([".bostrat",...(o.repos??[]).map(f=>f?.name).filter(Boolean)]),c=H.basename(s);i.has(c)&&a&&(c=a.replace("/","-"));for(let f=2;i.has(c);f++)c=`${H.basename(s)}-${f}`;let l=H.join(o.dir,c),u=await Ci(s);await ey(s,o.branch)?await ny(s,l,o.branch):await co(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 Ec(o.dir,o.repos,o.branch),pt(r,"retagged",{action:"add",repo:a??s,name:c,workspace:N0(o)}),await Y(),d}async function Qf(t,e){let n=await q(),r=Q(n,t);if(!r)throw new Error(`track "${t}" 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===e||c.repo===e||c.base===e));if(!s)throw new Error(`repo "${e}" 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 de.values())if(c.trackId===t&&!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 ud(s.dir,{ignorePlumbing:!0}).catch(()=>!1),i=await dd(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 ae(s.base,s.dir).catch(()=>{}),await U.rm(s.dir,{recursive:!0,force:!0}).catch(()=>{}),o.repos=(o.repos??[]).filter(c=>c&&c!==s),await Ec(o.dir,o.repos,o.branch),pt(r,"retagged",{action:"remove",repo:s.repo??s.base,name:s.name,workspace:N0(o)}),await Y(),{removed:s.name}}async function fM(t,e,{repo:n,repos:r,cwd:o}={}){await U.mkdir(Df,{recursive:!0});let s=H.join(Df,t),a=Array.isArray(r)?r.map(c=>typeof c=="string"?c.trim():"").filter(Boolean):[];if(a.length>=2)return dM(t,e,s,a);a.length===1&&!n&&(n=a[0]),typeof n=="string"&&!H.isAbsolute(n)&&/^[^/\s]+\/[^/\s]+$/.test(n)&&(n=await es(n)??await El(n));let i=await M0([n,o,OC]);if(i){let c=`track/${lp(e)}-${t}`;try{let l=await Ci(i);await co(i,s,c,l),await Uf(s);let u=await st(i).catch(()=>null);return{dir:s,base:i,branch:c,kind:"worktree",baseRef:l,repo:u}}catch{await U.rm(s,{recursive:!0,force:!0}).catch(()=>{})}}return await U.mkdir(s,{recursive:!0}),await ry(s),await Uf(s),{dir:s,base:null,branch:null,kind:"repo"}}async function Uf(t){try{await U.writeFile(H.join(t,"AGENTS.md"),ea,{flag:"wx"})}catch{return}await wM(t,["/AGENTS.md"])}function hM(t,e){let n=t.map(r=>`- \`${r.name}/\`${r.repo?` \u2014 github.com/${r.repo}`:""}${r.baseRef?` (forked from ${r.baseRef})`:""}`).join(`
161
- `);return`${mM}
164
+ ${o}`,{source:"restore"})}else Uo(r,o);return await J(),{ok:!0,draft:r.draft||null,rev:r.draftRev||0}}async function gp(t,e){if(typeof e!="string"||!e.trim())throw new Error("model (string) required");let n=e.trim(),r=Z(await K(),t);if(!r)throw new Error(`track "${t}" not found`);let o=await et(r.leadBox);if(!o)throw new Error(`lead box "${r.leadBox}" is not running`);let a=r.boxes.find(f=>f.name===r.leadBox)?.agent||o.agent||"claude",i=Ky(a,n),l=[...r.events||[]].reverse().find(f=>f.type==="model-change")?.to??null;l||(l=(await Ss(o.cwd,o.sessionId,{fallbackNewest:!1}).catch(()=>null))?.model??null),await In({cwd:o.cwd,sessionId:o.sessionId,sessionName:r.leadBox,agent:o.agent,agentCmd:xa(o.agent)});let u=await Gy(a,r.leadBox,i);return pt(r,"model-change",{to:n,from:l,box:r.leadBox,agent:a,verified:!!u.verified}),await J(),{ok:!0,requested:n,leadBox:r.leadBox,...u}}async function ix(t){for(let e of t){if(!e||!await qi(e))continue;let n=await Sy(e).catch(()=>null);if(!n)continue;if((await H.stat(W.join(n,".git")).catch(()=>null))?.isDirectory())return n}return null}function ae(t){let e=t;return e?e.kind==="multi"?Array.isArray(e.repos)?e.repos.filter(Boolean):[]:e.base?[{name:W.basename(e.base),dir:e.dir??null,base:e.base,baseRef:e.baseRef??null,repo:e.repo??null}]:[]:[]}async function _o(t){let e=[];for(let n of ae(t?.workspace)){if(!n?.dir)continue;let r=await Sd(n.dir,{ignorePlumbing:!0}).catch(()=>!1),o=await vd(n.dir,n.baseRef).catch(()=>0);(r||o>0)&&e.push({...n,dirty:r,ahead:o})}return e}async function cx(t){let e=t;typeof e=="string"&&!W.isAbsolute(e)&&/^[^/\s]+\/[^/\s]+$/.test(e)&&(e=await Gr(e)??await oi(e));let n=await ix([e]);if(!n)throw new Error(`tagged repo "${t}" is not a usable base (need a primary checkout or a synced owner/name)`);return n}async function YM(t,e,n,r){let o=`track/${Np(e)}-${t}`,s=[];try{await H.mkdir(n,{recursive:!0});let a=new Set([".bostrat"]);for(let i of r){let c=await cx(i);if(s.some(p=>p.base===c))throw new Error(`repo tagged twice: ${i}`);let l=await lt(c).catch(()=>null),u=W.basename(c);a.has(u)&&l&&(u=l.replace("/","-"));for(let p=2;a.has(u);p++)u=`${W.basename(c)}-${p}`;a.add(u);let f=W.join(n,u),d=await xo(c);await ko(c,f,o,d),s.push({name:u,dir:f,base:c,baseRef:d,repo:l})}return await Aa(n,s,o),{dir:n,kind:"multi",branch:o,repos:s}}catch(a){for(let i of s)await re(i.base,i.dir).catch(()=>{});throw await H.rm(n,{recursive:!0,force:!0}).catch(()=>{}),a}}async function yp(t,e){let n=await K(),r=Z(n,t);if(!r)throw new Error(`track "${t}" 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 cx(typeof e=="string"?e.trim():e);if((o.repos??[]).some(d=>d?.base===s))throw new Error(`repo already tagged: ${e}`);let a=await lt(s).catch(()=>null),i=new Set([".bostrat",...(o.repos??[]).map(d=>d?.name).filter(Boolean)]),c=W.basename(s);i.has(c)&&a&&(c=a.replace("/","-"));for(let d=2;i.has(c);d++)c=`${W.basename(s)}-${d}`;let l=W.join(o.dir,c),u=await xo(s);await vy(s,o.branch)?await Ki(s,l,o.branch):await ko(s,l,o.branch,u);let f={name:c,dir:l,base:s,baseRef:u,repo:a};return o.repos=[...(o.repos??[]).filter(Boolean),f],await Aa(o.dir,o.repos,o.branch),pt(r,"retagged",{action:"add",repo:a??s,name:c,workspace:lx(o)}),await J(),f}async function bp(t,e){let n=await K(),r=Z(n,t);if(!r)throw new Error(`track "${t}" 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===e||c.repo===e||c.base===e));if(!s)throw new Error(`repo "${e}" 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 se.values())if(c.trackId===t&&!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 Sd(s.dir,{ignorePlumbing:!0}).catch(()=>!1),i=await vd(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 re(s.base,s.dir).catch(()=>{}),await H.rm(s.dir,{recursive:!0,force:!0}).catch(()=>{}),o.repos=(o.repos??[]).filter(c=>c&&c!==s),await Aa(o.dir,o.repos,o.branch),pt(r,"retagged",{action:"remove",repo:s.repo??s.base,name:s.name,workspace:lx(o)}),await J(),{removed:s.name}}async function XM(t,e,{repo:n,repos:r,cwd:o}={}){await H.mkdir(da,{recursive:!0});let s=W.join(da,t),a=Array.isArray(r)?r.map(c=>typeof c=="string"?c.trim():"").filter(Boolean):[];if(a.length>=2)return YM(t,e,s,a);a.length===1&&!n&&(n=a[0]),typeof n=="string"&&!W.isAbsolute(n)&&/^[^/\s]+\/[^/\s]+$/.test(n)&&(n=await Gr(n)??await oi(n));let i=await ix([n,o,gM]);if(i){let c=`track/${Np(e)}-${t}`;try{let l=await xo(i);await ko(i,s,c,l),await wa(s);let u=await lt(i).catch(()=>null);return{dir:s,base:i,branch:c,kind:"worktree",baseRef:l,repo:u}}catch{await H.rm(s,{recursive:!0,force:!0}).catch(()=>{})}}return await H.mkdir(s,{recursive:!0}),await Td(s),await wa(s),{dir:s,base:null,branch:null,kind:"repo"}}async function wa(t){try{await H.writeFile(W.join(t,"AGENTS.md"),ua,{flag:"wx"})}catch{return}await eN(t,["/AGENTS.md"])}function tN(t,e){let n=t.map(r=>`- \`${r.name}/\`${r.repo?` \u2014 github.com/${r.repo}`:""}${r.baseRef?` (forked from ${r.baseRef})`:""}`).join(`
165
+ `);return`${QM}
162
166
 
163
167
  This directory is NOT a git repo. It is a bostrat Track workspace holding one
164
168
  git worktree per tagged repo, ALL on the same branch \`${e}\`:
@@ -170,18 +174,20 @@ push / open PRs) in each repo separately, always on that shared branch. Work
170
174
  only needs to land in the repos it actually touches \u2014 an untouched repo's
171
175
  branch simply stays at its fork point and never gets pushed. When asked to run
172
176
  or preview an app, run it from that app's own repo directory.
173
- `}async function Ec(t,e,n){let r=hM(e,n);for(let o of["CLAUDE.md","AGENTS.md"])await U.writeFile(H.join(t,o),r).catch(()=>{})}async function D0(t){let{stdout:e}=await RC("git",["-C",t,"rev-parse","--git-path","info/exclude"]);return H.resolve(t,e.trim())}async function wM(t,e){try{let n=await D0(t);await U.mkdir(H.dirname(n),{recursive:!0});let r=await U.readFile(n,"utf8").catch(()=>""),o=e.filter(s=>!r.split(`
174
- `).includes(s));o.length&&await U.appendFile(n,(r.endsWith(`
177
+ `}async function Aa(t,e,n){let r=tN(e,n);for(let o of["CLAUDE.md","AGENTS.md"])await H.writeFile(W.join(t,o),r).catch(()=>{})}async function dx(t){let{stdout:e}=await V0("git",["-C",t,"rev-parse","--git-path","info/exclude"]);return W.resolve(t,e.trim())}async function eN(t,e){try{let n=await dx(t);await H.mkdir(W.dirname(n),{recursive:!0});let r=await H.readFile(n,"utf8").catch(()=>""),o=e.filter(s=>!r.split(`
178
+ `).includes(s));o.length&&await H.appendFile(n,(r.endsWith(`
175
179
  `)||!r?"":`
176
180
  `)+o.join(`
177
181
  `)+`
178
- `)}catch{}}async function gM(t,e){try{let n=await D0(t),r=await U.readFile(n,"utf8"),o=r.split(`
182
+ `)}catch{}}async function nN(t,e){try{let n=await dx(t),r=await H.readFile(n,"utf8"),o=r.split(`
179
183
  `).filter(s=>s!==e);o.length!==r.split(`
180
- `).length&&await U.writeFile(n,o.join(`
181
- `))}catch{}}async function tp(){let t={refreshed:0,removed:0,codexGlobal:null};try{await U.mkdir(ln,{recursive:!0}),await U.writeFile(H.join(ln,"CLAUDE.md"),pM).catch(()=>{}),await U.writeFile(H.join(ln,"AGENTS.md"),ea).catch(()=>{});let e=process.env.CODEX_HOME||H.join(process.env.HOME||"/tmp",".codex");if((await U.stat(e).catch(()=>null))?.isDirectory()){let r=H.join(e,"AGENTS.md"),o=await U.readFile(r,"utf8").catch(()=>null);o===null?(await U.writeFile(r,Bf,{flag:"wx"}).catch(()=>{}),t.codexGlobal="created"):Nf(o)&&o!==Bf&&(await U.writeFile(r,Bf).catch(()=>{}),t.codexGlobal="refreshed")}for(let r of[Df,Po]){let o=await U.readdir(r,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(!s.isDirectory())continue;let a=H.join(r,s.name),i=H.join(a,"AGENTS.md"),c=await U.readFile(i,"utf8").catch(()=>null);c!==null&&Nf(c)&&c!==ea&&(await U.writeFile(i,ea).catch(()=>{}),t.refreshed++);let l=H.join(a,"CLAUDE.md"),u=await U.readFile(l,"utf8").catch(()=>null);u!==null&&Nf(u)&&(await U.rm(l,{force:!0}).catch(()=>{}),await gM(a,"/CLAUDE.md"),t.removed++)}}}catch{}return t}async function yM(t){let e=t.workspace;if(!(!e||!e.dir))try{if(e.kind==="multi"){for(let n of pe(e))n.base&&n.dir&&await ae(n.base,n.dir).catch(()=>{});await U.rm(e.dir,{recursive:!0,force:!0})}else e.kind==="worktree"&&e.base?await ae(e.base,e.dir):await U.rm(e.dir,{recursive:!0,force:!0})}catch{}}async function _c({name:t,cwd:e,repo:n,repos:r,agent:o="claude",skipPermissions:s=!0}){if(typeof t!="string"||!t.trim())throw new Error("name (string) required");let a=await Sc(o,s),i=await q(),c=la().slice(0,8),l=await fM(c,t,{repo:n,repos:r,cwd:e}),u=new Set(i.tracks.flatMap(m=>(m.boxes||[]).map(w=>w.name))),d=`${t.trim()} lead`;u.has(Gl(d))&&(d=`${t.trim().slice(0,50).trim()} ${c} lead`);let f=await or(d,l.dir,{agentCmd:a,agent:o});mi({cwd:f.cwd,sessionName:f.name,agent:o,agentCmd:a});let p={id:c,name:t.trim(),cwd:f.cwd,workspace:l,leadBox:f.name,boxes:[H0(f,"lead","live")],events:[],createdAt:Date.now()};return pt(p,"opened",{agent:o,box:f.name,skipPermissions:s,name:p.name,cwd:p.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:m,base:w,baseRef:y,repo:k})=>({name:m,base:w,baseRef:y,repo:k}))}:{}}}),i.tracks.push(p),await Y(),un(p)}async function ep({provider:t="claude",fresh:e=!1}={}){if(!bM.has(t))throw new Error(`unknown setup provider "${t}" (claude | codex | cursor)`);let r=(await q()).tracks.find(u=>u.kind==="setup"&&u.setup?.provider===t&&!u.archivedAt);if(r){if(!e){let u=await un(r);if(u.boxes.find(f=>f.name===u.leadBox)?.state==="live")return u}await Rr(r.id).catch(()=>{})}let o=(await Sc(t,!1)).replace(/\s+--(?:dangerously-skip-permissions|dangerously-bypass-approvals-and-sandbox)\b/g,""),s=la().slice(0,8),a=H.join(ln,"setup",s);await U.mkdir(a,{recursive:!0});let i=await or(`Connect ${t} ${s}`,a,{agentCmd:o,agent:t,firstRun:!0});t==="codex"&&mi({cwd:i.cwd,sessionName:i.name,agent:t,agentCmd:o});let c={id:s,name:`Connect ${t}`,kind:"setup",setup:{provider:t,startedAt:Date.now(),connectedAt:null},cwd:i.cwd,workspace:{dir:a,base:null,branch:null,kind:"scratch"},leadBox:i.name,boxes:[H0(i,"lead","live")],events:[],createdAt:Date.now()};return pt(c,"opened",{agent:t,box:i.name,skipPermissions:!1,trackKind:"setup",name:c.name,cwd:c.cwd,workspace:{base:null,branch:null,kind:"scratch"}}),(await q()).tracks.push(c),await Y(),un(c)}async function j0(t,e,n){await Yb(t).catch(()=>{});let r=ia.get(t);r&&!r.finishedAt&&(r.error=n,r.finishedAt=Date.now()),ia.delete(t),e.handoff&&!e.handoff.finishedAt&&(e.handoff.step="error",e.handoff.error=n,e.handoff.finishedAt=Date.now());for(let a of $r(t))a.finishedAt||(a.canceled=!0,a.finishedAt=Date.now()),await fp(a).catch(()=>{}),de.delete(a.id);for(let a of Object.values(e.subtasks||{}))a.finishedAt||(a.step="error",a.error=n,a.canceled=!0,a.finishedAt=Date.now());let o=await q(),s=new Set((o.tracks||[]).filter(a=>a.id!==t&&!a.archivedAt).flatMap(a=>(a.boxes||[]).map(i=>i.name)));for(let a of e.boxes)s.has(a.name)||await _e(a.name).catch(()=>{})}async function np(t,{cascadeMocks:e=!0,cascadeRunbooks:n=!1}={}){let r=await q(),o=r.tracks.findIndex(a=>a.id===t);if(o===-1)throw new Error(`track "${t}" not found`);let s=r.tracks[o];return e||await Ck(s),O0(t),await j0(t,s,"track deleted"),n?await l0(t).catch(()=>{}):await c0(t).catch(()=>{}),await Ry(),await yM(s),e&&await Mk(t).catch(()=>{}),e?await Yk(t).catch(()=>{}):await Jk(s).catch(()=>{}),pt(s,"track-deleted",{name:s.name,boxes:s.boxes.length,ageMs:s.createdAt?Date.now()-s.createdAt:null}),r.tracks.splice(o,1),await Y(),{ok:!0,id:t,name:s.name,boxes:s.boxes.length}}async function Rr(t){let e=await q(),n=Q(e,t);if(!n)throw new Error(`track "${t}" not found`);if(n.archivedAt)throw new Error(`track "${t}" is already archived`);return n.archivedAt=Date.now(),O0(t),pt(n,"archived",{boxes:n.boxes.length}),await Y(),n.kind==="setup"?(await L0(t),un(n)):(aa.add(t),SM(t).catch(()=>{}).finally(()=>aa.delete(t)),{...await un(n),archiving:!0})}async function SM(t){try{await vM(t)}catch{}await L0(t).catch(()=>{})}async function L0(t){let e=await q(),n=Q(e,t);if(!(!n||!n.archivedAt)){await j0(t,n,"track archived");for(let r of n.boxes)Ir.has(r.state)||(r.state="stopped");await Y()}}async function vM(t){let e=await q(),n=Q(e,t);if(!n||!n.archivedAt)return;let r=null,o=[],s="derived",a=(n.events||[]).some(l=>l.type==="said"),i=n.leadBox?await tt(n.leadBox).catch(()=>null):null;if(i?.cwd&&a)try{({text:r,items:o}=await Xw(n.leadBox,i.cwd,{timeoutMs:xM})),s="lead-cli"}catch{}if(r||(r=pg(n,await L(n).catch(()=>[]))),!r)return;let c={text:r,source:s,at:Date.now()};o.length&&(c.items=o),n.beat=c,await I(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 Y()}async function Je(t,e){let n=await Wt(t,e).catch(()=>null);if(!n?.archiveOnMerge||!n.trackId)return!1;let r=await F0(n);if(r.length){for(let o of r)await br(o.repo,o.number,!0).catch(()=>{});return!1}try{return await Rr(n.trackId),!0}catch(o){if(/already archived/i.test(String(o?.message||o)))return!1;throw o}}async function F0(t){return(await kr().catch(()=>[])).filter(n=>n.trackId===t.trackId&&n.state!=="merged"&&n.state!=="closed"&&n.state!=="lost"&&!(n.repo===t.repo&&n.number===t.number))}async function Ye(t,e){return Ic(t,e,"merged")}async function Ic(t,e,n="merged"){let r=await Wt(t,e).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 F0(r);if(s.length){let i=[...r.notifyPending||[],o];for(let c of s)await ib(c.repo,c.number,i).catch(()=>{});return!1}let a=[...r.notifyPending||[],o];try{return await fe(r.trackId,U0(a),{kind:"merge-notify"}),!0}catch{return!1}}function U0(t){let e=i=>`${i.repo?`${i.repo}`:""}#${i.number}${i.title?` "${i.title}"`:""}${i.url?` (${i.url})`:""}`;if(t.length===1){let i=t[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 ${y0[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=t.filter(i=>i.outcome==="merged"),r=t.filter(i=>i.outcome!=="merged"),o=r.length?`${n.length} of the ${t.length} PRs on this Track merged; ${r.length} did not land:`:`All ${t.length} PRs on this Track have merged:`,s=t.map(i=>`- ${e(i)} \u2014 ${y0[i.outcome]??i.outcome}`).join(`
184
+ `).length&&await H.writeFile(n,o.join(`
185
+ `))}catch{}}async function kp(){let t={refreshed:0,removed:0,codexGlobal:null};try{await H.mkdir(fn,{recursive:!0}),await H.writeFile(W.join(fn,"CLAUDE.md"),ZM).catch(()=>{}),await H.writeFile(W.join(fn,"AGENTS.md"),ua).catch(()=>{});let e=process.env.CODEX_HOME||W.join(process.env.HOME||"/tmp",".codex");if((await H.stat(e).catch(()=>null))?.isDirectory()){let r=W.join(e,"AGENTS.md"),o=await H.readFile(r,"utf8").catch(()=>null);o===null?(await H.writeFile(r,tp,{flag:"wx"}).catch(()=>{}),t.codexGlobal="created"):Qf(o)&&o!==tp&&(await H.writeFile(r,tp).catch(()=>{}),t.codexGlobal="refreshed")}for(let r of[da,Ko]){let o=await H.readdir(r,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(!s.isDirectory())continue;let a=W.join(r,s.name),i=W.join(a,"AGENTS.md"),c=await H.readFile(i,"utf8").catch(()=>null);c!==null&&Qf(c)&&c!==ua&&(await H.writeFile(i,ua).catch(()=>{}),t.refreshed++);let l=W.join(a,"CLAUDE.md"),u=await H.readFile(l,"utf8").catch(()=>null);u!==null&&Qf(u)&&(await H.rm(l,{force:!0}).catch(()=>{}),await nN(a,"/CLAUDE.md"),t.removed++)}}}catch{}return t}async function fx(t){let e=t.workspace;if(!(!e||!e.dir))try{if(e.kind==="multi"){for(let n of ae(e))n.base&&n.dir&&await re(n.base,n.dir).catch(()=>{});await H.rm(e.dir,{recursive:!0,force:!0})}else e.kind==="worktree"&&e.base?await re(e.base,e.dir):await H.rm(e.dir,{recursive:!0,force:!0})}catch{}}async function Lc({name:t,cwd:e,repo:n,repos:r,agent:o="claude",skipPermissions:s=!0}){if(typeof t!="string"||!t.trim())throw new Error("name (string) required");let a=await Sa(o,s),i=await K(),c=ba().slice(0,8),l=await XM(c,t,{repo:n,repos:r,cwd:e}),u=new Set(i.tracks.flatMap(h=>(h.boxes||[]).map(w=>w.name))),f=`${t.trim()} lead`;u.has(bi(f))&&(f=`${t.trim().slice(0,50).trim()} ${c} lead`);let d=await An(f,l.dir,{agentCmd:a,agent:o});Es({cwd:d.cwd,sessionName:d.name,agent:o,agentCmd:a});let p={id:c,name:t.trim(),cwd:d.cwd,workspace:l,leadBox:d.name,boxes:[_p(d,"lead","live")],events:[],createdAt:Date.now()};return pt(p,"opened",{agent:o,box:d.name,skipPermissions:s,name:p.name,cwd:p.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:h,base:w,baseRef:y,repo:k})=>({name:h,base:w,baseRef:y,repo:k}))}:{}}}),i.tracks.push(p),await J(),Fe(p)}async function xp({provider:t="claude",fresh:e=!1}={}){if(!rN.has(t))throw new Error(`unknown setup provider "${t}" (claude | codex | cursor)`);let r=(await K()).tracks.find(u=>u.kind==="setup"&&u.setup?.provider===t&&!u.archivedAt);if(r){if(!e){let u=await Fe(r);if(u.boxes.find(d=>d.name===u.leadBox)?.state==="live")return u}await Br(r.id).catch(()=>{})}let o=(await Sa(t,!1)).replace(/\s+--(?:dangerously-skip-permissions|dangerously-bypass-approvals-and-sandbox)\b/g,""),s=ba().slice(0,8),a=W.join(fn,"setup",s);await H.mkdir(a,{recursive:!0});let i=await An(`Connect ${t} ${s}`,a,{agentCmd:o,agent:t,firstRun:!0});t==="codex"&&Es({cwd:i.cwd,sessionName:i.name,agent:t,agentCmd:o});let c={id:s,name:`Connect ${t}`,kind:"setup",setup:{provider:t,startedAt:Date.now(),connectedAt:null},cwd:i.cwd,workspace:{dir:a,base:null,branch:null,kind:"scratch"},leadBox:i.name,boxes:[_p(i,"lead","live")],events:[],createdAt:Date.now()};return pt(c,"opened",{agent:t,box:i.name,skipPermissions:!1,trackKind:"setup",name:c.name,cwd:c.cwd,workspace:{base:null,branch:null,kind:"scratch"}}),(await K()).tracks.push(c),await J(),Fe(c)}async function Sp(t,e,n){await wk(t).catch(()=>{});let r=qo.get(t);r&&!r.finishedAt&&(r.error=n,r.finishedAt=Date.now()),qo.delete(t),e.handoff&&!e.handoff.finishedAt&&(e.handoff.step="error",e.handoff.error=n,e.handoff.finishedAt=Date.now());for(let a of jr(t))a.finishedAt||(a.canceled=!0,a.finishedAt=Date.now()),await Bp(a).catch(()=>{}),se.delete(a.id);for(let a of Object.values(e.subtasks||{}))a.finishedAt||(a.step="error",a.error=n,a.canceled=!0,a.finishedAt=Date.now());let o=await K(),s=new Set((o.tracks||[]).filter(a=>a.id!==t&&!a.archivedAt).flatMap(a=>(a.boxes||[]).map(i=>i.name)));for(let a of e.boxes)s.has(a.name)||await Re(a.name).catch(()=>{})}async function vp(t,{cascadeMocks:e=!0,cascadeRunbooks:n=!1}={}){let r=await K(),o=r.tracks.findIndex(a=>a.id===t);if(o===-1)throw new Error(`track "${t}" not found`);let s=r.tracks[o];return e||await Zk(s),hp(t),await Sp(t,s,"track deleted"),n?await R0(t).catch(()=>{}):await I0(t).catch(()=>{}),await Jy(),await fx(s),e&&await Qk(t).catch(()=>{}),e?await w0(t).catch(()=>{}):await h0(s).catch(()=>{}),pt(s,"track-deleted",{name:s.name,boxes:s.boxes.length,ageMs:s.createdAt?Date.now()-s.createdAt:null}),r.tracks.splice(o,1),await J(),{ok:!0,id:t,name:s.name,boxes:s.boxes.length}}async function Br(t){let e=await K(),n=Z(e,t);if(!n)throw new Error(`track "${t}" not found`);if(n.archivedAt)throw new Error(`track "${t}" is already archived`);return n.archivedAt=Date.now(),hp(t),pt(n,"archived",{boxes:n.boxes.length}),await J(),n.kind==="setup"?(await px(t),Fe(n)):(ga.add(t),aN(t).catch(()=>{}).finally(()=>ga.delete(t)),{...await Fe(n),archiving:!0})}async function aN(t){try{await iN(t)}catch{}await px(t).catch(()=>{})}async function px(t){let e=await K(),n=Z(e,t);if(!(!n||!n.archivedAt)){await Sp(t,n,"track archived");for(let r of n.boxes)Gn.has(r.state)||(r.state="stopped");await J()}}async function iN(t){let e=await K(),n=Z(e,t);if(!n||!n.archivedAt)return;let r=null,o=[],s="derived",a=(n.events||[]).some(l=>l.type==="said"),i=n.leadBox?await et(n.leadBox).catch(()=>null):null;if(i?.cwd&&a)try{({text:r,items:o}=await xg(n.leadBox,i.cwd,{timeoutMs:sN})),s="lead-cli"}catch{}if(r||(r=Pg(n,await F(n).catch(()=>[]))),!r)return;let c={text:r,source:s,at:Date.now()};o.length&&(c.items=o),n.beat=c,await I(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 J()}async function Xe(t,e){let n=await Kt(t,e).catch(()=>null);if(!n?.archiveOnMerge||!n.trackId)return!1;let r=await mx(n);if(r.length){for(let o of r)await _r(o.repo,o.number,!0).catch(()=>{});return!1}try{return await Br(n.trackId),!0}catch(o){if(/already archived/i.test(String(o?.message||o)))return!1;throw o}}async function mx(t){return(await Ir().catch(()=>[])).filter(n=>n.trackId===t.trackId&&n.state!=="merged"&&n.state!=="closed"&&n.state!=="lost"&&!(n.repo===t.repo&&n.number===t.number))}async function Ze(t,e){return Fc(t,e,"merged")}async function Fc(t,e,n="merged"){let r=await Kt(t,e).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 mx(r);if(s.length){let i=[...r.notifyPending||[],o];for(let c of s)await _b(c.repo,c.number,i).catch(()=>{});return!1}let a=[...r.notifyPending||[],o];try{return await me(r.trackId,hx(a),{kind:"merge-notify"}),!0}catch{return!1}}function hx(t){let e=i=>`${i.repo?`${i.repo}`:""}#${i.number}${i.title?` "${i.title}"`:""}${i.url?` (${i.url})`:""}`;if(t.length===1){let i=t[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 ${q0[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=t.filter(i=>i.outcome==="merged"),r=t.filter(i=>i.outcome!=="merged"),o=r.length?`${n.length} of the ${t.length} PRs on this Track merged; ${r.length} did not land:`:`All ${t.length} PRs on this Track have merged:`,s=t.map(i=>`- ${e(i)} \u2014 ${q0[i.outcome]??i.outcome}`).join(`
182
186
  `),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}
183
187
  ${s}
184
- ${a}`}async function Rc(t){if(t.archivedAt)return!1;let e=t.boxes.find(o=>o.name===t.leadBox);if(!e||Ir.has(e.state)||await tt(e.name))return!1;let n=Hf(e.agent,e.sessionId),r=await oi(n);if(r===Hr)return pt(t,"rehydrate-failed",{box:e.name,agent:e.agent,reason:`agent "${e.agent}" is not installed on this box`}),!1;r===Wr&&console.warn(`[track] ${e.name}: could not confirm "${e.agent}" on PATH \u2014 relaunching anyway (launch verifier will catch a real miss)`);try{let o=await or(e.name,e.cwd,{agentCmd:n,agent:e.agent,resumeSessionId:e.sessionId,pinned:e.pinned===!0});return e.hookTokenHash=Yo(o.hookToken),mi({cwd:e.cwd,sessionName:e.name,agent:e.agent,agentCmd:n}),e.state="live",pt(t,"rehydrated",{box:e.name,agent:e.agent}),!0}catch(o){return pt(t,"rehydrate-failed",{box:e.name,agent:e.agent,reason:String(o?.message||o)}),!1}}async function rp(t){let e=await q(),n=Q(e,t);if(!n)throw new Error(`track "${t}" not found`);if(!n.archivedAt)throw new Error(`track "${t}" is not archived`);return delete n.archivedAt,aa.delete(t),pt(n,"unarchived",{}),await Rc(n),await Y(),un(n)}async function op(){let t=await q(),e=new Set((await he()).map(s=>s.name)),n=new Set((t.tracks||[]).filter(s=>!s.archivedAt).flatMap(s=>(s.boxes||[]).map(a=>a.name))),r=0,o=!1;for(let s of t.tracks||[])if(s.archivedAt)for(let a of s.boxes)e.has(a.name)&&!n.has(a.name)&&(await _e(a.name).catch(()=>{}),pt(s,"orphan-reaped",{box:a.name,agent:a.agent}),r++,o=!0),!Ir.has(a.state)&&a.state!=="stopped"&&(a.state="stopped",o=!0);return o&&await Y(),r}async function $c(t){let e=await q(),n=Q(e,t);if(!n)throw new Error(`track "${t}" not found`);if(n.archivedAt)throw new Error(`track "${t}" is archived \u2014 restore it before restarting the lead`);let r=n.boxes.find(a=>a.name===n.leadBox);if(!r)throw new Error(`track "${t}" has no lead box`);if(Ir.has(r.state))throw new Error("lead box is terminal \u2014 nothing to restart");if(await tt(n.leadBox)){let a=await yt(n.leadBox,{lines:Ct}).catch(()=>"");if(fi(r.agent,a))throw new Error("lead is mid-turn \u2014 retry when it goes idle");await _e(n.leadBox),r.state="stopped"}let s=await Rc(n);if(await Y(),!s)throw new Error("rehydrate failed \u2014 see the track's rehydrate-failed event");return un(n)}async function sp(t,e,n){let r=await z(t);if(!r)throw new Error(`track "${t}" not found`);if(!e)throw new Error("unknown offer");let o=await L(r).catch(()=>[]);if(!o.some(i=>i.type==="box.fullscreen.detected"&&i.payload?.offerId===e))throw new Error("unknown offer");if(o.some(i=>i.type==="box.fullscreen.answered"&&i.payload?.offerId===e))throw new Error("offer already answered");return n&&await $c(t),await I(r,{type:"box.fullscreen.answered",actor:"user",source:"orchestrator",boxId:r.leadBox,payload:{ts:Date.now(),offerId:e,action:n?"restarted":"dismiss"}}).catch(()=>{}),{ok:!0,action:n?"restarted":"dismiss"}}function ap(t){return(!Array.isArray(t.epochs)||t.epochs.length===0)&&(t.epochs=[{agent:t.agent??null,sessionId:t.sessionId??null,pinned:t.pinned===!0,startedAt:t.createdAt??null,endedAt:null}]),t.epochs}async function bc(t,e){let n=await q(),r=Q(n,t);r&&(r.handoff={...r.handoff||{},...e},await Y())}function W0(t,e=Date.now()){let n=t?.handoff;if(!n||n.finishedAt)return null;let r=n.step,o=!!n.toBox&&n.toBox===n.fromBox,s=t.boxes?.find?.(i=>i.name===t.leadBox)||null;return(o?t.leadBox===n.fromBox&&!!n.startedAt&&Array.isArray(s?.epochs)&&s.epochs.some(i=>i.startedAt!=null&&i.startedAt>=n.startedAt):!!n.toBox&&t.leadBox===n.toBox)?{...n,step:"done",finishedAt:e,recovered:`committed before restart (was "${r}")`}:{...n,step:"error",finishedAt:e,error:`interrupted by an agent restart during "${r}"; lead "${t.leadBox}" retained \u2014 retry the handoff`,recovered:"rolled-back"}}async function ip(){let t=await q(),e=!1;for(let n of t.tracks||[]){let r=n.handoff,o=W0(n);if(!o)continue;e=!0;let s=!!r.toBox&&r.toBox===r.fromBox;if(s&&o.step==="error"){let c=await tt(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=ap(l),f=d[d.length-1],p=f.agent,m=f.sessionId??null;f.endedAt=u,r.reason&&(f.endReason=r.reason);let w=c.agent==="claude"&&!!c.sessionId;d.push({agent:r.toAgent,sessionId:c.sessionId||null,pinned:w,startedAt:u,endedAt:null}),l.agent=r.toAgent,l.sessionId=c.sessionId||null,l.pinned=w,l.state="live",n.pendingHandoffHydrate={artifact:fa,at:u},pt(n,"lead-handoff",{from:r.fromBox,to:r.fromBox,fromAgent:p,toAgent:r.toAgent,fromSessionId:m,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 G({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 G({flow:"lead-handoff",phase:"reconciled",trackId:n.id,outcome:o.step,recovered:o.recovered,fromBox:o.fromBox,toBox:o.toBox}).catch(()=>{}),i&&await _e(i).catch(()=>{}),a&&await _e(a).catch(()=>{})}return e&&await Y(),e}async function Oc(t,e,n=!0,r=null){let o=ia.get(t);if(o&&!o.finishedAt)throw new Error("a lead handoff is already running for this Track");let s=Q(await q(),t);if(!s)throw new Error(`track "${t}" not found`);ma(t,"handoff");let a=await Sc(e,n),i=fo(e);if(i){let u=new Error(`can't hand off to ${e} \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 tt(s.leadBox);if(!c)throw new Error(`lead box "${s.leadBox}" is not running`);let l={trackId:t,step:"checkpoint",fromBox:s.leadBox,toAgent:e,skipPermissions:n,reason:v0(r),toBox:s.leadBox,startedAt:Date.now(),finishedAt:null,error:null};return ia.set(t,l),await bc(t,{step:l.step,fromBox:l.fromBox,toAgent:e,toBox:l.toBox,skipPermissions:n,startedAt:l.startedAt,finishedAt:null,error:null}),TM(l,s,c,a,e).catch(async u=>{l.error=u?.message||String(u),l.finishedAt=Date.now(),console.error(`[lead-handoff ${t}] FAILED at step "${l.step}": ${l.error}`),await bc(t,{step:l.step,error:l.error,finishedAt:l.finishedAt}).catch(()=>{}),G({flow:"lead-handoff",phase:"failed",trackId:t,step:l.step,error:l.error,fromBox:l.fromBox,toAgent:l.toAgent,toBox:l.toBox}).catch(()=>{})}),G({flow:"lead-handoff",phase:"started",trackId:t,fromBox:l.fromBox,toAgent:e,cwd:c.cwd}).catch(()=>{}),l}async function TM(t,e,n,r,o){let s=async(R,J={})=>{t.step=R,console.log(`[lead-handoff ${t.trackId}] step \u2192 ${R}`),await bc(t.trackId,{step:R,toBox:t.toBox}),await G({flow:"lead-handoff",phase:R,trackId:t.trackId,fromBox:t.fromBox,toBox:t.toBox,toAgent:o,sessionName:J.sessionName,...J})};console.log(`[lead-handoff ${t.trackId}] ${t.fromBox}: ${n.agent} \u2192 ${o} IN PLACE`);let a=await q(),i=Q(a,t.trackId)?.boxes.find(R=>R.name===t.fromBox)||null,c=i?.agent||n.agent,l=i?.sessionId??n.sessionId??null,u=i?.pinned===!0;if(await s("checkpoint",{sessionName:t.fromBox}),t.checkpoint="llm",fo(c))t.checkpoint="skipped-capped";else try{await og(t.fromBox,{timeoutMs:CC})}catch(R){t.checkpoint="reconstructed",await G({flow:"lead-handoff",phase:"checkpoint-fallback",trackId:t.trackId,fromBox:t.fromBox,error:R?.message||String(R)}).catch(()=>{})}t.checkpoint!=="llm"&&(t.statusArtifact=await sg(t.trackId,n.cwd,{trackName:e.name||e.id}).catch(()=>null),await s("checkpoint-degraded",{sessionName:t.fromBox,checkpoint:t.checkpoint,statusArtifact:t.statusArtifact})),await s("swap",{cwd:n.cwd,agentCmd:r});let f=await Uu(t.fromBox,{agentCmd:r,agent:o});await s("hydrate",{sessionName:t.fromBox}),await Tn({cwd:n.cwd,sessionId:f.sessionId,sessionName:t.fromBox,agent:o,agentCmd:da(o)});let p=await yt(t.fromBox,{lines:Ct}).catch(()=>"");if(!pi(o,p)){await s("rollback",{sessionName:t.fromBox,fromAgent:c});let R=Hf(c,l,{skipPermissions:t.skipPermissions});await Uu(t.fromBox,{agentCmd:R,agent:c,resumeSessionId:l,pinned:u});let J=await q(),C=Q(J,t.trackId);if(C){let D=C.boxes.find(A=>A.name===t.fromBox);D&&(D.state="live"),pt(C,"lead-handoff-failed",{box:t.fromBox,fromAgent:c,toAgent:o,reason:t.reason,error:`incoming ${o} CLI never drew its composer`,rolledBack:!0,handoffStartedAt:t.startedAt}),await Y()}throw new Error(`incoming ${o} CLI never drew its composer \u2014 rolled back to ${c} (--resume, context intact)`)}await s("commit");let m=await q(),w=Q(m,t.trackId);if(!w)throw new Error(`track "${t.trackId}" not found during handoff commit \u2014 was it deleted or archived mid-flight?`);let y=w.boxes.find(R=>R.name===t.fromBox);if(!y)throw new Error(`lead box row "${t.fromBox}" missing during handoff commit`);let k=Date.now(),S=ap(y),$=S[S.length-1];$.endedAt=k,t.reason&&($.endReason=t.reason),S.push({agent:o,sessionId:f.sessionId,pinned:f.pinned,startedAt:k,endedAt:null}),y.agent=o,y.sessionId=f.sessionId,y.pinned=f.pinned,y.state="live",y.role="lead",w.pendingHandoffHydrate={artifact:t.statusArtifact||fa,at:k},pt(w,"lead-handoff",{from:t.fromBox,to:t.fromBox,fromAgent:c,toAgent:o,fromSessionId:l,toSessionId:f.sessionId,epoch:S.length-1,singleBox:!0,forced:f.forced||void 0,skipPermissions:t.skipPermissions,reason:t.reason,handoffStartedAt:t.startedAt,checkpoint:t.checkpoint}),await Y(),await s("done",{sessionName:t.fromBox}),await bc(t.trackId,{finishedAt:Date.now(),error:null}),t.finishedAt=Date.now()}async function q0(t,e,n){let r=await q(),o=Q(r,t);o&&(o.subtasks=o.subtasks||{},o.subtasks[e]={...o.subtasks[e]||{},...n},await Y())}async function Ro(t,e){t.step=e,await ha(t)}function K0(t,e=Date.now()){if(!t||t.finishedAt)return null;let n=t.step;return["snapshot","spawn","working"].includes(n)?{...t,step:"error",finishedAt:e,error:`interrupted by an agent restart during "${n}"; no changes were applied to the lead \u2014 retry the delegation`,recovered:"rolled-back"}:{...t,step:"error",finishedAt:e,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 ${t.branch}`,recovered:"partial-merge"}}function G0(t){return!!t&&!t.finishedAt&&!t.canceled&&t.step==="working"&&!!t.box&&!!t.dir&&!!t.base&&!!t.branch}async function IM(t,e,n){if(!G0(n)||de.has(e)||!await tt(n.box).catch(()=>null))return!1;try{await U.access(n.dir)}catch{return!1}let o=await tt(t.leadBox).catch(()=>null);if(!o?.cwd)return!1;let s={...n,id:e,leadBox:t.leadBox,step:"working",canceled:!1,forceMerge:!1};return de.set(e,s),z0(s,o).catch(a=>V0(s,a)),!0}async function cp(){let t=await q(),e=!1;for(let n of t.tracks||[]){for(let[r,o]of Object.entries(n.subtasks||{})){if(de.has(r))continue;if(await IM(n,r,o)){e=!0,pt(n,"subtask-resumed",{box:o.box,agent:o.agent,task:o.task,subtaskId:r,resumedStep:o.step}),await G({flow:"subtask",phase:"resumed",trackId:n.id,subtaskId:r,box:o.box,branch:o.branch}).catch(()=>{});continue}let s=o.step,a=K0(o);if(!a)continue;e=!0,n.subtasks[r]=a;let i=n.boxes.find(c=>c.subtaskId===r);i&&!Ir.has(i.state)&&(i.state="canceled"),pt(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 G({flow:"subtask",phase:"reconciled",trackId:n.id,subtaskId:r,outcome:a.step,recovered:a.recovered,box:o.box,branch:o.branch}).catch(()=>{}),await b0(n,o.box,o.dir)}for(let r of n.boxes){if(r.role!=="subtask"||Ir.has(r.state)||de.has(r.subtaskId)||n.subtasks?.[r.subtaskId])continue;e=!0,r.state="canceled";let o=r.subtaskId?H.join(Po,`${n.id}-${r.subtaskId}`):null;await G({flow:"subtask",phase:"reaped-legacy-orphan",trackId:n.id,subtaskId:r.subtaskId,box:r.name}).catch(()=>{}),await b0(n,r.name,o)}}return e=await RM(t)||e,e&&await Y(),e}async function b0(t,e,n){if(e&&await _e(e).catch(()=>{}),!n)return;if(t.workspace?.kind==="multi"){for(let o of pe(t.workspace)){let s=H.join(n,o.name);await ae(o.base,s).then(()=>!0,()=>!1)||await ae(o.dir,s).catch(()=>{})}await U.rm(n,{recursive:!0,force:!0}).catch(()=>{});return}let r=await tt(t.leadBox).catch(()=>null);r?.cwd&&await ae(r.cwd,n).catch(()=>{})}async function RM(t){let e;try{e=await U.readdir(Po)}catch{return!1}let n=new Set;for(let o of t.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 de.values())o.dir&&n.add(H.basename(o.dir));let r=!1;for(let o of e){if(n.has(o))continue;let s=H.join(Po,o),a=(t.tracks||[]).find(i=>o.startsWith(`${i.id}-`));if(a?.workspace?.kind==="multi"){for(let i of pe(a.workspace))await ae(i.base,H.join(s,i.name)).catch(()=>{});await U.rm(s,{recursive:!0,force:!0}).catch(()=>{})}else{let i=a?await tt(a.leadBox).catch(()=>null):null;i?.cwd?await ae(i.cwd,s).catch(()=>{}):await U.rm(s,{recursive:!0,force:!0}).catch(()=>{})}await G({flow:"subtask",phase:"swept-orphan-worktree",dir:s}).catch(()=>{}),r=!0}return r}async function up(t,{agent:e,task:n,skipPermissions:r=!0,reason:o=null}={}){if(typeof n!="string"||!io(n))throw new Error("task (string) required");let s=await Sc(e,r),a=fo(e);if(a){let p=new Error(`can't delegate to ${e} \u2014 its ${a.window} spend limit is reached ($${a.spentUsd.toFixed(2)} of $${a.limitUsd.toFixed(2)})`);throw p.usageCap=a,p}let i=Q(await q(),t);if(!i)throw new Error(`track "${t}" not found`);let c=await tt(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 p=pe(i.workspace);if(!p.length)throw new Error("this multi-repo Track has no tagged repos to delegate into");for(let m of p)if(!m?.dir||!await Oi(m.dir))throw new Error(`tagged checkout "${m?.name??"?"}" is missing from the lead workspace (${m?.dir??"no dir"})`);u=p.map(m=>({name:m.name,leadDir:m.dir,base:null}))}else if(!await Oi(c.cwd))throw new Error(`subtask delegation needs the lead's workspace to be a git repo (got ${c.cwd})`);let d=la().slice(0,8),f={id:d,trackId:t,trackName:i.name,agent:e,task:io(n),skipPermissions:r,reason:v0(o),step:"snapshot",leadBox:i.leadBox,box:null,branch:`bostrat/${lp(i.name)}-${d}`,base:null,repos:u,dir:H.join(Po,`${t}-${d}`),stat:null,conflicts:[],applied:null,startedAt:Date.now(),finishedAt:null,error:null,canceled:!1,forceMerge:!1};return de.set(d,f),await ha(f),$M(f,c,s).catch(p=>V0(f,p)),f}async function V0(t,e){t.failedStep=t.step,t.error=e instanceof ca?"canceled":e?.message||String(e),t.step=e instanceof ca?"canceled":"error",t.finishedAt=Date.now(),await fp(t).catch(()=>{}),await ha(t).catch(()=>{}),await PM(t).catch(()=>{})}function Mc(t){let e=de.get(t);if(!e)throw new Error(`subtask "${t}" not found`);if(e.finishedAt)throw new Error("subtask already finished");return e.canceled=!0,e}function dp(t){let e=de.get(t);if(!e)throw new Error(`subtask "${t}" not found`);if(e.finishedAt)throw new Error("subtask already finished");if(e.step!=="working")throw new Error(`subtask is not waiting to merge (step: ${e.step})`);return e.forceMerge=!0,e}async function $M(t,e,n){if(await Ro(t,"snapshot"),t.repos){for(let s of t.repos)s.base=await Rs(s.leadDir,`bostrat: snapshot for subtask ${t.id}`);await ha(t)}else t.base=await Rs(e.cwd,`bostrat: snapshot for subtask ${t.id}`);if(await Ro(t,"spawn"),await U.mkdir(Po,{recursive:!0}),t.repos){await U.mkdir(t.dir,{recursive:!0});for(let a of t.repos)await co(a.leadDir,H.join(t.dir,a.name),t.branch,a.base);let s=pe((Q(await q(),t.trackId)||{}).workspace);await Ec(t.dir,t.repos.map(a=>{let i=s.find(c=>c?.name===a.name);return{name:a.name,repo:i?.repo??null,baseRef:null}}),t.branch)}else await co(e.cwd,t.dir,t.branch,t.base),await Uf(t.dir);await OM(t,e);let r=t.trackName.slice(0,38).trim(),o=await or(`${r} ${t.agent} sub ${t.id}`,t.dir,{agentCmd:n,agent:t.agent});t.box=o.name,await CM(t,o),await T0(t.trackId,o.name,PC(t.task,!!t.repos),{kind:"subtask"}),await z0(t,e)}async function z0(t,e){await Ro(t,"working");let n=H.join(t.dir,yc);if(await BM(n,t),t.canceled)throw new ca;if(await Ro(t,"merge"),t.repos){let s={files:0,insertions:0,deletions:0},a=[],i=[],c=!0;for(let l of t.repos){let u=H.join(t.dir,l.name);await ld(u,`bostrat: subtask ${t.id} result (auto-committed)`),l.stat=await pd(l.leadDir,l.base,t.branch,Io),l.files=await md(l.leadDir,l.base,t.branch,Io);let d=await hd(l.leadDir,l.base,t.branch,Io);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(f=>H.join(l.name,f))),i.push(...l.conflicts.map(f=>f.startsWith("patch did not apply cleanly")?`${l.name}: ${f}`:H.join(l.name,f))),d.applied||(c=!1)}t.stat=s,t.files=a,t.conflicts=i,t.applied=c}else{await ld(t.dir,`bostrat: subtask ${t.id} result (auto-committed)`),t.stat=await pd(e.cwd,t.base,t.branch,Io),t.files=await md(e.cwd,t.base,t.branch,Io);let s=await hd(e.cwd,t.base,t.branch,Io);t.applied=s.applied,t.conflicts=s.conflicts}await ha(t);let r=await NM(t,e,n);await Ro(t,"resume"),await T0(t.trackId,t.leadBox,NC(t.task,t.stat,t.conflicts,r),{kind:"subtask-resume"}),await Ro(t,"reap"),await fp(t),t.step="done";let o=Date.now();await q0(t.trackId,t.id,{...Cc(t),finishedAt:o}),await MM(t,o),t.finishedAt=o}async function OM(t,e){let n=H.join(t.dir,H.dirname(na));await U.mkdir(n,{recursive:!0});let r="";try{r=await Rh(e.cwd,e.sessionId)}catch{}if(!r)try{r=await U.readFile(H.join(e.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 ${t.id}
188
+ ${a}`}async function Uc(t){if(t.archivedAt)return!1;let e=t.boxes.find(o=>o.name===t.leadBox);if(!e||Gn.has(e.state)||await et(e.name))return!1;let n=ip(e.agent,e.sessionId),r=await yi(n);if(r===Xr)return pt(t,"rehydrate-failed",{box:e.name,agent:e.agent,reason:`agent "${e.agent}" is not installed on this box`}),!1;r===Zr&&console.warn(`[track] ${e.name}: could not confirm "${e.agent}" on PATH \u2014 relaunching anyway (launch verifier will catch a real miss)`);try{let o=await An(e.name,e.cwd,{agentCmd:n,agent:e.agent,resumeSessionId:e.sessionId,pinned:e.pinned===!0});return e.hookTokenHash=as(o.hookToken),Es({cwd:e.cwd,sessionName:e.name,agent:e.agent,agentCmd:n}),e.state="live",pt(t,"rehydrated",{box:e.name,agent:e.agent}),!0}catch(o){return pt(t,"rehydrate-failed",{box:e.name,agent:e.agent,reason:String(o?.message||o)}),!1}}async function Tp(t){let e=await K(),n=Z(e,t);if(!n)throw new Error(`track "${t}" not found`);if(!n.archivedAt)throw new Error(`track "${t}" is not archived`);return delete n.archivedAt,ga.delete(t),pt(n,"unarchived",{}),await Uc(n),await J(),Fe(n)}async function Ap(){let t=await K(),e=new Set((await ge()).map(s=>s.name)),n=new Set((t.tracks||[]).filter(s=>!s.archivedAt).flatMap(s=>(s.boxes||[]).map(a=>a.name))),r=0,o=!1;for(let s of t.tracks||[])if(s.archivedAt)for(let a of s.boxes)e.has(a.name)&&!n.has(a.name)&&(await Re(a.name).catch(()=>{}),pt(s,"orphan-reaped",{box:a.name,agent:a.agent}),r++,o=!0),!Gn.has(a.state)&&a.state!=="stopped"&&(a.state="stopped",o=!0);return o&&await J(),r}async function Hc(t){let e=await K(),n=Z(e,t);if(!n)throw new Error(`track "${t}" not found`);if(n.archivedAt)throw new Error(`track "${t}" is archived \u2014 restore it before restarting the lead`);let r=n.boxes.find(a=>a.name===n.leadBox);if(!r)throw new Error(`track "${t}" has no lead box`);if(Gn.has(r.state))throw new Error("lead box is terminal \u2014 nothing to restart");if(await et(n.leadBox)){let a=await Tt(n.leadBox,{lines:Nt}).catch(()=>"");if(_i(r.agent,a))throw new Error("lead is mid-turn \u2014 retry when it goes idle");await Re(n.leadBox),r.state="stopped"}let s=await Uc(n);if(await J(),!s)throw new Error("rehydrate failed \u2014 see the track's rehydrate-failed event");return Fe(n)}async function Ep(t,e,n){let r=await Y(t);if(!r)throw new Error(`track "${t}" not found`);if(!e)throw new Error("unknown offer");let o=await F(r).catch(()=>[]);if(!o.some(i=>i.type==="box.fullscreen.detected"&&i.payload?.offerId===e))throw new Error("unknown offer");if(o.some(i=>i.type==="box.fullscreen.answered"&&i.payload?.offerId===e))throw new Error("offer already answered");return n&&await Hc(t),await I(r,{type:"box.fullscreen.answered",actor:"user",source:"orchestrator",boxId:r.leadBox,payload:{ts:Date.now(),offerId:e,action:n?"restarted":"dismiss"}}).catch(()=>{}),{ok:!0,action:n?"restarted":"dismiss"}}function Wc(t){return(!Array.isArray(t.epochs)||t.epochs.length===0)&&(t.epochs=[{agent:t.agent??null,sessionId:t.sessionId??null,pinned:t.pinned===!0,startedAt:t.createdAt??null,endedAt:null}]),t.epochs}async function Mc(t,e){let n=await K(),r=Z(n,t);r&&(r.handoff={...r.handoff||{},...e},await J())}function wx(t,e=Date.now()){let n=t?.handoff;if(!n||n.finishedAt)return null;let r=n.step,o=!!n.toBox&&n.toBox===n.fromBox,s=t.boxes?.find?.(i=>i.name===t.leadBox)||null;return(o?t.leadBox===n.fromBox&&!!n.startedAt&&Array.isArray(s?.epochs)&&s.epochs.some(i=>i.startedAt!=null&&i.startedAt>=n.startedAt):!!n.toBox&&t.leadBox===n.toBox)?{...n,step:"done",finishedAt:e,recovered:`committed before restart (was "${r}")`}:{...n,step:"error",finishedAt:e,error:`interrupted by an agent restart during "${r}"; lead "${t.leadBox}" retained \u2014 retry the handoff`,recovered:"rolled-back"}}async function Ip(){let t=await K(),e=!1;for(let n of t.tracks||[]){let r=n.handoff,o=wx(n);if(!o)continue;e=!0;let s=!!r.toBox&&r.toBox===r.fromBox;if(s&&o.step==="error"){let c=await et(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(),f=Wc(l),d=f[f.length-1],p=d.agent,h=d.sessionId??null;d.endedAt=u,r.reason&&(d.endReason=r.reason);let w=c.agent==="claude"&&!!c.sessionId;f.push({agent:r.toAgent,sessionId:c.sessionId||null,pinned:w,startedAt:u,endedAt:null}),l.agent=r.toAgent,l.sessionId=c.sessionId||null,l.pinned=w,l.state="live",n.pendingHandoffHydrate={artifact:Dr,at:u},pt(n,"lead-handoff",{from:r.fromBox,to:r.fromBox,fromAgent:p,toAgent:r.toAgent,fromSessionId:h,toSessionId:c.sessionId||null,epoch:f.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 G({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 G({flow:"lead-handoff",phase:"reconciled",trackId:n.id,outcome:o.step,recovered:o.recovered,fromBox:o.fromBox,toBox:o.toBox}).catch(()=>{}),i&&await Re(i).catch(()=>{}),a&&await Re(a).catch(()=>{})}return e&&await J(),e}async function qc(t,e,n=!0,r=null){let o=qo.get(t);if(o&&!o.finishedAt)throw new Error("a lead handoff is already running for this Track");let s=Z(await K(),t);if(!s)throw new Error(`track "${t}" not found`);Ta(t,"handoff");let a=await Sa(e,n),i=Tr(e);if(i){let u=new Error(`can't hand off to ${e} \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 et(s.leadBox);if(!c)throw new Error(`lead box "${s.leadBox}" is not running`);let l={trackId:t,step:"checkpoint",fromBox:s.leadBox,toAgent:e,skipPermissions:n,reason:Z0(r),toBox:s.leadBox,startedAt:Date.now(),finishedAt:null,error:null};return qo.set(t,l),await Mc(t,{step:l.step,fromBox:l.fromBox,toAgent:e,toBox:l.toBox,skipPermissions:n,startedAt:l.startedAt,finishedAt:null,error:null}),cN(l,s,c,a,e).catch(async u=>{l.error=u?.message||String(u),l.finishedAt=Date.now(),console.error(`[lead-handoff ${t}] FAILED at step "${l.step}": ${l.error}`),await Mc(t,{step:l.step,error:l.error,finishedAt:l.finishedAt}).catch(()=>{}),G({flow:"lead-handoff",phase:"failed",trackId:t,step:l.step,error:l.error,fromBox:l.fromBox,toAgent:l.toAgent,toBox:l.toBox}).catch(()=>{})}),G({flow:"lead-handoff",phase:"started",trackId:t,fromBox:l.fromBox,toAgent:e,cwd:c.cwd}).catch(()=>{}),l}async function cN(t,e,n,r,o){let s=async(O,z={})=>{t.step=O,console.log(`[lead-handoff ${t.trackId}] step \u2192 ${O}`),await Mc(t.trackId,{step:O,toBox:t.toBox}),await G({flow:"lead-handoff",phase:O,trackId:t.trackId,fromBox:t.fromBox,toBox:t.toBox,toAgent:o,sessionName:z.sessionName,...z})};console.log(`[lead-handoff ${t.trackId}] ${t.fromBox}: ${n.agent} \u2192 ${o} IN PLACE`);let a=await K(),i=Z(a,t.trackId)?.boxes.find(O=>O.name===t.fromBox)||null,c=i?.agent||n.agent,l=i?.sessionId??n.sessionId??null,u=i?.pinned===!0;if(await s("checkpoint",{sessionName:t.fromBox}),t.checkpoint="llm",Tr(c))t.checkpoint="skipped-capped";else try{await Gu(t.fromBox,{timeoutMs:Y0})}catch(O){t.checkpoint="reconstructed",await G({flow:"lead-handoff",phase:"checkpoint-fallback",trackId:t.trackId,fromBox:t.fromBox,error:O?.message||String(O)}).catch(()=>{})}t.checkpoint!=="llm"&&(t.statusArtifact=await Vu(t.trackId,n.cwd,{trackName:e.name||e.id}).catch(()=>null),await s("checkpoint-degraded",{sessionName:t.fromBox,checkpoint:t.checkpoint,statusArtifact:t.statusArtifact})),await s("swap",{cwd:n.cwd,agentCmd:r});let d=await Qu(t.fromBox,{agentCmd:r,agent:o});await s("hydrate",{sessionName:t.fromBox}),await In({cwd:n.cwd,sessionId:d.sessionId,sessionName:t.fromBox,agent:o,agentCmd:xa(o)});let p=await Tt(t.fromBox,{lines:Nt}).catch(()=>"");if(!Ii(o,p)){await s("rollback",{sessionName:t.fromBox,fromAgent:c});let O=ip(c,l,{skipPermissions:t.skipPermissions});await Qu(t.fromBox,{agentCmd:O,agent:c,resumeSessionId:l,pinned:u});let z=await K(),C=Z(z,t.trackId);if(C){let N=C.boxes.find(T=>T.name===t.fromBox);N&&(N.state="live"),pt(C,"lead-handoff-failed",{box:t.fromBox,fromAgent:c,toAgent:o,reason:t.reason,error:`incoming ${o} CLI never drew its composer`,rolledBack:!0,handoffStartedAt:t.startedAt}),await J()}throw new Error(`incoming ${o} CLI never drew its composer \u2014 rolled back to ${c} (--resume, context intact)`)}await s("commit");let h=await K(),w=Z(h,t.trackId);if(!w)throw new Error(`track "${t.trackId}" not found during handoff commit \u2014 was it deleted or archived mid-flight?`);let y=w.boxes.find(O=>O.name===t.fromBox);if(!y)throw new Error(`lead box row "${t.fromBox}" missing during handoff commit`);let k=Date.now(),x=Wc(y),E=x[x.length-1];E.endedAt=k,t.reason&&(E.endReason=t.reason),x.push({agent:o,sessionId:d.sessionId,pinned:d.pinned,startedAt:k,endedAt:null}),y.agent=o,y.sessionId=d.sessionId,y.pinned=d.pinned,y.state="live",y.role="lead",w.pendingHandoffHydrate={artifact:t.statusArtifact||Dr,at:k},pt(w,"lead-handoff",{from:t.fromBox,to:t.fromBox,fromAgent:c,toAgent:o,fromSessionId:l,toSessionId:d.sessionId,epoch:x.length-1,singleBox:!0,forced:d.forced||void 0,skipPermissions:t.skipPermissions,reason:t.reason,handoffStartedAt:t.startedAt,checkpoint:t.checkpoint}),await J(),await s("done",{sessionName:t.fromBox}),await Mc(t.trackId,{finishedAt:Date.now(),error:null}),t.finishedAt=Date.now()}async function $p(t){let e=ap.get(t);if(e&&!e.finishedAt)throw new Error("a transfer is already running for this Track");let n=await K(),r=Z(n,t);if(!r)throw new Error(`track "${t}" 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=qo.get(t);if(o&&!o.finishedAt)throw new Error("a lead handoff is running \u2014 retry when it settles");for(let a of se.values())if(a.trackId===t&&!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:t,step:"checkpoint",startedAt:Date.now(),finishedAt:null,error:null};return ap.set(t,s),lN(s,r).catch(a=>{s.error=a?.message||String(a),s.finishedAt=Date.now(),console.error(`[transfer-out ${t}] FAILED at step "${s.step}": ${s.error}`)}),s}async function lN(t,e){let n=e.boxes.find(u=>u.name===e.leadBox)||null,r=n?await et(n.name).catch(()=>null):null;if(t.checkpoint="llm",!r||n&&Tr(n.agent))t.checkpoint=r?"skipped-capped":"skipped-dead";else try{await Gu(e.leadBox,{timeoutMs:Y0})}catch{t.checkpoint="reconstructed"}t.checkpoint!=="llm"&&await Vu(e.id,e.cwd,{trackName:e.name||e.id}).catch(()=>null),t.step="push";let o=e.workspace?.branch??null,s=[];if(o)for(let u of ae(e.workspace)){if(!u?.dir)continue;let f={name:u.name??null,repo:u.repo??null,baseSha:null,pushed:!1};try{await dn(u.dir,["push","origin",o],sp);let{stdout:d}=await dn(u.dir,["rev-parse","HEAD"]);f.baseSha=d.trim(),f.pushed=!0}catch(d){f.error=String(d?.message||d).split(`
189
+ `)[0]}s.push(f)}t.step="wip";let a=await Kf({id:e.id,cwd:e.cwd}),i=await K(),c=Z(i,e.id),l=c?.boxes.find(u=>u.name===c.leadBox)||null;l&&Wc(l),await J(),t.result={name:c?.name??e.name,agent:l?.agent??null,leadBox:c?.leadBox??e.leadBox,createdAt:c?.createdAt??null,branch:o,repos:s.filter(u=>u.pushed).map(({name:u,repo:f,baseSha:d})=>({name:u,repo:f,baseSha:d})),unpushed:s.filter(u=>!u.pushed).map(({name:u,repo:f,error:d})=>({name:u,repo:f,error:d})),wip:a.pushed?{ref:a.ref,sha:a.sha}:null,checkpoint:t.checkpoint,epochs:l?.epochs??[],codeless:!o||!s.some(u=>u.pushed)},t.step="ready",t.finishedAt=Date.now()}async function Kc(t,{toNode:e,mode:n="transfer"}={}){if(!e||typeof e!="string")throw new Error("toNode required");let r=await K(),o=Z(r,t);if(!o)throw new Error(`track "${t}" not found`);if(o.transferredTo)return{ok:!0,alreadyTransferred:o.transferredTo};hp(t),await Sp(t,o,n==="recover"?"track recovered onto another node":"track transferred to another node");for(let a of o.boxes)Gn.has(a.state)||(a.state="stopped");let s=await Gf({id:o.id,cwd:o.cwd});return o.transferredTo=e,o.transferredAt=Date.now(),pt(o,"transferred-out",{toNode:e,mode:n,box:o.leadBox,...s.pushed?{rescueRef:s.ref,rescueSha:s.sha}:{}}),await J(),{ok:!0,toNode:e,rescue:s.pushed?{ref:s.ref,sha:s.sha}:null}}async function Op(t){let e=[];for(let n of Array.isArray(t)?t:[])if(!(!n?.id||!n?.toNode))try{let r=await Kc(n.id,{toNode:n.toNode,mode:n.mode==="recover"?"recover":"transfer"});e.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 e}async function K0(t,e,n){try{await Ki(t,e,n)}catch{await dn(t,["worktree","prune"]).catch(()=>{}),await Ki(t,e,n)}return e}async function Cp(t={}){let{trackId:e,name:n,agent:r="claude",skipPermissions:o=!0,mode:s="transfer"}=t;if(!e||typeof e!="string"||!/^[0-9a-f]{8}$/.test(e))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(ep.has(e))throw new Error("an adopt is already running for this Track");ep.set(e,{startedAt:Date.now()});try{return await uN({...t,trackId:e,name:n,agent:r,skipPermissions:o,mode:s})}finally{ep.delete(e)}}async function uN({trackId:t,name:e,agent:n,skipPermissions:r,mode:o,fromNode:s=null,toNode:a=null,branch:i=null,repos:c=[],wip:l=null,brief:u=null,epochs:f=[],createdAt:d=null,leadBox:p=null,reason:h=null}){let w=await Sa(n,r),y=await K(),k=Z(y,t);if(k&&!k.transferredTo)throw new Error(`track "${t}" is already hosted on this node`);k&&(await Gf({id:k.id,cwd:k.cwd}).catch(()=>{}),await fx(k),y.tracks.splice(y.tracks.indexOf(k),1),await J()),await H.mkdir(da,{recursive:!0});let x=W.join(da,t);await H.rm(x,{recursive:!0,force:!0}).catch(()=>{});let E=null,O=!1,z=[];try{let C=[];if(i)for(let g of Array.isArray(c)?c:[]){let m=typeof g=="string"?g:g?.repo;if(!m||!/^[^/\s]+\/[^/\s]+$/.test(m))continue;let v=await Gr(m)??await oi(m);await dn(v,["fetch","origin",`+refs/heads/${i}:refs/heads/${i}`],sp),C.push({slug:m,base:v,name:typeof g=="object"?g?.name??null:null})}if(i&&C.length===1){let{base:g,slug:m}=C[0];await K0(g,x,i),z.push({base:g,dir:x}),await wa(x);let v=await xo(g);E={dir:x,base:g,branch:i,kind:"worktree",baseRef:v,repo:m}}else if(i&&C.length>=2){await H.mkdir(x,{recursive:!0});let g=new Set([".bostrat"]),m=[];for(let v of C){let $=v.name||W.basename(v.base);g.has($)&&($=v.slug.replace("/","-"));for(let mt=2;g.has($);mt++)$=`${W.basename(v.base)}-${mt}`;g.add($);let it=W.join(x,$);await K0(v.base,it,i),z.push({base:v.base,dir:it});let ct=await xo(v.base);m.push({name:$,dir:it,base:v.base,baseRef:ct,repo:v.slug})}await Aa(x,m,i),E={dir:x,kind:"multi",branch:i,repos:m}}else O=!0,await H.mkdir(x,{recursive:!0}),await Td(x),await wa(x),E={dir:x,base:null,branch:null,kind:"repo"};let N=!1,T=null;if(l?.sha&&E.kind==="worktree")try{await dn(x,["fetch","origin",l.ref||qf(t)],sp);let{stdout:g}=await dn(x,["rev-parse","FETCH_HEAD^"]),{stdout:m}=await dn(x,["rev-parse","HEAD"]);g.trim()===m.trim()?(await dn(x,["read-tree","--reset","-u","FETCH_HEAD"]),await dn(x,["reset","-q"]),N=!0):T="snapshot does not parent the fetched branch head"}catch(g){T=String(g?.message||g).split(`
190
+ `)[0]}else l?.sha&&(T="wip snapshots cover single-repo worktrees only");await F0({id:t,cwd:x}).catch(()=>({restored:!1}));let D=W.join(x,Dr),j=null;(await fi(x)).restored?j="checkpoint":typeof u=="string"&&u.trim()&&(await H.mkdir(W.dirname(D),{recursive:!0}),await H.writeFile(D,u),j="brief");let rt=new Set(y.tracks.flatMap(g=>(g.boxes||[]).map(m=>m.name))),A=null;p&&!rt.has(p)&&!await et(p).catch(()=>null)?A=p:(A=`${e.trim()} lead`,rt.has(bi(A))&&(A=`${e.trim().slice(0,50).trim()} ${t} lead`));let B=await An(A,x,{agentCmd:w,agent:n});Es({cwd:B.cwd,sessionName:B.name,agent:n,agentCmd:w});let X=Date.now(),yt=_p(B,"lead","live"),dt=(Array.isArray(f)?f:[]).filter(g=>g&&typeof g=="object").map(g=>({...g})),bt=dt[dt.length-1];bt&&bt.endedAt==null&&(bt.endedAt=X,bt.endReason==null&&(bt.endReason=o==="recover"?"node-offline":"node-transfer")),dt.push({agent:n,sessionId:B.sessionId??null,pinned:B.pinned===!0,startedAt:X,endedAt:null}),yt.epochs=dt;let kt={id:t,name:e.trim(),cwd:B.cwd,workspace:E,leadBox:B.name,boxes:[yt],events:[],createdAt:Number.isFinite(d)?d:X,...j?{pendingHandoffHydrate:{artifact:Dr,at:X}}:{}};return pt(kt,"transferred-in",{box:B.name,agent:n,fromNode:s,toNode:a,mode:o,reason:h,branch:E.branch??null,wip:N,epoch:dt.length-1,name:kt.name,cwd:kt.cwd,workspace:{base:E.base??null,branch:E.branch??null,kind:E.kind,...E.baseRef?{baseRef:E.baseRef}:{},...E.repo?{repo:E.repo}:{},...E.repos?{repos:E.repos.map(({name:g,base:m,baseRef:v,repo:$})=>({name:g,base:m,baseRef:v,repo:$}))}:{}}}),y.tracks.push(kt),await J(),{...await Fe(kt),adopt:{wipApplied:N,wipSkipped:T,codeless:O,artifactSource:j}}}catch(C){for(let N of z)await re(N.base,N.dir).catch(()=>{});throw await H.rm(x,{recursive:!0,force:!0}).catch(()=>{}),C}}async function gx(t,e,n){let r=await K(),o=Z(r,t);o&&(o.subtasks=o.subtasks||{},o.subtasks[e]={...o.subtasks[e]||{},...n},await J())}async function Lo(t,e){t.step=e,await Ea(t)}function yx(t,e=Date.now()){if(!t||t.finishedAt)return null;let n=t.step;return["snapshot","spawn","working"].includes(n)?{...t,step:"error",finishedAt:e,error:`interrupted by an agent restart during "${n}"; no changes were applied to the lead \u2014 retry the delegation`,recovered:"rolled-back"}:{...t,step:"error",finishedAt:e,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 ${t.branch}`,recovered:"partial-merge"}}function bx(t){return!!t&&!t.finishedAt&&!t.canceled&&t.step==="working"&&!!t.box&&!!t.dir&&!!t.base&&!!t.branch}async function mN(t,e,n){if(!bx(n)||se.has(e)||!await et(n.box).catch(()=>null))return!1;try{await H.access(n.dir)}catch{return!1}let o=await et(t.leadBox).catch(()=>null);if(!o?.cwd)return!1;let s={...n,id:e,leadBox:t.leadBox,step:"working",canceled:!1,forceMerge:!1};return se.set(e,s),xx(s,o).catch(a=>kx(s,a)),!0}async function Mp(){let t=await K(),e=!1;for(let n of t.tracks||[]){for(let[r,o]of Object.entries(n.subtasks||{})){if(se.has(r))continue;if(await mN(n,r,o)){e=!0,pt(n,"subtask-resumed",{box:o.box,agent:o.agent,task:o.task,subtaskId:r,resumedStep:o.step}),await G({flow:"subtask",phase:"resumed",trackId:n.id,subtaskId:r,box:o.box,branch:o.branch}).catch(()=>{});continue}let s=o.step,a=yx(o);if(!a)continue;e=!0,n.subtasks[r]=a;let i=n.boxes.find(c=>c.subtaskId===r);i&&!Gn.has(i.state)&&(i.state="canceled"),pt(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 G({flow:"subtask",phase:"reconciled",trackId:n.id,subtaskId:r,outcome:a.step,recovered:a.recovered,box:o.box,branch:o.branch}).catch(()=>{}),await G0(n,o.box,o.dir)}for(let r of n.boxes){if(r.role!=="subtask"||Gn.has(r.state)||se.has(r.subtaskId)||n.subtasks?.[r.subtaskId])continue;e=!0,r.state="canceled";let o=r.subtaskId?W.join(Ko,`${n.id}-${r.subtaskId}`):null;await G({flow:"subtask",phase:"reaped-legacy-orphan",trackId:n.id,subtaskId:r.subtaskId,box:r.name}).catch(()=>{}),await G0(n,r.name,o)}}return e=await hN(t)||e,e&&await J(),e}async function G0(t,e,n){if(e&&await Re(e).catch(()=>{}),!n)return;if(t.workspace?.kind==="multi"){for(let o of ae(t.workspace)){let s=W.join(n,o.name);await re(o.base,s).then(()=>!0,()=>!1)||await re(o.dir,s).catch(()=>{})}await H.rm(n,{recursive:!0,force:!0}).catch(()=>{});return}let r=await et(t.leadBox).catch(()=>null);r?.cwd&&await re(r.cwd,n).catch(()=>{})}async function hN(t){let e;try{e=await H.readdir(Ko)}catch{return!1}let n=new Set;for(let o of t.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 se.values())o.dir&&n.add(W.basename(o.dir));let r=!1;for(let o of e){if(n.has(o))continue;let s=W.join(Ko,o),a=(t.tracks||[]).find(i=>o.startsWith(`${i.id}-`));if(a?.workspace?.kind==="multi"){for(let i of ae(a.workspace))await re(i.base,W.join(s,i.name)).catch(()=>{});await H.rm(s,{recursive:!0,force:!0}).catch(()=>{})}else{let i=a?await et(a.leadBox).catch(()=>null):null;i?.cwd?await re(i.cwd,s).catch(()=>{}):await H.rm(s,{recursive:!0,force:!0}).catch(()=>{})}await G({flow:"subtask",phase:"swept-orphan-worktree",dir:s}).catch(()=>{}),r=!0}return r}async function Pp(t,{agent:e,task:n,skipPermissions:r=!0,reason:o=null}={}){if(typeof n!="string"||!yo(n))throw new Error("task (string) required");let s=await Sa(e,r),a=Tr(e);if(a){let p=new Error(`can't delegate to ${e} \u2014 its ${a.window} spend limit is reached ($${a.spentUsd.toFixed(2)} of $${a.limitUsd.toFixed(2)})`);throw p.usageCap=a,p}let i=Z(await K(),t);if(!i)throw new Error(`track "${t}" not found`);let c=await et(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 p=ae(i.workspace);if(!p.length)throw new Error("this multi-repo Track has no tagged repos to delegate into");for(let h of p)if(!h?.dir||!await qi(h.dir))throw new Error(`tagged checkout "${h?.name??"?"}" is missing from the lead workspace (${h?.dir??"no dir"})`);u=p.map(h=>({name:h.name,leadDir:h.dir,base:null}))}else if(!await qi(c.cwd))throw new Error(`subtask delegation needs the lead's workspace to be a git repo (got ${c.cwd})`);let f=ba().slice(0,8),d={id:f,trackId:t,trackName:i.name,agent:e,task:yo(n),skipPermissions:r,reason:Z0(o),step:"snapshot",leadBox:i.leadBox,box:null,branch:`bostrat/${Np(i.name)}-${f}`,base:null,repos:u,dir:W.join(Ko,`${t}-${f}`),stat:null,conflicts:[],applied:null,startedAt:Date.now(),finishedAt:null,error:null,canceled:!1,forceMerge:!1};return se.set(f,d),await Ea(d),wN(d,c,s).catch(p=>kx(d,p)),d}async function kx(t,e){t.failedStep=t.step,t.error=e instanceof ya?"canceled":e?.message||String(e),t.step=e instanceof ya?"canceled":"error",t.finishedAt=Date.now(),await Bp(t).catch(()=>{}),await Ea(t).catch(()=>{}),await kN(t).catch(()=>{})}function Vc(t){let e=se.get(t);if(!e)throw new Error(`subtask "${t}" not found`);if(e.finishedAt)throw new Error("subtask already finished");return e.canceled=!0,e}function Dp(t){let e=se.get(t);if(!e)throw new Error(`subtask "${t}" not found`);if(e.finishedAt)throw new Error("subtask already finished");if(e.step!=="working")throw new Error(`subtask is not waiting to merge (step: ${e.step})`);return e.forceMerge=!0,e}async function wN(t,e,n){if(await Lo(t,"snapshot"),t.repos){for(let s of t.repos)s.base=await bo(s.leadDir,`bostrat: snapshot for subtask ${t.id}`);await Ea(t)}else t.base=await bo(e.cwd,`bostrat: snapshot for subtask ${t.id}`);if(await Lo(t,"spawn"),await H.mkdir(Ko,{recursive:!0}),t.repos){await H.mkdir(t.dir,{recursive:!0});for(let a of t.repos)await ko(a.leadDir,W.join(t.dir,a.name),t.branch,a.base);let s=ae((Z(await K(),t.trackId)||{}).workspace);await Aa(t.dir,t.repos.map(a=>{let i=s.find(c=>c?.name===a.name);return{name:a.name,repo:i?.repo??null,baseRef:null}}),t.branch)}else await ko(e.cwd,t.dir,t.branch,t.base),await wa(t.dir);await gN(t,e);let r=t.trackName.slice(0,38).trim(),o=await An(`${r} ${t.agent} sub ${t.id}`,t.dir,{agentCmd:n,agent:t.agent});t.box=o.name,await yN(t,o),await Q0(t.trackId,o.name,bM(t.task,!!t.repos),{kind:"subtask"}),await xx(t,e)}async function xx(t,e){await Lo(t,"working");let n=W.join(t.dir,Cc);if(await SN(n,t),t.canceled)throw new ya;if(await Lo(t,"merge"),t.repos){let s={files:0,insertions:0,deletions:0},a=[],i=[],c=!0;for(let l of t.repos){let u=W.join(t.dir,l.name);await xd(u,`bostrat: subtask ${t.id} result (auto-committed)`),l.stat=await Ed(l.leadDir,l.base,t.branch,jo),l.files=await _d(l.leadDir,l.base,t.branch,jo);let f=await Id(l.leadDir,l.base,t.branch,jo);l.applied=f.applied,l.conflicts=f.conflicts??[],s.files+=l.stat.files,s.insertions+=l.stat.insertions,s.deletions+=l.stat.deletions,a.push(...l.files.map(d=>W.join(l.name,d))),i.push(...l.conflicts.map(d=>d.startsWith("patch did not apply cleanly")?`${l.name}: ${d}`:W.join(l.name,d))),f.applied||(c=!1)}t.stat=s,t.files=a,t.conflicts=i,t.applied=c}else{await xd(t.dir,`bostrat: subtask ${t.id} result (auto-committed)`),t.stat=await Ed(e.cwd,t.base,t.branch,jo),t.files=await _d(e.cwd,t.base,t.branch,jo);let s=await Id(e.cwd,t.base,t.branch,jo);t.applied=s.applied,t.conflicts=s.conflicts}await Ea(t);let r=await xN(t,e,n);await Lo(t,"resume"),await Q0(t.trackId,t.leadBox,kM(t.task,t.stat,t.conflicts,r),{kind:"subtask-resume"}),await Lo(t,"reap"),await Bp(t),t.step="done";let o=Date.now();await gx(t.trackId,t.id,{...Gc(t),finishedAt:o}),await bN(t,o),t.finishedAt=o}async function gN(t,e){let n=W.join(t.dir,W.dirname(fa));await H.mkdir(n,{recursive:!0});let r="";try{r=await Qh(e.cwd,e.sessionId)}catch{}if(!r)try{r=await H.readFile(W.join(e.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 ${t.id}
185
191
 
186
192
  **Delegated task:** ${t.task}
187
193
 
@@ -192,15 +198,15 @@ ${a}`}async function Rc(t){if(t.archivedAt)return!1;let e=t.boxes.find(o=>o.name
192
198
  ## Conversation so far (lead \u2192 you)
193
199
 
194
200
  ${r}
195
- `;await U.writeFile(H.join(t.dir,na),o)}async function CM(t,e){let n=await q(),r=Q(n,t.trackId);r&&(r.boxes.push({name:e.name,agent:e.agent,role:"subtask",state:"live",cwd:e.cwd,sessionId:e.sessionId,hookTokenHash:Yo(e.hookToken),createdAt:Date.now(),subtaskId:t.id,branch:t.branch,task:t.task}),pt(r,"subtask-delegated",{to:e.name,toAgent:t.agent,task:t.task,subtaskId:t.id,skipPermissions:t.skipPermissions,reason:t.reason}),r.subtasks=r.subtasks||{},r.subtasks[t.id]={...r.subtasks[t.id]||{},...Cc(t)},await Y())}async function MM(t,e=t.finishedAt){let n=await q(),r=Q(n,t.trackId);if(!r)return;let o=r.boxes.find(s=>s.subtaskId===t.id);o&&(o.state=t.conflicts.length?"conflict":"merged",o.stat=t.stat),pt(r,"subtask-merged",{from:t.box,fromAgent:t.agent,task:t.task,subtaskId:t.id,stat:t.stat,conflicts:t.conflicts.length,files:t.files,durationMs:e?e-t.startedAt:null}),await Y()}async function PM(t){let e=await q(),n=Q(e,t.trackId);if(!n)return;let r=t.canceled||t.error==="canceled",o=n.boxes.find(s=>s.subtaskId===t.id);o&&(o.state=r?"canceled":"failed"),pt(n,r?"subtask-canceled":"subtask-failed",{from:t.box,fromAgent:t.agent,task:t.task,subtaskId:t.id,failedStep:t.failedStep||t.step,error:t.error,durationMs:t.finishedAt?t.finishedAt-t.startedAt:null}),n.subtasks=n.subtasks||{},n.subtasks[t.id]={...n.subtasks[t.id]||{},...Cc(t)},await Y()}async function NM(t,e,n){let r=`.bostrat/handoff/subtask-${t.id}.md`;try{let o=H.join(e.cwd,r);await U.mkdir(H.dirname(o),{recursive:!0}),await U.copyFile(n,o)}catch{}return r}async function fp(t){if(t.box&&await _e(t.box).catch(()=>{}),t.repos&&t.dir){for(let e of t.repos)await ae(e.leadDir,H.join(t.dir,e.name)).catch(()=>{});await U.rm(t.dir,{recursive:!0,force:!0}).catch(()=>{})}else if(t.dir){let n=(await tt(t.leadBox).catch(()=>null))?.cwd;n&&await ae(n,t.dir).catch(()=>{})}}async function BM(t,e){let n=(e.startedAt||Date.now())+AM;for(;;){if(e.canceled||e.forceMerge)return;try{await U.access(t);return}catch{}if(Date.now()>n)throw new Error("subtask timed out without signaling completion (no result digest written)");await Un(EM)}}function Un(t){return new Promise(e=>setTimeout(e,t))}var RC,ln,k0,$C,Df,OC,kc,ua,Fn,fa,CC,MC,yc,na,PC,NC,ue,Of,Q,Cf,pt,Mf,DC,Ir,w0,FC,UC,HC,WC,GC,ra,g0,zC,JC,YC,XC,ZC,$o,oa,nM,oM,sM,iM,Pf,lM,N0,sa,B0,pM,ea,Nf,mM,Bf,bM,aa,kM,xM,y0,H0,ia,No,AM,EM,Po,Io,de,_M,$r,Cc,ha,lp,ca,xr=M(()=>{Ht();Du();mg();hi();gn();eu();yg();Qt();We();Zo();li();Ng();Qr();od();ad();Zg();Su();ui();Cu();we();wd();Qn();gs();Bi();_y();vd();_b();Pu();_u();Rb();Ud();ct();sc();Xi();ho();pf();Ao();vf();gc();$f();Bn();h0();RC=IC(_C),ln=process.env.BOSTRAT_STATE_DIR||H.join(process.env.HOME||"/tmp",".bostrat"),k0=H.join(ln,"tracks.json"),$C=H.join(ln,"events.jsonl"),Df=H.join(ln,"workspaces"),OC=process.env.BOSTRAT_DEFAULT_REPO||null,kc={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"}},ua=Object.keys(kc);Fn={at:0,value:null};fa=".bostrat/handoff/latest.md",CC=Number(process.env.BOSTRAT_HANDOFF_CHECKPOINT_TIMEOUT_MS)||9e4;MC=/\(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\.\)$/;yc=".bostrat/handoff/subtask-result.md",na=".bostrat/handoff/lead-context.md",PC=(t,e=!1)=>e?`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 ${na} \u2014 read that first for context. Your scoped task:
201
+ `;await H.writeFile(W.join(t.dir,fa),o)}async function yN(t,e){let n=await K(),r=Z(n,t.trackId);r&&(r.boxes.push({name:e.name,agent:e.agent,role:"subtask",state:"live",cwd:e.cwd,sessionId:e.sessionId,hookTokenHash:as(e.hookToken),createdAt:Date.now(),subtaskId:t.id,branch:t.branch,task:t.task}),pt(r,"subtask-delegated",{to:e.name,toAgent:t.agent,task:t.task,subtaskId:t.id,skipPermissions:t.skipPermissions,reason:t.reason}),r.subtasks=r.subtasks||{},r.subtasks[t.id]={...r.subtasks[t.id]||{},...Gc(t)},await J())}async function bN(t,e=t.finishedAt){let n=await K(),r=Z(n,t.trackId);if(!r)return;let o=r.boxes.find(s=>s.subtaskId===t.id);o&&(o.state=t.conflicts.length?"conflict":"merged",o.stat=t.stat),pt(r,"subtask-merged",{from:t.box,fromAgent:t.agent,task:t.task,subtaskId:t.id,stat:t.stat,conflicts:t.conflicts.length,files:t.files,durationMs:e?e-t.startedAt:null}),await J()}async function kN(t){let e=await K(),n=Z(e,t.trackId);if(!n)return;let r=t.canceled||t.error==="canceled",o=n.boxes.find(s=>s.subtaskId===t.id);o&&(o.state=r?"canceled":"failed"),pt(n,r?"subtask-canceled":"subtask-failed",{from:t.box,fromAgent:t.agent,task:t.task,subtaskId:t.id,failedStep:t.failedStep||t.step,error:t.error,durationMs:t.finishedAt?t.finishedAt-t.startedAt:null}),n.subtasks=n.subtasks||{},n.subtasks[t.id]={...n.subtasks[t.id]||{},...Gc(t)},await J()}async function xN(t,e,n){let r=`.bostrat/handoff/subtask-${t.id}.md`;try{let o=W.join(e.cwd,r);await H.mkdir(W.dirname(o),{recursive:!0}),await H.copyFile(n,o)}catch{}return r}async function Bp(t){if(t.box&&await Re(t.box).catch(()=>{}),t.repos&&t.dir){for(let e of t.repos)await re(e.leadDir,W.join(t.dir,e.name)).catch(()=>{});await H.rm(t.dir,{recursive:!0,force:!0}).catch(()=>{})}else if(t.dir){let n=(await et(t.leadBox).catch(()=>null))?.cwd;n&&await re(n,t.dir).catch(()=>{})}}async function SN(t,e){let n=(e.startedAt||Date.now())+dN;for(;;){if(e.canceled||e.forceMerge)return;try{await H.access(t);return}catch{}if(Date.now()>n)throw new Error("subtask timed out without signaling completion (no result digest written)");await Vn(fN)}}function Vn(t){return new Promise(e=>setTimeout(e,t))}var V0,fn,z0,wM,da,gM,Nc,ka,Kn,Dr,Y0,yM,Cc,fa,bM,kM,pe,Jf,Z,Yf,pt,Xf,SM,Gn,H0,AM,EM,_M,IM,OM,pa,W0,MM,NM,PM,DM,BM,Fo,ma,UM,WM,qM,GM,Zf,zM,lx,ha,ux,ZM,ua,Qf,QM,tp,rN,ga,oN,sN,q0,_p,qo,Go,sp,dn,ap,Rp,ep,dN,fN,Ko,jo,se,pN,jr,Gc,Ea,Np,ya,Rr=M(()=>{qt();Ju();Dg();Ri();kn();du();Fg();Jt();Ke();cs();Ti();ry();lo();wd();yd();ky();Cu();Ai();Hu();ye();Rd();ar();_s();Ji();Vy();Dd();Vb();qu();Bu();Jb();tf();at();yc();uc();Ao();Ef();Po();Df();$c();Wf();Fn();P0();Vf();U0();pi();V0=hM(mM),fn=process.env.BOSTRAT_STATE_DIR||W.join(process.env.HOME||"/tmp",".bostrat"),z0=W.join(fn,"tracks.json"),wM=W.join(fn,"events.jsonl"),da=W.join(fn,"workspaces"),gM=process.env.BOSTRAT_DEFAULT_REPO||null,Nc={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"}},ka=Object.keys(Nc);Kn={at:0,value:null};Dr=".bostrat/handoff/latest.md",Y0=Number(process.env.BOSTRAT_HANDOFF_CHECKPOINT_TIMEOUT_MS)||9e4;yM=/\(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\.\)$/;Cc=".bostrat/handoff/subtask-result.md",fa=".bostrat/handoff/lead-context.md",bM=(t,e=!1)=>e?`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 ${fa} \u2014 read that first for context. Your scoped task:
196
202
 
197
203
  ${t}
198
204
 
199
- 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 ${yc} (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 ${na} \u2014 read that first for context. Your scoped task:
205
+ 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 ${Cc} (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 ${fa} \u2014 read that first for context. Your scoped task:
200
206
 
201
207
  ${t}
202
208
 
203
- 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 ${yc} 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.`,NC=(t,e,n,r)=>`A subtask box you delegated has finished: "${t}". Its changes are now merged into your working tree (${e.files} file${e.files===1?"":"s"}, +${e.insertions} \u2212${e.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."),ue=null,Of=null;Q=(t,e)=>t.tracks.find(n=>n.id===e)||null,Cf=Promise.resolve();pt=(t,e,n={})=>{let r={at:Date.now(),type:e,...n};return t.events.push(r),BC(t.id,r),$y(t,r),r};Mh(async({sessionName:t,from:e,to:n,version:r,status:o,error:s})=>{let i=(await q()).tracks.find(c=>c.leadBox===t||(c.boxes||[]).some(l=>l.name===t));i&&(pt(i,"codex-update",{box:t,from:e,to:r||n,status:o,...s?{error:s}:{}}),await Y().catch(()=>{}))});Mf=(t,e,n)=>e!=null&&n.some(r=>t===r.box&&e>=r.from&&e<=r.to),DC=new Set(["stuck","wrong-approach","too-slow","want-different-model","context-refresh","cost","parallelize","other"]);Ir=new Set(["merged","conflict","canceled","failed","handed-off"]),w0=new Map;FC=5e3;UC={claude:[/^\[Request interrupted by user(?: for tool use)?\]$/i],codex:[/^\[?Request interrupted/i,/^Conversation interrupted/i],cursor:[/^\[?Request interrupted/i]};HC=[/^\/model(?:\s|$)/i,/<command-(?:name|message|args)>[^<]*\bmodel\b/i,/^Model changed to\b/i];WC=10*6e4;GC=1500,ra=new Map;g0="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.";zC=4e3,JC=3,YC=[300,350,400],XC=1e3,ZC=12,$o=new Map,oa=new Map;nM=[250,400,500,600];oM=3e4,sM=[350,650,900];iM=[250,450,700],Pf=2;lM=12e4;N0=t=>({branch:t.branch,kind:t.kind,repos:(t.repos??[]).filter(Boolean).map(({name:e,base:n,baseRef:r,repo:o})=>({name:e,base:n,baseRef:r,repo:o}))});sa="# bostrat workspace",B0=`${sa}
209
+ 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 ${Cc} 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.`,kM=(t,e,n,r)=>`A subtask box you delegated has finished: "${t}". Its changes are now merged into your working tree (${e.files} file${e.files===1?"":"s"}, +${e.insertions} \u2212${e.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."),pe=null,Jf=null;Z=(t,e)=>t.tracks.find(n=>n.id===e)||null,Yf=Promise.resolve();pt=(t,e,n={})=>{let r={at:Date.now(),type:e,...n};return t.events.push(r),xM(t.id,r),Yy(t,r),r};rw(async({sessionName:t,from:e,to:n,version:r,status:o,error:s})=>{let i=(await K()).tracks.find(c=>c.leadBox===t||(c.boxes||[]).some(l=>l.name===t));i&&(pt(i,"codex-update",{box:t,from:e,to:r||n,status:o,...s?{error:s}:{}}),await J().catch(()=>{}))});Xf=(t,e,n)=>e!=null&&n.some(r=>t===r.box&&e>=r.from&&e<=r.to),SM=new Set(["stuck","wrong-approach","too-slow","want-different-model","context-refresh","cost","parallelize","other"]);Gn=new Set(["merged","conflict","canceled","failed","handed-off"]),H0=new Map;AM=5e3;EM={claude:[/^\[Request interrupted by user(?: for tool use)?\]$/i],codex:[/^\[?Request interrupted/i,/^Conversation interrupted/i],cursor:[/^\[?Request interrupted/i]};_M=[/^\/model(?:\s|$)/i,/<command-(?:name|message|args)>[^<]*\bmodel\b/i,/^Model changed to\b/i];IM=10*6e4;OM=1500,pa=new Map;W0="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.";MM=4e3,NM=3,PM=[300,350,400],DM=1e3,BM=12,Fo=new Map,ma=new Map;UM=[250,400,500,600];WM=3e4,qM=[350,650,900];GM=[250,450,700],Zf=2;zM=12e4;lx=t=>({branch:t.branch,kind:t.kind,repos:(t.repos??[]).filter(Boolean).map(({name:e,base:n,baseRef:r,repo:o})=>({name:e,base:n,baseRef:r,repo:o}))});ha="# bostrat workspace",ux=`${ha}
204
210
 
205
211
  TRACK MEMORY: if \`.bostrat/memory/MEMORY.md\` exists in your workspace, read it
206
212
  before substantive work \u2014 it is the shared cross-provider memory for this repo
@@ -390,9 +396,31 @@ When asked about scheduled or routine jobs ("loops"), check \`bostrat-loop ls\`
390
396
  it lists every Loop for this owner across ALL nodes (\`bostrat-loop show
391
397
  <name-or-id>\` prints one loop's prompt, schedule and recent runs; a loop's run
392
398
  Track is named "\u21BB <loop name>"). Loops are operator-managed from the Loops tab:
393
- you can read them but never create, edit, fire, or delete one \u2014 describe any
394
- proposed change in chat instead. Never claim a loop does or doesn't exist from
395
- Track names or memory alone; \`bostrat-loop ls\` is the authority.
399
+ you can read them but never edit, fire, or delete one \u2014 describe any proposed
400
+ change in chat instead. Never claim a loop does or doesn't exist from Track
401
+ names or memory alone; \`bostrat-loop ls\` is the authority.
402
+
403
+ When the operator asks you to SET UP a recurring job ("check X every morning",
404
+ "make this a nightly job"), do NOT hand-write instructions or a cron entry \u2014
405
+ write the loop as JSON and run:
406
+
407
+ bostrat-loop propose <plan.json>
408
+
409
+ Plan shape: \`{ "name", "schedule": "0 7 * * *" (5-field crontab, UTC),
410
+ "prompt", "expectation"?, "notify"?: off|transition|nag, "assignment"?:
411
+ {"provider": "claude"|"codex"|"cursor"} }\` (the \`bostrat-loop\` header documents
412
+ the details). The repo comes from THIS Track and the owner from the operator's
413
+ session \u2014 a plan cannot aim a loop at another repo, node, or user. This posts a
414
+ one-tap review card showing your prompt VERBATIM; NOTHING is scheduled until
415
+ they confirm, and the loop is then created by Bostrat under their account, not
416
+ by you. Write the prompt as the full standing instructions for an unattended
417
+ run \u2014 it is what future runs execute, with no one there to clarify it \u2014 and end
418
+ it by telling the run to report its outcome (\`bostrat-loop report \u2026\`, below).
419
+ Proposing is a BLOCKING prompt: once the CLI reports the card was posted, STOP
420
+ and end your turn \u2014 do not start or resume other work until the operator's
421
+ decision comes back to you as a chat message. Propose only when the operator has
422
+ asked for a recurring job; never volunteer one as a bonus, and never propose a
423
+ second loop to "fix" one they already have (describe that change in chat).
396
424
 
397
425
  If THIS Track is a loop's run Track (its name starts with "\u21BB"), you MUST end
398
426
  every run by reporting its outcome: \`bostrat-loop report ok\` when it went as
@@ -430,69 +458,68 @@ which steps to run (and which to skip). An offer buried mid-message, phrased as
430
458
  statement, or omitted entirely renders no controls \u2014 so close EVERY completed
431
459
  implementation turn this way, every time. When the operator has already asked you
432
460
  to commit / push / open the PR, just do it; do not re-offer.
433
- `,pM=B0,ea=B0+Iw;Nf=t=>typeof t=="string"&&(t===sa||t.startsWith(`${sa}
434
- `)),mM="# bostrat multi-repo workspace";Bf=ea.replace(`${sa}
435
- `,`${sa}
461
+ `,ZM=ux,ua=ux+Zw;Qf=t=>typeof t=="string"&&(t===ha||t.startsWith(`${ha}
462
+ `)),QM="# bostrat multi-repo workspace";tp=ua.replace(`${ha}
463
+ `,`${ha}
436
464
 
437
465
  (Global copy managed by bostrat \u2014 rewritten on service start; edits will be lost.)
438
466
  SCOPE: these instructions apply ONLY when your working directory is under
439
467
  ~/.bostrat/workspaces/ or ~/.bostrat/worktrees/ \u2014 a bostrat-orchestrated box.
440
468
  When working anywhere else, ignore everything below.
441
- `);bM=new Set(["claude","codex","cursor"]);aa=new Set,kM=t=>aa.has(t);xM=9e4;y0={merged:"merged",closed:"closed on GitHub WITHOUT merging",lost:"no longer found on GitHub (deleted, or its repo left the grant)"};H0=(t,e,n)=>({name:t.name,agent:t.agent,role:e,state:n,cwd:t.cwd,sessionId:t.sessionId,pinned:t.pinned===!0,hookTokenHash:Yo(t.hookToken),createdAt:Date.now()});ia=new Map,No=t=>ia.get(t)||(ue?Q(ue,t)?.handoff:null)||null;AM=Number(process.env.BOSTRAT_SUBTASK_TIMEOUT_MS)||18e5,EM=Number(process.env.BOSTRAT_SUBTASK_POLL_MS)||3e3,Po=H.join(ln,"worktrees"),Io=[na,yc],de=new Map,_M=t=>de.get(t)||(ue?ue.tracks.map(e=>e.subtasks?.[t]).find(Boolean):null)||null,$r=t=>{let e=new Map([...de.values()].filter(r=>r.trackId===t).map(r=>[r.id,r])),n=ue?Q(ue,t):null;if(n?.subtasks)for(let[r,o]of Object.entries(n.subtasks))e.has(r)||e.set(r,o);return[...e.values()].sort((r,o)=>r.startedAt-o.startedAt)},Cc=t=>({id:t.id,trackId:t.trackId,trackName:t.trackName,agent:t.agent,task:t.task,skipPermissions:t.skipPermissions,reason:t.reason||null,step:t.step,failedStep:t.failedStep||null,box:t.box,branch:t.branch,base:t.base,repos:t.repos||null,dir:t.dir,stat:t.stat,files:t.files||null,conflicts:t.conflicts||[],applied:t.applied,error:t.error,canceled:t.canceled,startedAt:t.startedAt,finishedAt:t.finishedAt});ha=t=>q0(t.trackId,t.id,Cc(t));lp=t=>t.trim().replace(/\s+/g,"-").replace(/[^A-Za-z0-9._-]/g,"").toLowerCase()||"track",ca=class extends Error{}});Ht();import ut from"node:path";import Ft from"node:fs";import k1 from"node:readline";import{fileURLToPath as x1}from"node:url";import ve from"express";import S1 from"node:http";import v1 from"node:https";import ym from"node:os";import{WebSocketServer as T1}from"ws";Ht();import $A from"node-pty";async function Sh(t,e,n={}){if(!bt(e)){ci(t,`invalid session name: ${e}`),t.close(1008,"invalid session name");return}if(!await xn()){ci(t,`host tmux server not running on ${te}`),t.close(1011,"tmux server unavailable");return}if(!await tt(e)){ci(t,`session "${e}" not found`),t.close(1008,"session not found");return}let r=xh(n.cols,120,vh),o=xh(n.rows,32,Th),s;try{s=$A.spawn(B,["-S",te,"attach-session","-d","-t",e],{name:"xterm-256color",cols:r,rows:o,cwd:process.env.HOME||"/",env:{...process.env,TERM:"xterm-256color"}})}catch(a){ci(t,`failed to spawn tmux attach: ${a.message}`),t.close(1011,"spawn failed");return}s.onData(a=>{t.readyState===t.OPEN&&Vl(t,{type:"data",data:a})}),s.onExit(({exitCode:a,signal:i})=>{t.readyState===t.OPEN&&(Vl(t,{type:"exit",code:a??null,signal:i??null}),t.close(1e3,"tmux exited"))}),t.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"&&PA(i.cols,i.rows))try{s.resize(Math.min(500,i.cols|0),Math.min(500,i.rows|0))}catch{}}}),t.on("close",()=>{try{s.kill()}catch{}MA(e)})}var OA=6,CA=250;async function MA(t,e=OA,n=CA){for(let r=0;r<e;r++){if(await sr(t).catch(()=>!0))return!0;await new Promise(o=>setTimeout(o,n))}return!1}var vh=20,Th=6;function PA(t,e){return Number.isFinite(Number(t))&&Number.isFinite(Number(e))&&Number(t)>=vh&&Number(e)>=Th}function xh(t,e,n){let r=Number(t);return!Number.isFinite(r)||r<n?e:Math.min(500,r|0)}function Vl(t,e){try{t.send(JSON.stringify(e))}catch{}}function ci(t,e){Vl(t,{type:"error",message:e})}function Ah(t){let e=typeof t=="string"&&t?t:"/",n=e.indexOf("?"),r=n===-1?e:e.slice(0,n),o=n===-1?"":e.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}}we();li();Du();xr();var DM=t=>!!t&&!t.finishedAt&&!t.canceled&&!t.error;function Y0({tracks:t=[],views:e=[],queuedOf:n=()=>[]}={}){let r=[];for(let o of t)!o||o.archivedAt&&!o.archiving||(o.working&&r.push(`working:${o.id}`),o.prompted&&r.push(`prompted:${o.id}`),(n(o.id)??[]).length&&r.push(`queued:${o.id}`),(o.boxes||[]).some(s=>s?.role==="subtask"&&s?.state==="live")&&r.push(`subtask:${o.id}`),Object.values(o.subtasks||{}).some(DM)&&r.push(`merge-back:${o.id}`));return e.some(o=>o?.state==="live"||o?.state==="starting")&&r.push("views"),{busy:r.length>0,reasons:r}}ct();Qt();var jM=(...t)=>fetch(...t);function LM(t=process.env){return!!(vt(t)&&t.BOSTRAT_PLANE_TOKEN)}async function pp(t=process.env){if(!LM(t))throw new Error("no plane configured \u2014 circuits live on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let e=new AbortController,n=setTimeout(()=>e.abort(),1e4);try{let r=await jM(`${vt(t)}/v1/circuits`,{headers:{authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN}`},signal:e.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 Bo(t,e=process.env){let n=String(t??"").trim();if(!n)throw new Error("a circuit name or id is required");let r=await pp(e),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 Pc(t,e,{source:n="chat"}={}){return I(t,{type:"track.circuit.tagged",actor:"orchestrator",source:"orchestrator",payload:e?{circuitId:e.id,circuitName:e.name??null,source:n}:{circuitId:null,source:n}})}ct();Qt();var FM=(...t)=>fetch(...t);async function Nc(t,e,n,r=process.env){if(!(vt(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 FM(`${vt(r)}${e}`,{method:t,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 UM(t,e=process.env){return Nc("POST","/v1/circuits",{name:t},e).then(n=>n.circuit)}async function X0({circuitRef:t,newCircuitName:e,name:n,markdown:r},o=process.env){let s=e?await UM(e,o):await Bo(t,o),a=await Nc("POST","/v1/blueprints",{circuitId:s.id,name:n,markdown:r},o);return{circuit:s,...a}}async function mp(t,e=process.env){let n=await Bo(t,e),r=await Nc("GET",`/v1/blueprints/${encodeURIComponent(n.id)}`,null,e);return{circuit:n,...r}}async function hp(t,e=process.env){return(await Nc("GET","/v1/circuits",null,e)).memberships?.[t]??null}async function Z0(t,e,n,r=process.env){let{blueprint:o,items:s}=await mp(e,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 I(t,{type:"blueprint.item.bound",actor:"orchestrator",source:"orchestrator",payload:{itemIds:n,blueprintId:o.id,source:"cli"}}),{blueprint:o,itemIds:n}}$f();ct();import xa from"node:fs/promises";import qc from"node:path";import OP from"node:os";gn();import HM from"node:fs/promises";import Q0 from"node:path";import WM from"node:os";var tx=()=>Q0.join(process.env.BOSTRAT_STATE_DIR||Q0.join(process.env.HOME||WM.tmpdir(),".bostrat"),"integrations.json");async function dn(){try{return JSON.parse(await HM.readFile(tx(),"utf8"))||{}}catch{return{}}}var Bc=["linked","prOpened","prMerged","create"],wp=["prompt","auto","off"],qM={create:["prompt","off"]},ex=t=>qM[t]??wp;function Dc(t){let e=t.linear||{},n=e.transitions===!0?"auto":"prompt",r={};for(let o of Bc){let s=ex(o),a=s.includes(n)?n:"prompt",i=t.ticketFlow?.[o]??e.ticketFlow?.[o];r[o]=s.includes(i)?i:a}return r}async function Or(){let t=await dn(),e=process.env.BOSTRAT_LINEAR_API_KEY||t.linear?.apiKey,n=process.env.BOSTRAT_LINEAR_DEFAULT_TEAM||t.linear?.defaultTeam||null;return e?{apiKey:e,ticketFlow:Dc(t),defaultTeam:n}:null}async function jc(){let t=await dn(),e=t.jira||{},n=process.env.BOSTRAT_JIRA_BASE_URL||e.baseUrl,r=process.env.BOSTRAT_JIRA_EMAIL||e.email,o=process.env.BOSTRAT_JIRA_API_TOKEN||e.apiToken;return!n||!r||!o?null:{baseUrl:String(n).replace(/\/$/,""),email:r,apiToken:o,tokenExpiresAt:e.tokenExpiresAt??null,ticketFlow:Dc(t)}}async function gp(){return Dc(await dn())}async function nx(t){let e=Object.entries(t||{});if(!e.length)throw new Error(`nothing to set \u2014 phases: ${Bc.join(", ")}`);for(let[r,o]of e){if(!Bc.includes(r))throw new Error(`unknown phase "${r}" \u2014 configurable phases: ${Bc.join(", ")}`);let s=ex(r);if(!s.includes(o))throw new Error(s.length<wp.length?`mode "${o}" not allowed for "${r}" \u2014 ${r} is always confirmed (modes: ${s.join(", ")})`:`unknown mode "${o}" \u2014 modes: ${wp.join(", ")}`)}let n=await dn();return n.ticketFlow={...Dc(n),...Object.fromEntries(e)},n.linear&&(delete n.linear.ticketFlow,delete n.linear.transitions),await zt(tx(),n,{mode:384}),n.ticketFlow}async function wa(){let t=(await dn()).deepgram||{},e=process.env.DEEPGRAM_API_KEY||t.apiKey;return e?{apiKey:e}:null}async function KM(){let t=(await dn()).openai||{},e=process.env.BOSTRAT_OPENAI_API_KEY||t.apiKey;return e?{apiKey:e}:null}var GM={openai:{model:"gpt-realtime-2.1-mini",voice:"marin"}};async function Lc(){let e=(await dn()).voiceChat||{},n=e.provider||"openai",r=GM[n];if(!r)return null;let o=n==="openai"?await KM():null;return o?{provider:n,model:e.model||r.model,voice:e.voice||r.voice,apiKey:o.apiKey}:null}async function rx(){let t=(await dn()).cedar||{},e=process.env.BOSTRAT_CEDAR_INGEST_KEY||t.ingestKey,n=process.env.BOSTRAT_CEDAR_URL||t.url||"https://cedar-api.fly.dev";return e?{url:n,ingestKey:e}:null}async function Cr(){let t=(await dn()).slack||{},e=process.env.BOSTRAT_SLACK_BOT_TOKEN||t.botToken,n=process.env.BOSTRAT_SLACK_APP_TOKEN||t.appToken;return!e||!n?null:{botToken:e,appToken:n,channel:process.env.BOSTRAT_SLACK_CHANNEL||t.channel||null,maxConcurrent:Number.isInteger(t.maxConcurrent)&&t.maxConcurrent>0?t.maxConcurrent:2}}ct();bn();ur();Ao();import ya from"node:fs/promises";import fx from"node:path";import gP from"node:os";import{randomUUID as px}from"node:crypto";var bp={};gl(bp,{createComment:()=>eP,findIssueUrl:()=>YM,issueStates:()=>oP,mdToAdf:()=>ax,moveIssue:()=>sP,parseIssueRef:()=>JM,resolveIssue:()=>XM,uploadImage:()=>nP,upsertCard:()=>ZM,whoami:()=>yp});var Do=t=>String(t.baseUrl||"").replace(/\/$/,""),sx=t=>`Basic ${Buffer.from(`${t.email}:${t.apiToken}`).toString("base64")}`;async function Mr(t,e,n,r){let o=await fetch(`${Do(t)}${n}`,{method:e,headers:{authorization:sx(t),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 VM=/\/browse\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,zM=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function JM(t){let e=String(t||"").trim();if(/^https?:\/\//i.test(e)){let r=e.match(VM);return r?r[1].toUpperCase():null}let n=e.match(zM);return n?n[1]:null}function YM(t,e=null){let n=null;try{n=e?.baseUrl?new URL(e.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(t||"").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 XM(t,e){let n;try{n=await Mr(t,"GET",`/rest/api/3/issue/${encodeURIComponent(e)}?fields=summary,status`)}catch(r){throw r.status===404?new Error(`jira: issue "${e}" not found`):r}return{issueId:n.id,key:n.key,title:n.fields?.summary??null,url:`${Do(t)}/browse/${n.key}`,state:n.fields?.status?.name??null}}async function ZM(t,e,{url:n,title:r,subtitle:o}){await Mr(t,"POST",`/rest/api/3/issue/${encodeURIComponent(e.key)}/remotelink`,{globalId:n,application:{type:"com.bostrat.tracks",name:"Bostrat"},object:{url:n,title:r,summary:o,icon:{title:"Bostrat"}}})}var QM=/(!\[[^\]]*\]\([^)\s]+\)|\*\*[^*\n]+\*\*|`[^`\n]+`|_[^_\n]+_|https?:\/\/[^\s)]+)/g;function tP(t){let e=[],n=0;for(let r of t.matchAll(QM)){r.index>n&&e.push({type:"text",text:t.slice(n,r.index)});let o=r[0];if(o.startsWith("![")){let[,s,a]=o.match(/^!\[([^\]]*)\]\(([^)\s]+)\)$/);e.push({type:"text",text:s||a,marks:[{type:"link",attrs:{href:a}}]})}else o.startsWith("**")?e.push({type:"text",text:o.slice(2,-2),marks:[{type:"strong"}]}):o.startsWith("`")?e.push({type:"text",text:o.slice(1,-1),marks:[{type:"code"}]}):o.startsWith("_")?e.push({type:"text",text:o.slice(1,-1),marks:[{type:"em"}]}):e.push({type:"text",text:o,marks:[{type:"link",attrs:{href:o}}]});n=r.index+o.length}return n<t.length&&e.push({type:"text",text:t.slice(n)}),e}function ax(t){let e=String(t??"").split(/\n{2,}/).map(n=>n.trim()).filter(Boolean).map(n=>{let r=[];return n.split(`
442
- `).forEach((o,s)=>{s>0&&r.push({type:"hardBreak"}),r.push(...tP(o))}),{type:"paragraph",content:r.length?r:[{type:"text",text:" "}]}});return{type:"doc",version:1,content:e.length?e:[{type:"paragraph",content:[{type:"text",text:" "}]}]}}async function eP(t,e,n){let r=await Mr(t,"POST",`/rest/api/3/issue/${encodeURIComponent(e.key)}/comment`,{body:ax(n)});return r?.id?`${Do(t)}/browse/${e.key}?focusedCommentId=${r.id}`:null}async function yp(t){let e=await Mr(t,"GET","/rest/api/3/myself"),n=null;try{n=new URL(Do(t)).host}catch{n=t.baseUrl??null}return{user:e?.displayName??e?.emailAddress??null,org:n}}async function nP(t,{issue:e,filename:n,contentType:r,buffer:o}){let s=new FormData;s.append("file",new Blob([o],{type:r}),n);let a=await fetch(`${Do(t)}/rest/api/3/issue/${encodeURIComponent(e)}/attachments`,{method:"POST",headers:{authorization:sx(t),"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??`${Do(t)}/rest/api/3/attachment/content/${c.id}`}var rP={new:"unstarted",indeterminate:"started",done:"completed"},ox=t=>rP[t?.key]??"started";async function oP(t,e){let n=encodeURIComponent(e.key),[r,o]=await Promise.all([Mr(t,"GET",`/rest/api/3/issue/${n}?fields=status`),Mr(t,"GET",`/rest/api/3/issue/${n}/transitions`)]),s=r?.fields?.status??null,a=s?{id:`status:${s.id}`,name:s.name,type:ox(s.statusCategory)}:null,i=(o?.transitions??[]).map((c,l)=>({id:c.id,name:c.to?.name??c.name,type:ox(c.to?.statusCategory),position:l}));return{current:a,states:i}}async function sP(t,e,n){await Mr(t,"POST",`/rest/api/3/issue/${encodeURIComponent(e.key)}/transitions`,{transition:{id:String(n)}})}var vp={};gl(vp,{createComment:()=>pP,createIssue:()=>Sp,createProject:()=>xp,findIssueUrl:()=>uP,issueStates:()=>hP,moveIssue:()=>wP,parseIssueRef:()=>lP,resolveIssue:()=>dP,teams:()=>jo,uploadImage:()=>mP,upsertCard:()=>fP,whoami:()=>kp});var aP=()=>process.env.BOSTRAT_LINEAR_API_URL||"https://api.linear.app/graphql";async function Le(t,e,n={}){let r=await fetch(aP(),{method:"POST",headers:{"content-type":"application/json",authorization:t.apiKey},body:JSON.stringify({query:e,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 iP=/linear\.app\/[^/\s]+\/issue\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,cP=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function lP(t){let e=String(t||"").trim(),n=e.match(iP);if(n)return n[1].toUpperCase();let r=e.match(cP);return r?r[1]:null}function uP(t){let e=String(t||"").match(/https?:\/\/linear\.app\/[^/\s]+\/issue\/[A-Za-z][A-Za-z0-9]{0,9}-\d+[^\s)]*/);return e?e[0]:null}async function dP(t,e){let r=(await Le(t,"query($id: String!) { issue(id: $id) { id identifier title url state { name } team { key } } }",{id:e})).issue;if(!r)throw new Error(`linear: issue "${e}" 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 fP(t,e,{url:n,title:r,subtitle:o}){let s=await Le(t,"mutation($input: AttachmentCreateInput!) { attachmentCreate(input: $input) { success attachment { id } } }",{input:{issueId:e.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 pP(t,e,n){let r=await Le(t,"mutation($input: CommentCreateInput!) { commentCreate(input: $input) { success comment { url } } }",{input:{issueId:e.issueId,body:n}});if(!r.commentCreate?.success)throw new Error("linear: commentCreate did not succeed");return r.commentCreate.comment?.url??null}async function kp(t){let e=await Le(t,"query { viewer { name email } organization { name urlKey } }");return{user:e.viewer?.name??e.viewer?.email??null,org:e.organization?.name??e.organization?.urlKey??null}}async function mP(t,{filename:e,contentType:n,buffer:r}){let o=await Le(t,`mutation($contentType: String!, $filename: String!, $size: Int!) {
469
+ `);rN=new Set(["claude","codex","cursor"]);ga=new Set,oN=t=>ga.has(t);sN=9e4;q0={merged:"merged",closed:"closed on GitHub WITHOUT merging",lost:"no longer found on GitHub (deleted, or its repo left the grant)"};_p=(t,e,n)=>({name:t.name,agent:t.agent,role:e,state:n,cwd:t.cwd,sessionId:t.sessionId,pinned:t.pinned===!0,hookTokenHash:as(t.hookToken),createdAt:Date.now()});qo=new Map,Go=t=>qo.get(t)||(pe?Z(pe,t)?.handoff:null)||null;sp=6e4,dn=(t,e,n=15e3)=>V0("git",["-C",t,...e],{timeout:n,maxBuffer:8*1024*1024}),ap=new Map,Rp=t=>ap.get(t)||null;ep=new Map;dN=Number(process.env.BOSTRAT_SUBTASK_TIMEOUT_MS)||18e5,fN=Number(process.env.BOSTRAT_SUBTASK_POLL_MS)||3e3,Ko=W.join(fn,"worktrees"),jo=[fa,Cc],se=new Map,pN=t=>se.get(t)||(pe?pe.tracks.map(e=>e.subtasks?.[t]).find(Boolean):null)||null,jr=t=>{let e=new Map([...se.values()].filter(r=>r.trackId===t).map(r=>[r.id,r])),n=pe?Z(pe,t):null;if(n?.subtasks)for(let[r,o]of Object.entries(n.subtasks))e.has(r)||e.set(r,o);return[...e.values()].sort((r,o)=>r.startedAt-o.startedAt)},Gc=t=>({id:t.id,trackId:t.trackId,trackName:t.trackName,agent:t.agent,task:t.task,skipPermissions:t.skipPermissions,reason:t.reason||null,step:t.step,failedStep:t.failedStep||null,box:t.box,branch:t.branch,base:t.base,repos:t.repos||null,dir:t.dir,stat:t.stat,files:t.files||null,conflicts:t.conflicts||[],applied:t.applied,error:t.error,canceled:t.canceled,startedAt:t.startedAt,finishedAt:t.finishedAt});Ea=t=>gx(t.trackId,t.id,Gc(t));Np=t=>t.trim().replace(/\s+/g,"-").replace(/[^A-Za-z0-9._-]/g,"").toLowerCase()||"track",ya=class extends Error{}});qt();import ut from"node:path";import Ut from"node:fs";import rj from"node:readline";import{fileURLToPath as oj}from"node:url";import he from"express";import sj from"node:http";import aj from"node:https";import Wm from"node:os";import{WebSocketServer as ij}from"ws";qt();import sE from"node-pty";async function Gh(t,e,n={}){if(!At(e)){vi(t,`invalid session name: ${e}`),t.close(1008,"invalid session name");return}if(!await Tn()){vi(t,`host tmux server not running on ${ne}`),t.close(1011,"tmux server unavailable");return}if(!await et(e)){vi(t,`session "${e}" not found`),t.close(1008,"session not found");return}let r=Kh(n.cols,120,Vh),o=Kh(n.rows,32,zh),s;try{s=sE.spawn(L,["-S",ne,"attach-session","-d","-t",e],{name:"xterm-256color",cols:r,rows:o,cwd:process.env.HOME||"/",env:{...process.env,TERM:"xterm-256color"}})}catch(a){vi(t,`failed to spawn tmux attach: ${a.message}`),t.close(1011,"spawn failed");return}s.onData(a=>{t.readyState===t.OPEN&&ru(t,{type:"data",data:a})}),s.onExit(({exitCode:a,signal:i})=>{t.readyState===t.OPEN&&(ru(t,{type:"exit",code:a??null,signal:i??null}),t.close(1e3,"tmux exited"))}),t.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"&&lE(i.cols,i.rows))try{s.resize(Math.min(500,i.cols|0),Math.min(500,i.rows|0))}catch{}}}),t.on("close",()=>{try{s.kill()}catch{}cE(e)})}var aE=6,iE=250;async function cE(t,e=aE,n=iE){for(let r=0;r<e;r++){if(await dr(t).catch(()=>!0))return!0;await new Promise(o=>setTimeout(o,n))}return!1}var Vh=20,zh=6;function lE(t,e){return Number.isFinite(Number(t))&&Number.isFinite(Number(e))&&Number(t)>=Vh&&Number(e)>=zh}function Kh(t,e,n){let r=Number(t);return!Number.isFinite(r)||r<n?e:Math.min(500,r|0)}function ru(t,e){try{t.send(JSON.stringify(e))}catch{}}function vi(t,e){ru(t,{type:"error",message:e})}function Jh(t){let e=typeof t=="string"&&t?t:"/",n=e.indexOf("?"),r=n===-1?e:e.slice(0,n),o=n===-1?"":e.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}}ye();Ti();Ju();Rr();var vN=t=>!!t&&!t.finishedAt&&!t.canceled&&!t.error;function vx({tracks:t=[],views:e=[],queuedOf:n=()=>[]}={}){let r=[];for(let o of t)!o||o.archivedAt&&!o.archiving||o.transferredTo||(o.working&&r.push(`working:${o.id}`),o.prompted&&r.push(`prompted:${o.id}`),(n(o.id)??[]).length&&r.push(`queued:${o.id}`),(o.boxes||[]).some(s=>s?.role==="subtask"&&s?.state==="live")&&r.push(`subtask:${o.id}`),Object.values(o.subtasks||{}).some(vN)&&r.push(`merge-back:${o.id}`));return e.some(o=>o?.state==="live"||o?.state==="starting")&&r.push("views"),{busy:r.length>0,reasons:r}}at();Jt();var TN=(...t)=>fetch(...t);function AN(t=process.env){return!!(St(t)&&t.BOSTRAT_PLANE_TOKEN)}async function jp(t=process.env){if(!AN(t))throw new Error("no plane configured \u2014 circuits live on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let e=new AbortController,n=setTimeout(()=>e.abort(),1e4);try{let r=await TN(`${St(t)}/v1/circuits`,{headers:{authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN}`},signal:e.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 Vo(t,e=process.env){let n=String(t??"").trim();if(!n)throw new Error("a circuit name or id is required");let r=await jp(e),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 zc(t,e,{source:n="chat"}={}){return I(t,{type:"track.circuit.tagged",actor:"orchestrator",source:"orchestrator",payload:e?{circuitId:e.id,circuitName:e.name??null,source:n}:{circuitId:null,source:n}})}at();Jt();var EN=(...t)=>fetch(...t);async function Jc(t,e,n,r=process.env){if(!(St(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 EN(`${St(r)}${e}`,{method:t,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 _N(t,e=process.env){return Jc("POST","/v1/circuits",{name:t},e).then(n=>n.circuit)}async function Tx({circuitRef:t,newCircuitName:e,name:n,markdown:r},o=process.env){let s=e?await _N(e,o):await Vo(t,o),a=await Jc("POST","/v1/blueprints",{circuitId:s.id,name:n,markdown:r},o);return{circuit:s,...a}}async function Lp(t,e=process.env){let n=await Vo(t,e),r=await Jc("GET",`/v1/blueprints/${encodeURIComponent(n.id)}`,null,e);return{circuit:n,...r}}async function Fp(t,e=process.env){return(await Jc("GET","/v1/circuits",null,e)).memberships?.[t]??null}async function Ax(t,e,n,r=process.env){let{blueprint:o,items:s}=await Lp(e,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 I(t,{type:"blueprint.item.bound",actor:"orchestrator",source:"orchestrator",payload:{itemIds:n,blueprintId:o.id,source:"cli"}}),{blueprint:o,itemIds:n}}Wf();at();import Ca from"node:fs/promises";import ol from"node:path";import gP from"node:os";kn();import IN from"node:fs/promises";import Ex from"node:path";import RN from"node:os";var _x=()=>Ex.join(process.env.BOSTRAT_STATE_DIR||Ex.join(process.env.HOME||RN.tmpdir(),".bostrat"),"integrations.json");async function pn(){try{return JSON.parse(await IN.readFile(_x(),"utf8"))||{}}catch{return{}}}var Yc=["linked","prOpened","prMerged","create"],Up=["prompt","auto","off"],$N={create:["prompt","off"]},Ix=t=>$N[t]??Up;function Xc(t){let e=t.linear||{},n=e.transitions===!0?"auto":"prompt",r={};for(let o of Yc){let s=Ix(o),a=s.includes(n)?n:"prompt",i=t.ticketFlow?.[o]??e.ticketFlow?.[o];r[o]=s.includes(i)?i:a}return r}async function Lr(){let t=await pn(),e=process.env.BOSTRAT_LINEAR_API_KEY||t.linear?.apiKey,n=process.env.BOSTRAT_LINEAR_DEFAULT_TEAM||t.linear?.defaultTeam||null;return e?{apiKey:e,ticketFlow:Xc(t),defaultTeam:n}:null}async function Zc(){let t=await pn(),e=t.jira||{},n=process.env.BOSTRAT_JIRA_BASE_URL||e.baseUrl,r=process.env.BOSTRAT_JIRA_EMAIL||e.email,o=process.env.BOSTRAT_JIRA_API_TOKEN||e.apiToken;return!n||!r||!o?null:{baseUrl:String(n).replace(/\/$/,""),email:r,apiToken:o,tokenExpiresAt:e.tokenExpiresAt??null,ticketFlow:Xc(t)}}async function Hp(){return Xc(await pn())}async function Rx(t){let e=Object.entries(t||{});if(!e.length)throw new Error(`nothing to set \u2014 phases: ${Yc.join(", ")}`);for(let[r,o]of e){if(!Yc.includes(r))throw new Error(`unknown phase "${r}" \u2014 configurable phases: ${Yc.join(", ")}`);let s=Ix(r);if(!s.includes(o))throw new Error(s.length<Up.length?`mode "${o}" not allowed for "${r}" \u2014 ${r} is always confirmed (modes: ${s.join(", ")})`:`unknown mode "${o}" \u2014 modes: ${Up.join(", ")}`)}let n=await pn();return n.ticketFlow={...Xc(n),...Object.fromEntries(e)},n.linear&&(delete n.linear.ticketFlow,delete n.linear.transitions),await Yt(_x(),n,{mode:384}),n.ticketFlow}async function _a(){let t=(await pn()).deepgram||{},e=process.env.DEEPGRAM_API_KEY||t.apiKey;return e?{apiKey:e}:null}async function ON(){let t=(await pn()).openai||{},e=process.env.BOSTRAT_OPENAI_API_KEY||t.apiKey;return e?{apiKey:e}:null}var CN={openai:{model:"gpt-realtime-2.1-mini",voice:"marin"}};async function Qc(){let e=(await pn()).voiceChat||{},n=e.provider||"openai",r=CN[n];if(!r)return null;let o=n==="openai"?await ON():null;return o?{provider:n,model:e.model||r.model,voice:e.voice||r.voice,apiKey:o.apiKey}:null}async function $x(){let t=(await pn()).cedar||{},e=process.env.BOSTRAT_CEDAR_INGEST_KEY||t.ingestKey,n=process.env.BOSTRAT_CEDAR_URL||t.url||"https://cedar-api.fly.dev";return e?{url:n,ingestKey:e}:null}async function Fr(){let t=(await pn()).slack||{},e=process.env.BOSTRAT_SLACK_BOT_TOKEN||t.botToken,n=process.env.BOSTRAT_SLACK_APP_TOKEN||t.appToken;return!e||!n?null:{botToken:e,appToken:n,channel:process.env.BOSTRAT_SLACK_CHANNEL||t.channel||null,maxConcurrent:Number.isInteger(t.maxConcurrent)&&t.maxConcurrent>0?t.maxConcurrent:2}}at();Sn();wr();Po();import Ra from"node:fs/promises";import Lx from"node:path";import rP from"node:os";import{randomUUID as Fx}from"node:crypto";var qp={};$l(qp,{createComment:()=>UN,findIssueUrl:()=>DN,issueStates:()=>qN,mdToAdf:()=>Mx,moveIssue:()=>KN,parseIssueRef:()=>PN,resolveIssue:()=>BN,uploadImage:()=>HN,upsertCard:()=>jN,whoami:()=>Wp});var zo=t=>String(t.baseUrl||"").replace(/\/$/,""),Cx=t=>`Basic ${Buffer.from(`${t.email}:${t.apiToken}`).toString("base64")}`;async function Ur(t,e,n,r){let o=await fetch(`${zo(t)}${n}`,{method:e,headers:{authorization:Cx(t),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 MN=/\/browse\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,NN=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function PN(t){let e=String(t||"").trim();if(/^https?:\/\//i.test(e)){let r=e.match(MN);return r?r[1].toUpperCase():null}let n=e.match(NN);return n?n[1]:null}function DN(t,e=null){let n=null;try{n=e?.baseUrl?new URL(e.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(t||"").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 BN(t,e){let n;try{n=await Ur(t,"GET",`/rest/api/3/issue/${encodeURIComponent(e)}?fields=summary,status`)}catch(r){throw r.status===404?new Error(`jira: issue "${e}" not found`):r}return{issueId:n.id,key:n.key,title:n.fields?.summary??null,url:`${zo(t)}/browse/${n.key}`,state:n.fields?.status?.name??null}}async function jN(t,e,{url:n,title:r,subtitle:o}){await Ur(t,"POST",`/rest/api/3/issue/${encodeURIComponent(e.key)}/remotelink`,{globalId:n,application:{type:"com.bostrat.tracks",name:"Bostrat"},object:{url:n,title:r,summary:o,icon:{title:"Bostrat"}}})}var LN=/(!\[[^\]]*\]\([^)\s]+\)|\*\*[^*\n]+\*\*|`[^`\n]+`|_[^_\n]+_|https?:\/\/[^\s)]+)/g;function FN(t){let e=[],n=0;for(let r of t.matchAll(LN)){r.index>n&&e.push({type:"text",text:t.slice(n,r.index)});let o=r[0];if(o.startsWith("![")){let[,s,a]=o.match(/^!\[([^\]]*)\]\(([^)\s]+)\)$/);e.push({type:"text",text:s||a,marks:[{type:"link",attrs:{href:a}}]})}else o.startsWith("**")?e.push({type:"text",text:o.slice(2,-2),marks:[{type:"strong"}]}):o.startsWith("`")?e.push({type:"text",text:o.slice(1,-1),marks:[{type:"code"}]}):o.startsWith("_")?e.push({type:"text",text:o.slice(1,-1),marks:[{type:"em"}]}):e.push({type:"text",text:o,marks:[{type:"link",attrs:{href:o}}]});n=r.index+o.length}return n<t.length&&e.push({type:"text",text:t.slice(n)}),e}function Mx(t){let e=String(t??"").split(/\n{2,}/).map(n=>n.trim()).filter(Boolean).map(n=>{let r=[];return n.split(`
470
+ `).forEach((o,s)=>{s>0&&r.push({type:"hardBreak"}),r.push(...FN(o))}),{type:"paragraph",content:r.length?r:[{type:"text",text:" "}]}});return{type:"doc",version:1,content:e.length?e:[{type:"paragraph",content:[{type:"text",text:" "}]}]}}async function UN(t,e,n){let r=await Ur(t,"POST",`/rest/api/3/issue/${encodeURIComponent(e.key)}/comment`,{body:Mx(n)});return r?.id?`${zo(t)}/browse/${e.key}?focusedCommentId=${r.id}`:null}async function Wp(t){let e=await Ur(t,"GET","/rest/api/3/myself"),n=null;try{n=new URL(zo(t)).host}catch{n=t.baseUrl??null}return{user:e?.displayName??e?.emailAddress??null,org:n}}async function HN(t,{issue:e,filename:n,contentType:r,buffer:o}){let s=new FormData;s.append("file",new Blob([o],{type:r}),n);let a=await fetch(`${zo(t)}/rest/api/3/issue/${encodeURIComponent(e)}/attachments`,{method:"POST",headers:{authorization:Cx(t),"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??`${zo(t)}/rest/api/3/attachment/content/${c.id}`}var WN={new:"unstarted",indeterminate:"started",done:"completed"},Ox=t=>WN[t?.key]??"started";async function qN(t,e){let n=encodeURIComponent(e.key),[r,o]=await Promise.all([Ur(t,"GET",`/rest/api/3/issue/${n}?fields=status`),Ur(t,"GET",`/rest/api/3/issue/${n}/transitions`)]),s=r?.fields?.status??null,a=s?{id:`status:${s.id}`,name:s.name,type:Ox(s.statusCategory)}:null,i=(o?.transitions??[]).map((c,l)=>({id:c.id,name:c.to?.name??c.name,type:Ox(c.to?.statusCategory),position:l}));return{current:a,states:i}}async function KN(t,e,n){await Ur(t,"POST",`/rest/api/3/issue/${encodeURIComponent(e.key)}/transitions`,{transition:{id:String(n)}})}var zp={};$l(zp,{createComment:()=>QN,createIssue:()=>Vp,createProject:()=>Gp,findIssueUrl:()=>YN,issueStates:()=>eP,moveIssue:()=>nP,parseIssueRef:()=>JN,resolveIssue:()=>XN,teams:()=>Jo,uploadImage:()=>tP,upsertCard:()=>ZN,whoami:()=>Kp});var GN=()=>process.env.BOSTRAT_LINEAR_API_URL||"https://api.linear.app/graphql";async function Ue(t,e,n={}){let r=await fetch(GN(),{method:"POST",headers:{"content-type":"application/json",authorization:t.apiKey},body:JSON.stringify({query:e,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 VN=/linear\.app\/[^/\s]+\/issue\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,zN=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function JN(t){let e=String(t||"").trim(),n=e.match(VN);if(n)return n[1].toUpperCase();let r=e.match(zN);return r?r[1]:null}function YN(t){let e=String(t||"").match(/https?:\/\/linear\.app\/[^/\s]+\/issue\/[A-Za-z][A-Za-z0-9]{0,9}-\d+[^\s)]*/);return e?e[0]:null}async function XN(t,e){let r=(await Ue(t,"query($id: String!) { issue(id: $id) { id identifier title url state { name } team { key } } }",{id:e})).issue;if(!r)throw new Error(`linear: issue "${e}" 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 ZN(t,e,{url:n,title:r,subtitle:o}){let s=await Ue(t,"mutation($input: AttachmentCreateInput!) { attachmentCreate(input: $input) { success attachment { id } } }",{input:{issueId:e.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 QN(t,e,n){let r=await Ue(t,"mutation($input: CommentCreateInput!) { commentCreate(input: $input) { success comment { url } } }",{input:{issueId:e.issueId,body:n}});if(!r.commentCreate?.success)throw new Error("linear: commentCreate did not succeed");return r.commentCreate.comment?.url??null}async function Kp(t){let e=await Ue(t,"query { viewer { name email } organization { name urlKey } }");return{user:e.viewer?.name??e.viewer?.email??null,org:e.organization?.name??e.organization?.urlKey??null}}async function tP(t,{filename:e,contentType:n,buffer:r}){let o=await Ue(t,`mutation($contentType: String!, $filename: String!, $size: Int!) {
443
471
  fileUpload(contentType: $contentType, filename: $filename, size: $size) {
444
472
  success
445
473
  uploadFile { uploadUrl assetUrl headers { key value } }
446
474
  }
447
- }`,{contentType:n,filename:e,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 hP(t,e){let n=await Le(t,"query($id: String!) { issue(id: $id) { state { id name type } team { states { nodes { id name type position } } } } }",{id:e.key});if(!n.issue)throw new Error(`linear: issue "${e.key}" not found`);return{current:n.issue.state??null,states:n.issue.team?.states?.nodes??[]}}async function wP(t,e,n){if(!(await Le(t,"mutation($id: String!, $input: IssueUpdateInput!) { issueUpdate(id: $id, input: $input) { success } }",{id:e.issueId,input:{stateId:n}})).issueUpdate?.success)throw new Error("linear: issueUpdate did not succeed")}async function jo(t){return((await Le(t,"query { teams(first: 100) { nodes { id key name } } }")).teams?.nodes??[]).map(n=>({id:n.id,key:n.key,name:n.name}))}var ix=255;async function xp(t,{teamId:e,name:n,description:r}){let o=r||null,s=!!o&&o.length>ix,a=s?`${o.slice(0,ix-1).trimEnd()}\u2026`:o,i=await Le(t,"mutation($input: ProjectCreateInput!) { projectCreate(input: $input) { success project { id url name } } }",{input:{teamIds:[e],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 Sp(t,{teamId:e,title:n,description:r,projectId:o,priority:s}){let a=await Le(t,"mutation($input: IssueCreateInput!) { issueCreate(input: $input) { success issue { id identifier url title } } }",{input:{teamId:e,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}}var mx={linear:{api:vp,config:Or},jira:{api:bp,config:jc}};async function $p(){let t=[];for(let[e,{api:n,config:r}]of Object.entries(mx)){let o=await r();o&&t.push({name:e,api:n,cfg:o})}return t}async function Pr(t){let e=mx[t?.provider];if(!e)return null;let n=await e.config();return n?{name:t.provider,api:e.api,cfg:n}:null}function Op(t,e){if(!t||t.name)return t;let n=e.find(r=>r.id===t.id);return n?{...t,name:n.name}:t}var hx=()=>process.env.BOSTRAT_STATE_DIR||fx.join(process.env.HOME||gP.tmpdir(),".bostrat"),_p=()=>fx.join(hx(),"tickets.json"),wx=()=>(process.env.BOSTRAT_PUBLIC_URL||"http://bostrat.globopi").replace(/\/$/,""),Fc=t=>`${wx()}/track/${t}`,Hn=null,Tp=null,Ap=Promise.resolve();async function ka(){return Hn||(Tp??=ya.readFile(_p(),"utf8").then(t=>({tickets:JSON.parse(t)?.tickets??{},existed:!0})).catch(()=>({tickets:{},existed:!1})).then(async({tickets:t,existed:e})=>{if(Hn=t,!e&&wt()){let{records:n,source:r}=await $t("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;Hn[s]=i}Object.keys(Hn).length&&await Ip().catch(()=>{})}}return Hn}).finally(()=>Tp=null),Tp)}async function Ip(){let t=JSON.stringify({tickets:Hn},null,2),e=`${_p()}.${process.pid}.tmp`;await ya.mkdir(hx(),{recursive:!0}),await ya.writeFile(e,t),await ya.rename(e,_p())}async function Wn(t=null){if(Ap=Ap.then(Ip,Ip),await Ap.catch(()=>{}),!t)return;let e=Hn?.[t];e?Ut("tickets",{id:t,updatedAt:Date.now(),...e},{trackId:t}).catch(()=>{}):me("tickets",t).catch(()=>{})}async function Fe(t){return(await ka())[t]??null}async function gx(){return{...await ka()}}async function yx(){return(await $p()).length>0}async function Lo(t,e,{source:n="api"}={}){let r=await $p();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(e);if(d)try{s=await u.api.resolveIssue(u.cfg,d),o=u;break}catch(f){a=f}}if(!o)throw a||new Error(`"${e}" is not a Linear or Jira issue URL or key (ABC-123)`);let i=(t.boxes||[]).find(u=>u.name===t.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:t.name,branch:t.workspace?.branch??null,leadAgent:i?.agent??null,cwd:t.cwd??null,...t.workspace?.kind==="multi"?{repos:(t.workspace.repos??[]).map(u=>u?.name).filter(Boolean)}:{}},pr:null};(await ka())[t.id]=c,await Wn(t.id),await I({id:t.id,cwd:t.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 ba(t.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 ga(c,`**Bostrat** \u2014 Track **${c.track.name}** linked${l.length?` (${l.join(", ")})`:""}.`),await xx(t.id,c,"linked"),c}async function Cp(t){let e=await ka();return e[t]?(delete e[t],await Wn(t),!0):!1}var Rp=t=>`$${t>=100?Math.round(t):t.toFixed(2)}`;async function bx(t,e){if(!t.track?.cwd)return null;let n=Rn(await L({id:e,cwd:t.track.cwd}));return!n.totalUsd||n.totalUsd<.01?null:n}function yP(t){let e=Object.entries(t.byProvider).sort((r,o)=>o[1].usd-r[1].usd).map(([r,o])=>`${r} ${Rp(o.usd)}`).join(" \xB7 "),n=Object.keys(t.byBox).length;return`${Rp(t.totalUsd)}${e?` (${e})`:""}${n>1?` across ${n} boxes`:""}`}function bP(t,e){let n=[];return t.track.leadAgent&&n.push(`lead ${t.track.leadAgent}`),t.track.branch&&n.push(t.track.branch),t.track.repos?.length&&n.push(t.track.repos.join(" + ")),t.pr?.number&&n.push(`PR #${t.pr.number} ${t.pr.change==="merged"?"merged":"open"}`),e&&n.push(Rp(e.totalUsd)),n.join(" \xB7 ")||"linked"}async function ba(t,e){let n=await Pr(e);if(!n)return;let r=await bx(e,t).catch(()=>null);await n.api.upsertCard(n.cfg,e,{url:Fc(t),title:`Bostrat Track: ${e.track.name}`,subtitle:bP(e,r)})}function Uc(t){let e=new URL(wx());return`${e.protocol}//${t}.${e.host}/`}var kP={linked:"linked",opened:"prOpened",merged:"prMerged"};function xP(t,e,n){let r=o=>e.filter(s=>s.type===o).sort((s,a)=>s.position-a.position);if(n==="linked"){if(["triage","backlog","unstarted"].includes(t?.type))return r("started")[0]??null}else if(n==="opened"){if(t?.type!=="completed")return r("started").find(o=>/review/i.test(o.name))??null}else if(n==="merged"&&t?.type!=="completed")return r("completed")[0]??null;return null}async function kx(t,e,{from:n,to:r,mode:o,phase:s=null,actor:a="user"}){e.state=r,await Wn(t),await I({id:t,cwd:e.track?.cwd},{type:"ticket.state.changed",actor:a,source:"orchestrator",payload:{ts:Date.now(),key:e.key,url:e.url,from:n??null,to:r,mode:o,...s?{phase:s}:{}}}).catch(()=>{})}async function xx(t,e,n){let r=await Pr(e);if(!r)return;let o=r.cfg.ticketFlow?.[kP[n]]??"prompt";if(o==="off")return;let{current:s,states:a}=await r.api.issueStates(r.cfg,e),i=Op(s,a),c=xP(i,a,n);if(!c||c.id===i?.id)return;let l=i?.name??e.state??null;if(o==="auto"){await r.api.moveIssue(r.cfg,e,c.id),await kx(t,e,{from:l,to:c.name,mode:"auto",phase:n,actor:"system"});return}await I({id:t,cwd:e.track?.cwd},{type:"ticket.move.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),offerId:px(),provider:e.provider,key:e.key,url:e.url,phase:n,from:l,to:{id:c.id,name:c.name,type:c.type},...e.pr?.number?{prNumber:e.pr.number}:{}}}).catch(()=>{})}async function Sx(t){let e=await Fe(t);if(!e)throw new Error("no ticket linked to this Track");let n=await Pr(e);if(!n)throw new Error("no ticketing integration configured");let{current:r,states:o}=await n.api.issueStates(n.cfg,e),s=Op(r,o);return s?.name&&e.state!==s.name&&(e.state=s.name,await Wn(t)),{key:e.key,url:e.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 Mp(t,e,{mode:n="manual"}={}){if(!e)throw new Error("stateId required");let r=await Fe(t);if(!r)throw new Error("no ticket linked to this Track");let o=await Pr(r);if(!o)throw new Error("no ticketing integration configured");let{current:s,states:a}=await o.api.issueStates(o.cfg,r),i=Op(s,a),c=a.find(u=>u.id===e);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 Wn(t)),{key:r.key,from:l,to:c.name,moved:!1}):(await o.api.moveIssue(o.cfg,r,c.id),await kx(t,r,{from:l,to:c.name,mode:n}),{key:r.key,from:l,to:c.name,moved:!0})}async function vx(t,e){let n=await Fe(t);if(!n)throw new Error("no ticket linked to this Track");let r=await Pr(n);if(!r)throw new Error("no ticketing integration configured");let o=String(e||"").trim();if(!o)throw new Error("comment body required");let s=await r.api.createComment(r.cfg,n,o);return await I({id:t,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 Tx(t,e,n){if(!e)throw new Error("offerId required");let r=await L({id:t.id,cwd:t.cwd}),o=r.find(a=>a.type==="ticket.move.offered"&&a.payload?.offerId===e);if(!o)throw new Error("unknown offer");if(r.some(a=>a.type==="ticket.move.answered"&&a.payload?.offerId===e))throw new Error("offer already answered");let s=null;return n&&(s=await Mp(t.id,o.payload.to?.id,{mode:"offer"})),await I({id:t.id,cwd:t.cwd},{type:"ticket.move.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:e,action:n?"moved":"dismiss",...s?{from:s.from,to:s.to}:{}}}),{offerId:e,action:n?"moved":"dismiss",...s??{}}}var cx=50;async function Ax(){let t=await Or();if(!t)throw new Error("no ticketing integration configured");return jo(t)}function SP(t){let e=t&&typeof t=="object"?t:{},n=(Array.isArray(e.issues)?e.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=e.epic&&String(e.epic.name||"").trim()?{name:String(e.epic.name).trim(),description:e.epic.description?String(e.epic.description):null}:null;if(!n.length&&!r)throw new Error("a plan needs an epic or at least one issue");if(n.length>cx)throw new Error(`too many issues (${n.length}); cap is ${cx} per proposal`);return{epic:r,issues:n,team:e.team?String(e.team).trim():null,linkCurrentTrack:e.linkCurrentTrack===!0}}async function vP(t,e,n,r){let o=r??await jo(t),s=i=>o.find(c=>c.id===i||c.key.toLowerCase()===String(i).toLowerCase()||c.name.toLowerCase()===String(i).toLowerCase())??null;if(e.team){let i=s(e.team);if(i)return i}let a=await Fe(n.id);if(a?.key){let i=a.key.split("-")[0],c=o.find(l=>l.key===i);if(c)return c}if(t.defaultTeam){let i=s(t.defaultTeam);if(i)return i}return o.length===1?o[0]:null}async function Ex(t,e){let n=await Or();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=SP(e),o=await jo(n),s=await vP(n,r,t,o),a=s?{id:s.id,key:s.key,name:s.name}:null,i=px();return await I({id:t.id,cwd:t.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 _x(t,e,n,{teamId:r=null}={}){if(!e)throw new Error("proposalId required");let o=await L({id:t.id,cwd:t.cwd}),s=o.find(m=>m.type==="ticket.create.offered"&&m.payload?.proposalId===e);if(!s)throw new Error("unknown proposal");if(o.some(m=>m.type==="ticket.create.answered"&&m.payload?.proposalId===e))throw new Error("proposal already answered");if(!n)return await I({id:t.id,cwd:t.cwd},{type:"ticket.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:e,action:"dismiss"}}),{proposalId:e,action:"dismiss"};let a=await Or();if(!a)throw new Error("no ticketing integration configured");let i=s.payload,c=i.team??null;if(!c&&r){let m=(await jo(a)).find(w=>w.id===r);if(!m)throw new Error("unknown team");c={id:m.id,key:m.key,name:m.name}}if(!c)throw new Error("a team is required to create \u2014 pick one");let l=[],u=[],d=null;if(i.epic){let m=await xp(a,{teamId:c.id,name:i.epic.name,description:i.epic.description});d=m.id,l.push({kind:"epic",title:m.name,url:m.url})}for(let m of i.issues||[])try{let w=await Sp(a,{teamId:c.id,title:m.title,description:m.description,projectId:d,priority:m.priority});l.push({kind:"issue",key:w.key,title:w.title,url:w.url})}catch(w){u.push({title:m.title,message:w?.message||String(w)})}await I({id:t.id,cwd:t.cwd},{type:"ticket.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:e,team:{key:c.key,name:c.name},items:l,failed:u}}),await I({id:t.id,cwd:t.cwd},{type:"ticket.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:e,action:"created",createdCount:l.length,failedCount:u.length}});let f=l.filter(m=>m.kind==="issue"),p=null;return i.linkCurrentTrack&&f.length===1&&!await Fe(t.id)&&(p=await Lo(t,f[0].key,{source:"created"}).catch(()=>null)),{proposalId:e,action:"created",created:l,failed:u,linked:p?p.key:null}}async function ga(t,e){let n=await Pr(t);n&&await n.api.createComment(n.cfg,t,e)}async function TP(t,e,n){let r=await Pr(t);if(!r)return null;let o=await en(e);if(!o)return null;let s=ke(o,n);if(!s)return null;let a=await ya.readFile(le(o,s.v).png).catch(()=>null);return a?r.api.uploadImage(r.cfg,{issue:t.key,filename:`${o.name.replace(/[^\w.-]+/g,"-")}.v${s.v}.png`,contentType:"image/png",buffer:a}):null}var lx=()=>Number(process.env.BOSTRAT_TICKET_COST_SYNC_MS??12e4),Ep=new Map;function AP(t,e){if(lx()<=0)return ba(t,e);if(Ep.has(t))return;let n=setTimeout(()=>{Ep.delete(t),Fe(t).then(r=>r?ba(t,r):null).catch(()=>{})},lx());n.unref?.(),Ep.set(t,n)}var ux=new Map;async function dx(t,e,n){let r=ux.get(t)??0;Date.now()-r<600*1e3||(ux.set(t,Date.now()),await I({id:t,cwd:e},{type:"ticket.sync.failed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),message:n?.message||String(n)}}).catch(()=>{}))}async function EP(t,{resolveTrack:e=null}={}){let n=await Fe(t.trackId),r=t.payload||{};if(!n){if(t.type!=="turn.user"||t.actor!=="user")return;let o=null;for(let a of await $p())if(o=a.api.findIssueUrl(r.text,a.cfg),o)break;if(!o)return;let s=e?await e(t.trackId):null;if(!s)return;try{await Lo(s,o,{source:"chat"})}catch(a){await dx(t.trackId,s.cwd,a)}return}if(!n.track.cwd&&e){let o=await e(t.trackId).catch(()=>null);o?.cwd&&(n.track.cwd=o.cwd,await Wn(t.trackId))}try{switch(t.type){case"handoff.done":n.track.leadAgent=r.toAgent??n.track.leadAgent,await Wn(t.trackId),await ba(t.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 Wn(t.trackId),await ba(t.trackId,n),r.change==="opened"||r.change==="merged"){let o=r.change==="merged"?await bx(n,t.trackId).catch(()=>null):null;await ga(n,`**Bostrat** \u2014 PR ${r.change} for **${n.track.name}**${r.url?`: ${r.url}`:r.number?` (#${r.number})`:""}`+(o?`
475
+ }`,{contentType:n,filename:e,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 eP(t,e){let n=await Ue(t,"query($id: String!) { issue(id: $id) { state { id name type } team { states { nodes { id name type position } } } } }",{id:e.key});if(!n.issue)throw new Error(`linear: issue "${e.key}" not found`);return{current:n.issue.state??null,states:n.issue.team?.states?.nodes??[]}}async function nP(t,e,n){if(!(await Ue(t,"mutation($id: String!, $input: IssueUpdateInput!) { issueUpdate(id: $id, input: $input) { success } }",{id:e.issueId,input:{stateId:n}})).issueUpdate?.success)throw new Error("linear: issueUpdate did not succeed")}async function Jo(t){return((await Ue(t,"query { teams(first: 100) { nodes { id key name } } }")).teams?.nodes??[]).map(n=>({id:n.id,key:n.key,name:n.name}))}var Nx=255;async function Gp(t,{teamId:e,name:n,description:r}){let o=r||null,s=!!o&&o.length>Nx,a=s?`${o.slice(0,Nx-1).trimEnd()}\u2026`:o,i=await Ue(t,"mutation($input: ProjectCreateInput!) { projectCreate(input: $input) { success project { id url name } } }",{input:{teamIds:[e],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 Vp(t,{teamId:e,title:n,description:r,projectId:o,priority:s}){let a=await Ue(t,"mutation($input: IssueCreateInput!) { issueCreate(input: $input) { success issue { id identifier url title } } }",{input:{teamId:e,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}}var Ux={linear:{api:zp,config:Lr},jira:{api:qp,config:Zc}};async function em(){let t=[];for(let[e,{api:n,config:r}]of Object.entries(Ux)){let o=await r();o&&t.push({name:e,api:n,cfg:o})}return t}async function Hr(t){let e=Ux[t?.provider];if(!e)return null;let n=await e.config();return n?{name:t.provider,api:e.api,cfg:n}:null}function nm(t,e){if(!t||t.name)return t;let n=e.find(r=>r.id===t.id);return n?{...t,name:n.name}:t}var Hx=()=>process.env.BOSTRAT_STATE_DIR||Lx.join(process.env.HOME||rP.tmpdir(),".bostrat"),Zp=()=>Lx.join(Hx(),"tickets.json"),Wx=()=>(process.env.BOSTRAT_PUBLIC_URL||"http://bostrat.globopi").replace(/\/$/,""),tl=t=>`${Wx()}/track/${t}`,zn=null,Jp=null,Yp=Promise.resolve();async function Oa(){return zn||(Jp??=Ra.readFile(Zp(),"utf8").then(t=>({tickets:JSON.parse(t)?.tickets??{},existed:!0})).catch(()=>({tickets:{},existed:!1})).then(async({tickets:t,existed:e})=>{if(zn=t,!e&&vt()){let{records:n,source:r}=await Mt("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;zn[s]=i}Object.keys(zn).length&&await Qp().catch(()=>{})}}return zn}).finally(()=>Jp=null),Jp)}async function Qp(){let t=JSON.stringify({tickets:zn},null,2),e=`${Zp()}.${process.pid}.tmp`;await Ra.mkdir(Hx(),{recursive:!0}),await Ra.writeFile(e,t),await Ra.rename(e,Zp())}async function Jn(t=null){if(Yp=Yp.then(Qp,Qp),await Yp.catch(()=>{}),!t)return;let e=zn?.[t];e?Wt("tickets",{id:t,updatedAt:Date.now(),...e},{trackId:t}).catch(()=>{}):we("tickets",t).catch(()=>{})}async function He(t){return(await Oa())[t]??null}async function qx(){return{...await Oa()}}async function Kx(){return(await em()).length>0}async function Yo(t,e,{source:n="api"}={}){let r=await em();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 f=u.api.parseIssueRef(e);if(f)try{s=await u.api.resolveIssue(u.cfg,f),o=u;break}catch(d){a=d}}if(!o)throw a||new Error(`"${e}" is not a Linear or Jira issue URL or key (ABC-123)`);let i=(t.boxes||[]).find(u=>u.name===t.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:t.name,branch:t.workspace?.branch??null,leadAgent:i?.agent??null,cwd:t.cwd??null,...t.workspace?.kind==="multi"?{repos:(t.workspace.repos??[]).map(u=>u?.name).filter(Boolean)}:{}},pr:null};(await Oa())[t.id]=c,await Jn(t.id),await I({id:t.id,cwd:t.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 $a(t.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 Ia(c,`**Bostrat** \u2014 Track **${c.track.name}** linked${l.length?` (${l.join(", ")})`:""}.`),await zx(t.id,c,"linked"),c}async function rm(t){let e=await Oa();return e[t]?(delete e[t],await Jn(t),!0):!1}var tm=t=>`$${t>=100?Math.round(t):t.toFixed(2)}`;async function Gx(t,e){if(!t.track?.cwd)return null;let n=Mn(await F({id:e,cwd:t.track.cwd}));return!n.totalUsd||n.totalUsd<.01?null:n}function oP(t){let e=Object.entries(t.byProvider).sort((r,o)=>o[1].usd-r[1].usd).map(([r,o])=>`${r} ${tm(o.usd)}`).join(" \xB7 "),n=Object.keys(t.byBox).length;return`${tm(t.totalUsd)}${e?` (${e})`:""}${n>1?` across ${n} boxes`:""}`}function sP(t,e){let n=[];return t.track.leadAgent&&n.push(`lead ${t.track.leadAgent}`),t.track.branch&&n.push(t.track.branch),t.track.repos?.length&&n.push(t.track.repos.join(" + ")),t.pr?.number&&n.push(`PR #${t.pr.number} ${t.pr.change==="merged"?"merged":"open"}`),e&&n.push(tm(e.totalUsd)),n.join(" \xB7 ")||"linked"}async function $a(t,e){let n=await Hr(e);if(!n)return;let r=await Gx(e,t).catch(()=>null);await n.api.upsertCard(n.cfg,e,{url:tl(t),title:`Bostrat Track: ${e.track.name}`,subtitle:sP(e,r)})}function el(t){let e=new URL(Wx());return`${e.protocol}//${t}.${e.host}/`}var aP={linked:"linked",opened:"prOpened",merged:"prMerged"};function iP(t,e,n){let r=o=>e.filter(s=>s.type===o).sort((s,a)=>s.position-a.position);if(n==="linked"){if(["triage","backlog","unstarted"].includes(t?.type))return r("started")[0]??null}else if(n==="opened"){if(t?.type!=="completed")return r("started").find(o=>/review/i.test(o.name))??null}else if(n==="merged"&&t?.type!=="completed")return r("completed")[0]??null;return null}async function Vx(t,e,{from:n,to:r,mode:o,phase:s=null,actor:a="user"}){e.state=r,await Jn(t),await I({id:t,cwd:e.track?.cwd},{type:"ticket.state.changed",actor:a,source:"orchestrator",payload:{ts:Date.now(),key:e.key,url:e.url,from:n??null,to:r,mode:o,...s?{phase:s}:{}}}).catch(()=>{})}async function zx(t,e,n){let r=await Hr(e);if(!r)return;let o=r.cfg.ticketFlow?.[aP[n]]??"prompt";if(o==="off")return;let{current:s,states:a}=await r.api.issueStates(r.cfg,e),i=nm(s,a),c=iP(i,a,n);if(!c||c.id===i?.id)return;let l=i?.name??e.state??null;if(o==="auto"){await r.api.moveIssue(r.cfg,e,c.id),await Vx(t,e,{from:l,to:c.name,mode:"auto",phase:n,actor:"system"});return}await I({id:t,cwd:e.track?.cwd},{type:"ticket.move.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),offerId:Fx(),provider:e.provider,key:e.key,url:e.url,phase:n,from:l,to:{id:c.id,name:c.name,type:c.type},...e.pr?.number?{prNumber:e.pr.number}:{}}}).catch(()=>{})}async function Jx(t){let e=await He(t);if(!e)throw new Error("no ticket linked to this Track");let n=await Hr(e);if(!n)throw new Error("no ticketing integration configured");let{current:r,states:o}=await n.api.issueStates(n.cfg,e),s=nm(r,o);return s?.name&&e.state!==s.name&&(e.state=s.name,await Jn(t)),{key:e.key,url:e.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 om(t,e,{mode:n="manual"}={}){if(!e)throw new Error("stateId required");let r=await He(t);if(!r)throw new Error("no ticket linked to this Track");let o=await Hr(r);if(!o)throw new Error("no ticketing integration configured");let{current:s,states:a}=await o.api.issueStates(o.cfg,r),i=nm(s,a),c=a.find(u=>u.id===e);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 Jn(t)),{key:r.key,from:l,to:c.name,moved:!1}):(await o.api.moveIssue(o.cfg,r,c.id),await Vx(t,r,{from:l,to:c.name,mode:n}),{key:r.key,from:l,to:c.name,moved:!0})}async function Yx(t,e){let n=await He(t);if(!n)throw new Error("no ticket linked to this Track");let r=await Hr(n);if(!r)throw new Error("no ticketing integration configured");let o=String(e||"").trim();if(!o)throw new Error("comment body required");let s=await r.api.createComment(r.cfg,n,o);return await I({id:t,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 Xx(t,e,n){if(!e)throw new Error("offerId required");let r=await F({id:t.id,cwd:t.cwd}),o=r.find(a=>a.type==="ticket.move.offered"&&a.payload?.offerId===e);if(!o)throw new Error("unknown offer");if(r.some(a=>a.type==="ticket.move.answered"&&a.payload?.offerId===e))throw new Error("offer already answered");let s=null;return n&&(s=await om(t.id,o.payload.to?.id,{mode:"offer"})),await I({id:t.id,cwd:t.cwd},{type:"ticket.move.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:e,action:n?"moved":"dismiss",...s?{from:s.from,to:s.to}:{}}}),{offerId:e,action:n?"moved":"dismiss",...s??{}}}var Px=50;async function Zx(){let t=await Lr();if(!t)throw new Error("no ticketing integration configured");return Jo(t)}function cP(t){let e=t&&typeof t=="object"?t:{},n=(Array.isArray(e.issues)?e.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=e.epic&&String(e.epic.name||"").trim()?{name:String(e.epic.name).trim(),description:e.epic.description?String(e.epic.description):null}:null;if(!n.length&&!r)throw new Error("a plan needs an epic or at least one issue");if(n.length>Px)throw new Error(`too many issues (${n.length}); cap is ${Px} per proposal`);return{epic:r,issues:n,team:e.team?String(e.team).trim():null,linkCurrentTrack:e.linkCurrentTrack===!0}}async function lP(t,e,n,r){let o=r??await Jo(t),s=i=>o.find(c=>c.id===i||c.key.toLowerCase()===String(i).toLowerCase()||c.name.toLowerCase()===String(i).toLowerCase())??null;if(e.team){let i=s(e.team);if(i)return i}let a=await He(n.id);if(a?.key){let i=a.key.split("-")[0],c=o.find(l=>l.key===i);if(c)return c}if(t.defaultTeam){let i=s(t.defaultTeam);if(i)return i}return o.length===1?o[0]:null}async function Qx(t,e){let n=await Lr();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=cP(e),o=await Jo(n),s=await lP(n,r,t,o),a=s?{id:s.id,key:s.key,name:s.name}:null,i=Fx();return await I({id:t.id,cwd:t.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 tS(t,e,n,{teamId:r=null}={}){if(!e)throw new Error("proposalId required");let o=await F({id:t.id,cwd:t.cwd}),s=o.find(h=>h.type==="ticket.create.offered"&&h.payload?.proposalId===e);if(!s)throw new Error("unknown proposal");if(o.some(h=>h.type==="ticket.create.answered"&&h.payload?.proposalId===e))throw new Error("proposal already answered");if(!n)return await I({id:t.id,cwd:t.cwd},{type:"ticket.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:e,action:"dismiss"}}),{proposalId:e,action:"dismiss"};let a=await Lr();if(!a)throw new Error("no ticketing integration configured");let i=s.payload,c=i.team??null;if(!c&&r){let h=(await Jo(a)).find(w=>w.id===r);if(!h)throw new Error("unknown team");c={id:h.id,key:h.key,name:h.name}}if(!c)throw new Error("a team is required to create \u2014 pick one");let l=[],u=[],f=null;if(i.epic){let h=await Gp(a,{teamId:c.id,name:i.epic.name,description:i.epic.description});f=h.id,l.push({kind:"epic",title:h.name,url:h.url})}for(let h of i.issues||[])try{let w=await Vp(a,{teamId:c.id,title:h.title,description:h.description,projectId:f,priority:h.priority});l.push({kind:"issue",key:w.key,title:w.title,url:w.url})}catch(w){u.push({title:h.title,message:w?.message||String(w)})}await I({id:t.id,cwd:t.cwd},{type:"ticket.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:e,team:{key:c.key,name:c.name},items:l,failed:u}}),await I({id:t.id,cwd:t.cwd},{type:"ticket.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:e,action:"created",createdCount:l.length,failedCount:u.length}});let d=l.filter(h=>h.kind==="issue"),p=null;return i.linkCurrentTrack&&d.length===1&&!await He(t.id)&&(p=await Yo(t,d[0].key,{source:"created"}).catch(()=>null)),{proposalId:e,action:"created",created:l,failed:u,linked:p?p.key:null}}async function Ia(t,e){let n=await Hr(t);n&&await n.api.createComment(n.cfg,t,e)}async function uP(t,e,n){let r=await Hr(t);if(!r)return null;let o=await rn(e);if(!o)return null;let s=ve(o,n);if(!s)return null;let a=await Ra.readFile(fe(o,s.v).png).catch(()=>null);return a?r.api.uploadImage(r.cfg,{issue:t.key,filename:`${o.name.replace(/[^\w.-]+/g,"-")}.v${s.v}.png`,contentType:"image/png",buffer:a}):null}var Dx=()=>Number(process.env.BOSTRAT_TICKET_COST_SYNC_MS??12e4),Xp=new Map;function dP(t,e){if(Dx()<=0)return $a(t,e);if(Xp.has(t))return;let n=setTimeout(()=>{Xp.delete(t),He(t).then(r=>r?$a(t,r):null).catch(()=>{})},Dx());n.unref?.(),Xp.set(t,n)}var Bx=new Map;async function jx(t,e,n){let r=Bx.get(t)??0;Date.now()-r<600*1e3||(Bx.set(t,Date.now()),await I({id:t,cwd:e},{type:"ticket.sync.failed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),message:n?.message||String(n)}}).catch(()=>{}))}async function fP(t,{resolveTrack:e=null}={}){let n=await He(t.trackId),r=t.payload||{};if(!n){if(t.type!=="turn.user"||t.actor!=="user")return;let o=null;for(let a of await em())if(o=a.api.findIssueUrl(r.text,a.cfg),o)break;if(!o)return;let s=e?await e(t.trackId):null;if(!s)return;try{await Yo(s,o,{source:"chat"})}catch(a){await jx(t.trackId,s.cwd,a)}return}if(!n.track.cwd&&e){let o=await e(t.trackId).catch(()=>null);o?.cwd&&(n.track.cwd=o.cwd,await Jn(t.trackId))}try{switch(t.type){case"handoff.done":n.track.leadAgent=r.toAgent??n.track.leadAgent,await Jn(t.trackId),await $a(t.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 Jn(t.trackId),await $a(t.trackId,n),r.change==="opened"||r.change==="merged"){let o=r.change==="merged"?await Gx(n,t.trackId).catch(()=>null):null;await Ia(n,`**Bostrat** \u2014 PR ${r.change} for **${n.track.name}**${r.url?`: ${r.url}`:r.number?` (#${r.number})`:""}`+(o?`
448
476
 
449
- Agent cost for this Track: ${yP(o)}.`:"")),await xx(t.trackId,n,r.change)}break}case"mock.state.changed":{if(r.change==="ready"&&r.mockId){let o=await TP(n,r.mockId,r.version??null);if(!o)break;let s=(r.version??1)>1?` revised (v${r.version})`:"";await ga(n,`**Bostrat** \u2014 mock **${r.name}**${s}${r.group?` (group \`${r.group}\`)`:""}:
477
+ Agent cost for this Track: ${oP(o)}.`:"")),await zx(t.trackId,n,r.change)}break}case"mock.state.changed":{if(r.change==="ready"&&r.mockId){let o=await uP(n,r.mockId,r.version??null);if(!o)break;let s=(r.version??1)>1?` revised (v${r.version})`:"";await Ia(n,`**Bostrat** \u2014 mock **${r.name}**${s}${r.group?` (group \`${r.group}\`)`:""}:
450
478
 
451
- ![${r.name}](${o})`)}else if(r.change==="picked"){let o=(r.siblings??[]).map(s=>`**${s.name}**`).join(", ");await ga(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 ga(n,`**Bostrat** \u2014 live preview **${r.name}**: ${Uc(r.slug)}
452
- _(runs on the Track's branch; reachable on the operator's private network only)_`);break}case"cost.recorded":await AP(t.trackId,n);break;default:break}}catch(o){let s=e?await e(t.trackId).catch(()=>null):null;await dx(t.trackId,s?.cwd??null,o)}}function Ix({resolveTrack:t}){Yt.on("event",e=>{EP(e,{resolveTrack:t}).catch(()=>{})})}async function Rx(){if(!wt())return{pushed:0,source:"unconfigured"};let{records:t,source:e}=await $t("tickets");if(e!=="plane"||t.length)return{pushed:0,source:e};let n=await ka(),r=0;for(let[o,s]of Object.entries(n))await Ut("tickets",{id:o,updatedAt:Date.now(),...s},{trackId:o}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}ho();Ao();import _P from"ws";var $x=()=>process.env.BOSTRAT_SLACK_API_BASE||"https://slack.com/api";async function Hc(t,e,n={}){let r=await fetch(`${$x()}/${t}`,{method:"POST",headers:{authorization:`Bearer ${e}`,"content-type":"application/json; charset=utf-8"},body:JSON.stringify(n)}),o=await r.json().catch(()=>null);if(!o?.ok)throw new Error(`slack ${t}: ${o?.error||`http ${r.status}`}`);return o}var Pp=(t,e)=>Hc("chat.postMessage",t,e),Nr=(t,e)=>Hc("chat.update",t,e);async function Kt(t,e){await fetch(t,{method:"POST",headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify(e)}).catch(()=>{})}async function IP(t,e,n={}){let r=await fetch(`${$x()}/${t}`,{method:"POST",headers:{authorization:`Bearer ${e}`,"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 ${t}: ${o?.error||`http ${r.status}`}`);return o}async function Ox(t,{filename:e,buffer:n,title:r,channelId:o,threadTs:s,initialComment:a}){let{upload_url:i,file_id:c}=await IP("files.getUploadURLExternal",t,{filename:e,length:String(n.length)}),l=await fetch(i,{method:"POST",body:n});if(!l.ok)throw new Error(`slack upload: http ${l.status}`);return Hc("files.completeUploadExternal",t,{files:[{id:c,title:r}],channel_id:o,thread_ts:s,...a?{initial_comment:a}:{}})}var RP=2200;function Cx({getToken:t,onEnvelope:e,log:n=()=>{}}){let r=!1,o=null,s=null,a=1e3;async function i(){if(r)return;let l;try{let u=await t();if(!u)throw new Error("app token missing");({url:l}=await Hc("apps.connections.open",u))}catch(u){return n(`connections.open failed: ${u?.message||u}`),c()}o=new _P(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 f=w=>{try{o.send(JSON.stringify(w?{envelope_id:d.envelope_id,payload:w}:{envelope_id:d.envelope_id}))}catch{}},p=!1,m=setTimeout(()=>{p=!0,f()},RP);Promise.resolve().then(()=>e(d)).then(w=>{clearTimeout(m),!p&&(p=!0,f(d.accepts_response_payload?w:void 0))},w=>{clearTimeout(m),p||(p=!0,f()),n(`envelope handler failed: ${w?.message||w}`)})}),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 Nx=()=>process.env.BOSTRAT_STATE_DIR||qc.join(process.env.HOME||OP.tmpdir(),".bostrat"),Lp=()=>qc.join(Nx(),"slack.json"),Wc=null,Np=null,Bp=Promise.resolve();async function Up(){return Wc||(Np??=xa.readFile(Lp(),"utf8").then(t=>JSON.parse(t)?.threads??{}).catch(()=>({})).then(t=>Wc=t).finally(()=>Np=null),Np)}async function Mx(){let t=JSON.stringify({threads:Wc},null,2),e=`${Lp()}.${process.pid}.tmp`;await xa.mkdir(Nx(),{recursive:!0}),await xa.writeFile(e,t),await xa.rename(e,Lp())}async function xe(){Bp=Bp.then(Mx,Mx),await Bp.catch(()=>{})}async function Hp(t){return(await Up())[t]??null}async function CP(t,e){let n=await Up();for(let[r,o]of Object.entries(n))if(o.channel===t&&o.ts===e)return{trackId:r,rec:o};return null}var X=t=>String(t??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");function Sa(t,e){let n=String(t??"").trim();return n.length<=e?n:`${n.slice(0,e-1).trimEnd()}\u2026`}function MP(t,e=500){let n=String(t??"").trim().split(/\n\s*\n/)[0]??"";return Sa(n.replace(/\n+/g," "),e)}function Bx(t){let e=`*${X(t.name)}*${t.archivedAt?" \xB7 _archived_":""}`,n=`${X(t.repoLabel)} \xB7 \`${X(t.branch||"?")}\` \xB7 lead *${X(t.lead)}*`,r=t.kickoff?`> ${X(Sa(t.kickoff,300))}`:"_no kickoff yet \u2014 reply in this thread to steer the lead_";return[{type:"section",text:{type:"mrkdwn",text:`${e}
453
- ${n}`}},{type:"section",text:{type:"mrkdwn",text:r}},{type:"context",elements:[{type:"mrkdwn",text:`<${Fc(t.trackId)}|open the Track> \xB7 reachable on the operator's private network only`}]}]}async function Fp(t,e){await Nr(t.botToken,{channel:e.channel,ts:e.ts,text:`Track: ${e.name}`,blocks:Bx(e)})}async function Kn(t,e,n,r=void 0){return Pp(t.botToken,{channel:e.channel,thread_ts:e.ts,text:n,...r?{blocks:r}:{},unfurl_links:!1})}var Px=new Set;function qn(t){Px.add(t),t.catch(()=>{}).finally(()=>Px.delete(t))}var ht=t=>({response_type:"ephemeral",text:t}),PP="*/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._",NP=["claude","cursor","codex"];function Dp(t,e){let n=(e||"").toLowerCase(),r=t.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 jp=(t,e)=>ht(`No live Track matches \u201C${X(e)}\u201D. Live: ${t.map(n=>`\`${X(n.name)}\``).join(" \xB7 ")||"none"}`);async function Dx(t,e,{name:n,repo:r,responseUrl:o}){let s=t.deps;try{let a=(await s.listTracks()).filter(d=>!d.archivedAt);if(a.length>=e.maxConcurrent){await Kt(o,{...ht(`At capacity \u2014 ${a.length} live Tracks (limit ${e.maxConcurrent}). Archive or stop something first.`),replace_original:!0});return}if(!e.channel){await Kt(o,{...ht("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:e.channel,name:i.name,branch:c.branch||null,repoLabel:c.repo||(c.base?qc.basename(c.base):"fresh workspace"),lead:"claude"},u=await Pp(e.botToken,{channel:e.channel,text:`Track started: ${l.name}`,blocks:Bx(l),unfurl_links:!1});l.ts=u.ts,(await Up())[i.id]=l,await xe(),await Kt(o,{...ht(`\u2713 *${X(l.name)}* started \u2014 root message posted.`),replace_original:!0})}catch(a){await Kt(o,{...ht(`Start failed: ${a?.message||a}`),replace_original:!0})}}async function BP(t,e,{track:n,responseUrl:r}){let o=t.deps;try{await o.archiveTrack(n.id);let s=await Hp(n.id);s&&(s.archivedAt=Date.now(),await xe(),await Fp(e,s).catch(()=>{})),await Kt(r,{...ht(`\u2713 *${X(n.name)}* archived.`),replace_original:!0})}catch(s){await Kt(r,{...ht(`Archive failed: ${s?.message||s}`),replace_original:!0})}}async function DP(t,e,{track:n,agent:r,responseUrl:o}){try{await t.deps.startLeadHandoff(n.id,r),await Kt(o,{...ht(`\u2713 Handing *${X(n.name)}* to ${X(r)} \u2014 the root message updates when the baton lands.`),replace_original:!0})}catch(s){await Kt(o,{...ht(`Handoff failed: ${s?.message||s}`),replace_original:!0})}}async function jP(t,e,{track:n,responseUrl:r}){let o=t.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 Kt(r,{...ht(`\u2713 Stopped *${X(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 Kt(r,{...ht(`Stop failed: ${s?.message||s}`),replace_original:!0})}}function LP(t,e){let n=[...e.slice(0,99).map(r=>({text:{type:"plain_text",text:Sa(`${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:t}),text:{type:"mrkdwn",text:`Repo for *${X(t)}*:`},accessory:{type:"static_select",action_id:"bostrat-start-repo",placeholder:{type:"plain_text",text:"Choose a repo"},options:n}}]}async function FP(t){let e=await t.listTracks(),n=e.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?qc.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 *${X(s.name)}* \u2014 ${X(i)}${a.branch?` \`${X(a.branch)}\``:""} \xB7 lead ${X(c)} \xB7 ${l}`}),o=e.length-n.length;return r.join(`
479
+ ![${r.name}](${o})`)}else if(r.change==="picked"){let o=(r.siblings??[]).map(s=>`**${s.name}**`).join(", ");await Ia(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 Ia(n,`**Bostrat** \u2014 live preview **${r.name}**: ${el(r.slug)}
480
+ _(runs on the Track's branch; reachable on the operator's private network only)_`);break}case"cost.recorded":await dP(t.trackId,n);break;default:break}}catch(o){let s=e?await e(t.trackId).catch(()=>null):null;await jx(t.trackId,s?.cwd??null,o)}}function eS({resolveTrack:t}){Zt.on("event",e=>{fP(e,{resolveTrack:t}).catch(()=>{})})}async function nS(){if(!vt())return{pushed:0,source:"unconfigured"};let{records:t,source:e}=await Mt("tickets");if(e!=="plane"||t.length)return{pushed:0,source:e};let n=await Oa(),r=0;for(let[o,s]of Object.entries(n))await Wt("tickets",{id:o,updatedAt:Date.now(),...s},{trackId:o}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}Ao();Po();import pP from"ws";var rS=()=>process.env.BOSTRAT_SLACK_API_BASE||"https://slack.com/api";async function nl(t,e,n={}){let r=await fetch(`${rS()}/${t}`,{method:"POST",headers:{authorization:`Bearer ${e}`,"content-type":"application/json; charset=utf-8"},body:JSON.stringify(n)}),o=await r.json().catch(()=>null);if(!o?.ok)throw new Error(`slack ${t}: ${o?.error||`http ${r.status}`}`);return o}var sm=(t,e)=>nl("chat.postMessage",t,e),Wr=(t,e)=>nl("chat.update",t,e);async function Vt(t,e){await fetch(t,{method:"POST",headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify(e)}).catch(()=>{})}async function mP(t,e,n={}){let r=await fetch(`${rS()}/${t}`,{method:"POST",headers:{authorization:`Bearer ${e}`,"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 ${t}: ${o?.error||`http ${r.status}`}`);return o}async function oS(t,{filename:e,buffer:n,title:r,channelId:o,threadTs:s,initialComment:a}){let{upload_url:i,file_id:c}=await mP("files.getUploadURLExternal",t,{filename:e,length:String(n.length)}),l=await fetch(i,{method:"POST",body:n});if(!l.ok)throw new Error(`slack upload: http ${l.status}`);return nl("files.completeUploadExternal",t,{files:[{id:c,title:r}],channel_id:o,thread_ts:s,...a?{initial_comment:a}:{}})}var hP=2200;function sS({getToken:t,onEnvelope:e,log:n=()=>{}}){let r=!1,o=null,s=null,a=1e3;async function i(){if(r)return;let l;try{let u=await t();if(!u)throw new Error("app token missing");({url:l}=await nl("apps.connections.open",u))}catch(u){return n(`connections.open failed: ${u?.message||u}`),c()}o=new pP(l),o.on("message",u=>{let f;try{f=JSON.parse(u)}catch{return}if(f.type==="hello"){a=1e3,n("socket connected");return}if(f.type==="disconnect"){try{o.close()}catch{}return}if(!f.envelope_id)return;let d=w=>{try{o.send(JSON.stringify(w?{envelope_id:f.envelope_id,payload:w}:{envelope_id:f.envelope_id}))}catch{}},p=!1,h=setTimeout(()=>{p=!0,d()},hP);Promise.resolve().then(()=>e(f)).then(w=>{clearTimeout(h),!p&&(p=!0,d(f.accepts_response_payload?w:void 0))},w=>{clearTimeout(h),p||(p=!0,d()),n(`envelope handler failed: ${w?.message||w}`)})}),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 cS=()=>process.env.BOSTRAT_STATE_DIR||ol.join(process.env.HOME||gP.tmpdir(),".bostrat"),um=()=>ol.join(cS(),"slack.json"),rl=null,am=null,im=Promise.resolve();async function fm(){return rl||(am??=Ca.readFile(um(),"utf8").then(t=>JSON.parse(t)?.threads??{}).catch(()=>({})).then(t=>rl=t).finally(()=>am=null),am)}async function aS(){let t=JSON.stringify({threads:rl},null,2),e=`${um()}.${process.pid}.tmp`;await Ca.mkdir(cS(),{recursive:!0}),await Ca.writeFile(e,t),await Ca.rename(e,um())}async function Te(){im=im.then(aS,aS),await im.catch(()=>{})}async function pm(t){return(await fm())[t]??null}async function yP(t,e){let n=await fm();for(let[r,o]of Object.entries(n))if(o.channel===t&&o.ts===e)return{trackId:r,rec:o};return null}var Q=t=>String(t??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");function Ma(t,e){let n=String(t??"").trim();return n.length<=e?n:`${n.slice(0,e-1).trimEnd()}\u2026`}function bP(t,e=500){let n=String(t??"").trim().split(/\n\s*\n/)[0]??"";return Ma(n.replace(/\n+/g," "),e)}function lS(t){let e=`*${Q(t.name)}*${t.archivedAt?" \xB7 _archived_":""}`,n=`${Q(t.repoLabel)} \xB7 \`${Q(t.branch||"?")}\` \xB7 lead *${Q(t.lead)}*`,r=t.kickoff?`> ${Q(Ma(t.kickoff,300))}`:"_no kickoff yet \u2014 reply in this thread to steer the lead_";return[{type:"section",text:{type:"mrkdwn",text:`${e}
481
+ ${n}`}},{type:"section",text:{type:"mrkdwn",text:r}},{type:"context",elements:[{type:"mrkdwn",text:`<${tl(t.trackId)}|open the Track> \xB7 reachable on the operator's private network only`}]}]}async function dm(t,e){await Wr(t.botToken,{channel:e.channel,ts:e.ts,text:`Track: ${e.name}`,blocks:lS(e)})}async function Xn(t,e,n,r=void 0){return sm(t.botToken,{channel:e.channel,thread_ts:e.ts,text:n,...r?{blocks:r}:{},unfurl_links:!1})}var iS=new Set;function Yn(t){iS.add(t),t.catch(()=>{}).finally(()=>iS.delete(t))}var xt=t=>({response_type:"ephemeral",text:t}),kP="*/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._",xP=["claude","cursor","codex"];function cm(t,e){let n=(e||"").toLowerCase(),r=t.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 lm=(t,e)=>xt(`No live Track matches \u201C${Q(e)}\u201D. Live: ${t.map(n=>`\`${Q(n.name)}\``).join(" \xB7 ")||"none"}`);async function uS(t,e,{name:n,repo:r,responseUrl:o}){let s=t.deps;try{let a=(await s.listTracks()).filter(f=>!f.archivedAt);if(a.length>=e.maxConcurrent){await Vt(o,{...xt(`At capacity \u2014 ${a.length} live Tracks (limit ${e.maxConcurrent}). Archive or stop something first.`),replace_original:!0});return}if(!e.channel){await Vt(o,{...xt("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:e.channel,name:i.name,branch:c.branch||null,repoLabel:c.repo||(c.base?ol.basename(c.base):"fresh workspace"),lead:"claude"},u=await sm(e.botToken,{channel:e.channel,text:`Track started: ${l.name}`,blocks:lS(l),unfurl_links:!1});l.ts=u.ts,(await fm())[i.id]=l,await Te(),await Vt(o,{...xt(`\u2713 *${Q(l.name)}* started \u2014 root message posted.`),replace_original:!0})}catch(a){await Vt(o,{...xt(`Start failed: ${a?.message||a}`),replace_original:!0})}}async function SP(t,e,{track:n,responseUrl:r}){let o=t.deps;try{await o.archiveTrack(n.id);let s=await pm(n.id);s&&(s.archivedAt=Date.now(),await Te(),await dm(e,s).catch(()=>{})),await Vt(r,{...xt(`\u2713 *${Q(n.name)}* archived.`),replace_original:!0})}catch(s){await Vt(r,{...xt(`Archive failed: ${s?.message||s}`),replace_original:!0})}}async function vP(t,e,{track:n,agent:r,responseUrl:o}){try{await t.deps.startLeadHandoff(n.id,r),await Vt(o,{...xt(`\u2713 Handing *${Q(n.name)}* to ${Q(r)} \u2014 the root message updates when the baton lands.`),replace_original:!0})}catch(s){await Vt(o,{...xt(`Handoff failed: ${s?.message||s}`),replace_original:!0})}}async function TP(t,e,{track:n,responseUrl:r}){let o=t.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 Vt(r,{...xt(`\u2713 Stopped *${Q(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 Vt(r,{...xt(`Stop failed: ${s?.message||s}`),replace_original:!0})}}function AP(t,e){let n=[...e.slice(0,99).map(r=>({text:{type:"plain_text",text:Ma(`${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:t}),text:{type:"mrkdwn",text:`Repo for *${Q(t)}*:`},accessory:{type:"static_select",action_id:"bostrat-start-repo",placeholder:{type:"plain_text",text:"Choose a repo"},options:n}}]}async function EP(t){let e=await t.listTracks(),n=e.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?ol.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 *${Q(s.name)}* \u2014 ${Q(i)}${a.branch?` \`${Q(a.branch)}\``:""} \xB7 lead ${Q(c)} \xB7 ${l}`}),o=e.length-n.length;return r.join(`
454
482
  `)+(o?`
455
- _${o} archived_`:"")}async function UP(t,e){let n=await Cr();if(!n)return ht("Slack integration not configured.");let r=t.deps,o=(e.text||"").trim().split(/\s+/).filter(Boolean),s=(o[0]||"help").toLowerCase(),a=o.slice(1);switch(s){case"start":{if(!a.length)return ht("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?(qn(Dx(t,n,{name:u,repo:l.path,responseUrl:e.response_url})),ht(`Starting *${X(u)}* on ${X(l.name)}\u2026`)):{response_type:"ephemeral",text:`Pick a repo for \u201C${u}\u201D`,blocks:LP(u,i)}}case"archive":{if(!a.length)return ht("Usage: `/bostrat archive <track>`");let{match:i,live:c}=Dp(await r.listTracks(),a.join(" "));return i?(qn(BP(t,n,{track:i,responseUrl:e.response_url})),ht(`Archiving *${X(i.name)}*\u2026`)):jp(c,a.join(" "))}case"handoff":{let i=r.knownAgents??NP,c=a.at(-1)?.toLowerCase();if(a.length<2||!i.includes(c))return ht(`Usage: \`/bostrat handoff <track> <${i.join("|")}>\``);let l=a.slice(0,-1).join(" "),{match:u,live:d}=Dp(await r.listTracks(),l);return u?(qn(DP(t,n,{track:u,agent:c,responseUrl:e.response_url})),ht(`Handing *${X(u.name)}* to ${X(c)}\u2026`)):jp(d,l)}case"stop":{if(!a.length)return ht("Usage: `/bostrat stop <track>`");let{match:i,live:c}=Dp(await r.listTracks(),a.join(" "));return i?(qn(jP(t,n,{track:i,responseUrl:e.response_url})),ht(`Stopping *${X(i.name)}*\u2026`)):jp(c,a.join(" "))}case"list":return ht(await FP(r));default:return ht(PP)}}async function HP(t,e,n,r){let{trackId:o,promptId:s,label:a}=r,i=await Hp(o);try{if(await t.deps.answerPrompt(o,{promptId:s,answers:[a]}),i?.prompt?.promptId===s){let{ts:c,question:l}=i.prompt;delete i.prompt,await xe(),await Nr(e.botToken,{channel:i.channel,ts:c,text:`\u2713 ${a}`,blocks:[{type:"section",text:{type:"mrkdwn",text:`~${X(l||"question")}~
456
- \u2713 *${X(a)}*`}}]}).catch(()=>{})}}catch(c){await Kt(n.response_url,ht(`Couldn't answer: ${c?.message||c}`))}}async function WP(t,e,n,r){let{trackId:o,offerId:s,action:a}=r,i=t.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(f=>f.type==="pr.offered"&&f.payload?.offerId===s);if(!u)throw new Error("unknown offer");if(l.some(f=>f.type==="pr.offer.answered"&&f.payload?.offerId===s))throw new Error("offer already answered");let d=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,mo(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 Kt(n.response_url,ht(`Couldn't act on the offer: ${c?.message||c}`))}}async function qP(t,e,n,r){let{trackId:o,offerId:s,choice:a}=r;try{let i=await t.deps.resolveTrack(o);if(!i)throw new Error("track not found");await t.deps.answerPrExists(i,{offerId:s,choice:a})}catch(i){await Kt(n.response_url,ht(`Couldn't act on the offer: ${i?.message||i}`))}}async function KP(t,e){let n=e.actions?.[0];if(!n?.action_id)return;let r=await Cr();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 Kt(e.response_url,{...ht(`Starting *${X(s)}*\u2026`),replace_original:!0}),qn(Dx(t,r,{name:s,repo:a==="__fresh__"?null:a,responseUrl:e.response_url}));return}let o;try{o=JSON.parse(n.value)}catch{return}n.action_id==="bostrat-prompt"?qn(HP(t,r,e,o)):n.action_id==="bostrat-ship"?qn(WP(t,r,e,o)):n.action_id==="bostrat-pr-exists"&&qn(qP(t,r,e,o))}async function GP(t,e){if(!e||e.type!=="message"||e.bot_id||e.subtype||!e.thread_ts||e.thread_ts===e.ts||!e.text?.trim())return;let n=await CP(e.channel,e.thread_ts);if(!n)return;let r=await Cr();if(r)try{await t.deps.sayToLead(n.trackId,e.text.trim())}catch(o){await Kn(r,n.rec,`Couldn't deliver that to the lead: ${o?.message||o}`).catch(()=>{})}}function VP(t){return async e=>{if(e.type==="slash_commands")return UP(t,e.payload);if(e.type==="interactive"){await KP(t,e.payload);return}if(e.type==="events_api"){await GP(t,e.payload?.event);return}}}var zP=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 JP(t,e){let n=[{type:"section",text:{type:"mrkdwn",text:`\u2753 ${X(e.question||"The lead needs an answer")}`}}],r=(e.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:Sa(String(o),75)},value:JSON.stringify({trackId:t,promptId:e.promptId,label:String(o)})}))}):n.push({type:"context",elements:[{type:"mrkdwn",text:"_reply in this thread to answer_"}]}),n}async function YP(t,e,n){let r=n.payload||{};if(!r.promptId||e.prompt?.promptId===r.promptId)return;e.prompt&&await Nr(t.botToken,{channel:e.channel,ts:e.prompt.ts,text:"superseded",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${X(e.prompt.question||"question")}~ _superseded_`}}]}).catch(()=>{});let o=await Kn(t,e,r.question||"The lead needs an answer",JP(n.trackId,r));e.prompt={promptId:r.promptId,ts:o.ts,question:r.question||null},await xe()}async function XP(t,e,n){let r=n.payload||{};if(!e.prompt||r.promptId&&e.prompt.promptId!==r.promptId)return;let{ts:o,question:s}=e.prompt;delete e.prompt,await xe(),await Nr(t.botToken,{channel:e.channel,ts:o,text:"answered",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${X(s||"question")}~
457
- \u2713 _answered_`}}]})}async function ZP(t,e,n){let r=n.payload||{};if(!r.offerId||e.offers?.[r.offerId])return;let o=(i,c,l)=>({type:"button",action_id:"bostrat-ship",text:{type:"plain_text",text:c},value:JSON.stringify({trackId:n.trackId,offerId:r.offerId,action:i}),...l?{style:l}:{}}),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")],a=await Kn(t,e,r.excerpt||"Ship it?",[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${X(Sa(r.excerpt||"The lead offered to ship.",300))}`}},{type:"actions",elements:s}]);e.offers=e.offers||{},e.offers[r.offerId]=a.ts,await xe()}async function QP(t,e,n){let r=n.payload||{},o=e.offers?.[r.offerId];if(!o)return;delete e.offers[r.offerId],await xe();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 Nr(t.botToken,{channel:e.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function tN(t,e,n){let r=n.payload||{};if(!r.offerId||e.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 Kn(t,e,`PR ${o} already open \u2014 push or new PR?`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${o}${r.branch?` (${X(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")]}]);e.offers=e.offers||{},e.offers[r.offerId]=a.ts,await xe()}async function eN(t,e,n){let r=n.payload||{},o=e.offers?.[r.offerId];if(!o)return;delete e.offers[r.offerId],await xe();let s=r.choice==="dismiss"?"dismissed":r.choice==="new"?"\u2713 opening a new PR":"\u2713 pushing to the open PR";await Nr(t.botToken,{channel:e.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function nN(t,e,n,r){let o=n.payload||{};if(o.change==="ready"&&o.mockId){let s=await(r.readMockPng??rN)(o.mockId,o.version??null);if(!s)return;let a=(o.version??1)>1?` (v${o.version})`:"";await Ox(t.botToken,{filename:s.filename,buffer:s.buffer,title:`${o.name}${a}`,channelId:e.channel,threadTs:e.ts,initialComment:`\u{1F3A8} mock *${X(o.name)}*${a}${o.group?` (group \`${X(o.group)}\`)`:""}`})}else if(o.change==="picked"){let s=(o.siblings??[]).map(a=>`*${X(a.name)}*`).join(", ");await Kn(t,e,`Design decision: ${o.name} picked`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F3A8} design decision: *${X(o.name)}* picked${s?` over ${s}`:""}`}}])}}async function rN(t,e){let n=await en(t);if(!n)return null;let r=ke(n,e);if(!r)return null;let o=await xa.readFile(le(n,r.v).png).catch(()=>null);return o?{filename:`${n.name.replace(/[^\w.-]+/g,"-")}.v${r.v}.png`,buffer:o}:null}async function oN(t,e){if(!zP.has(e.type))return;let n=await Hp(e.trackId);if(!n)return;let r=await Cr();if(!r)return;let o=e.payload||{};switch(e.type){case"turn.user":if(n.kickoff||e.actor!=="user"||!o.text)return;n.kickoff=o.text,await xe(),await Fp(r,n);return;case"turn.agent":{if(!o.text)return;let s=MP(o.text);if(!s)return;await Kn(r,n,s,[{type:"section",text:{type:"mrkdwn",text:X(s)}},{type:"context",elements:[{type:"mrkdwn",text:`<${Fc(e.trackId)}|full turn \u2192>`}]}]);return}case"prompt.raised":return YP(r,n,e);case"prompt.answered":return XP(r,n,e);case"pr.offered":return ZP(r,n,e);case"pr.offer.answered":return QP(r,n,e);case"pr.exists.offered":return tN(r,n,e);case"pr.exists.answered":return eN(r,n,e);case"pr.state.changed":{if(o.change!=="opened"&&o.change!=="merged")return;let s=o.change==="opened"?"PR opened":"PR merged";await Kn(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 xe(),await Fp(r,n);return;case"view.state.changed":{if(o.change!=="created"||o.restarted||!o.slug)return;await Kn(r,n,`Live preview ${o.name}: ${Uc(o.slug)}`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F50D} live preview *${X(o.name)}*: ${Uc(o.slug)}
458
- _runs on the Track's branch; reachable on the operator's private network only_`}}]);return}case"mock.state.changed":return nN(r,n,e,t.deps)}}function jx(t){let e={deps:t};Yt.on("event",s=>{oN(e,s).catch(()=>{})});let n=null,r=null,o=async()=>{n||!await Cr()||(r&&clearInterval(r),r=null,n=Cx({getToken:async()=>(await Cr())?.appToken,onEnvelope:VP(e),log:s=>console.log(`[slack] ${s}`)}))};return r=setInterval(()=>o().catch(()=>{}),3e4),r.unref?.(),o().catch(()=>{}),()=>{r&&clearInterval(r),n?.()}}we();ct();We();Pd();Es();import sN from"node:fs/promises";function aN(t){let e=new Map;for(let n of String(t||"").split(`
459
- `)){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;i&&e.set(i,{messageId:i,tokens:a,model:o.message?.model||o.model||null})}return[...e.values()]}function iN(t){let e=new Set;for(let n of t)if(n.type==="cost.recorded"){n.payload?.messageId&&e.add(n.payload.messageId);for(let r of n.payload?.messageIds||[])e.add(r)}return e}var cN=new Set(["Write","Edit","NotebookEdit"]),lN=220,uN=160;function dN(t,e){let n=t?.tool_name??null,r={tool:n},o=t?.tool_input;if(!o||typeof o!="object")return r;if(cN.has(n)&&typeof o.file_path=="string"&&o.file_path){let s=o.file_path,a=e?.cwd;a&&s.startsWith(`${a}/`)&&(s=s.slice(a.length+1)),r.path=s.slice(0,lN)}else n==="Bash"&&typeof o.command=="string"&&o.command.trim()&&(r.head=nr(o.command.trim().replace(/\s+/g," ")).slice(0,uN));return r}function fN(t,e){return t?.transcript_path?t.transcript_path:e?.cwd&&e?.sessionId?qe(e.cwd,e.sessionId):e?.cwd?Yl(e.cwd):null}async function Lx(t,e){let n=await e(t?.session_id,t?.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 I(r,{...s,...c}))};switch(t?.hook_event_name){case"SessionStart":await i({type:"session.ready",actor:"system",payload:{sessionId:t.session_id}});break;case"UserPromptSubmit":{let c=String(t.prompt??t.user_prompt??""),l=Zi(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:dN(t,o)});break;case"Stop":await pN(r,o,t,i);break;default:break}return a}async function pN(t,e,n,r){let o=[],s=fN(n,e);if(s)try{o=aN(await sN.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??e?.model??null,messageId:a?.messageId??null}}),!o.length)return;let i=iN(await L(t)),c=o.filter(u=>!i.has(u.messageId));if(c.length){let u=new Map;for(let d of c){let f=d.model||"unknown",p=u.get(f)||{tokens:{input:0,output:0,cacheWrite:0,cacheRead:0},messageIds:[]};for(let m of Object.keys(p.tokens))p.tokens[m]+=d.tokens[m];p.messageIds.push(d.messageId),u.set(f,p)}for(let[d,f]of u)await r({type:"cost.recorded",actor:"system",source:"transcript",payload:{model:d,usd:In(d,f.tokens),tokens:f.tokens,messageId:f.messageIds[f.messageIds.length-1],messageIds:f.messageIds,apiCalls:f.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}})}Zo();ct();Bi();import wN from"node:fs";import qp from"node:fs/promises";import gN from"node:http";import Fo from"node:path";import Vc from"node:os";import{createRequire as yN}from"node:module";import Kp from"ws";import mN from"node:path";import hN from"node:os";var va=process.env.BOSTRAT_STATE_DIR||mN.join(process.env.HOME||hN.tmpdir(),".bostrat");function Wp(t=process.env){let e=(t.BOSTRAT_HOST||"").trim();if(e!=="all")return e||(t.BOSTRAT_PLANE_URL?"127.0.0.1":void 0)}function Fx(t=process.env){if(!t.BOSTRAT_PLANE_URL)return null;let e=Wp(t);return e==="127.0.0.1"||e==="::1"||e==="localhost"?null:{host:e}}function Ux(t){let e=String(t||"").trim();if(!e)return"";let n=/^[a-z][a-z0-9+.-]*:\/\//i.test(e)?e:`wss://${e}`,r;try{r=new URL(n)}catch{return e}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()):e}var Kc=(()=>{try{return yN(import.meta.url)("../package.json").version||null}catch{return null}})(),bN=process.env.BOSTRAT_STATE_DIR||Fo.join(process.env.HOME||Vc.tmpdir(),".bostrat");function kN(t,e){let n=String(t).split(".").map(Number),r=String(e).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 xN({home:t=process.env.HOME||Vc.homedir(),env:e=process.env}={}){let n=r=>{try{return wN.statSync(r),!0}catch{return!1}};return{claude:n(Fo.join(t,".claude",".credentials.json")),codex:n(Fo.join(e.CODEX_HOME||Fo.join(t,".codex"),"auth.json"))}}var Nt=1,Hx=1e3,SN=3e4,vN=6e4,TN=1500,AN=500,Gc=100,EN=2e3,_N=25e3,IN=6e4,RN=6e4,$N=6e4;function Wx({url:t,token:e,nodeId:n=Vc.hostname(),name:r=Vc.hostname(),listTracks:o,detectAgents:s=null,sampleMetrics:a=null,metricsMs:i=RN,selfUrl:c=`http://127.0.0.1:${process.env.PORT||3362}`,log:l=console}){if(!t||!e)throw new Error("plane-link: url and token are required");if(typeof o!="function")throw new Error("plane-link: listTracks is required");t=Ux(t);let u=c.replace(/^http/,"ws"),d=new Map,f=new Map,p=Fo.join(bN,"plane-link","cursor.json"),m={},w={},y=new Map,k=null,S=!1,$=!1,R=Hx,J=null,C=null,D=null,A=null,N=null,W=!1,at=0;async function it(){try{m=JSON.parse(await qp.readFile(p,"utf8"))}catch{m={}}}function E(){W=!0,!D&&(D=setTimeout(async()=>{if(D=null,!!W){W=!1;try{await qp.mkdir(Fo.dirname(p),{recursive:!0}),await qp.writeFile(p,JSON.stringify(m))}catch(K){l.error("[plane-link] cursor flush failed:",K?.message||K)}}},EN),D.unref?.())}function O(K){return!k||k.readyState!==Kp.OPEN?!1:(k.send(JSON.stringify(K)),!0)}function At(K){let b=Date.now();for(let{trackId:v,event:P}of K){let mt=y.get(P.id);y.set(P.id,{trackId:v,seq:P.seq,event:P,sentAt:b,tries:(mt?.tries??0)+1})}return O({v:Nt,ch:"events",type:"append",events:K})}function Gt(K){let b=null;for(let v of y.values())v.trackId===K&&(b==null||v.seq<b)&&(b=v.seq);return b}function gt(K){let b=w[K];if(b==null)return;let v=Gt(K),P=v==null?b:Math.min(b,v-1);P>(m[K]??0)&&(m[K]=P,E())}function g(){if(!S)return;let K=Date.now(),b=[...y.values()].filter(v=>v.event&&K-v.sentAt>=IN);if(b.length){b.sort((v,P)=>v.trackId===P.trackId?v.seq-P.seq:v.trackId<P.trackId?-1:1),l.log(`[plane-link] re-sending ${b.length} unacked event(s) the plane never confirmed`);for(let v=0;v<b.length;v+=Gc){let P=b.slice(v,v+Gc).map(mt=>({trackId:mt.trackId,event:mt.event}));if(!At(P))return}}}async function h(){if(!a)return;let K;try{K=await a()}catch(b){l.error("[plane-link] metrics sample failed:",b?.message||b);return}K&&O({v:Nt,ch:"ctl",type:"metrics",metrics:K})}function T(){a&&(N&&clearInterval(N),h(),N=setInterval(h,i),N.unref?.())}async function _(){let K;try{K=await o()}catch(b){l.error("[plane-link] backfill listTracks failed:",b?.message||b);return}O({v:Nt,ch:"ctl",type:"tracks",ids:K.map(b=>b.id).filter(b=>typeof b=="string")});for(let b of K){if(!S)return;let v;try{v=await L(b)}catch{continue}let P=m[b.id]??0,mt=v.filter(rt=>rt.seq>P&&typeof rt.id=="string");for(let rt=0;rt<mt.length;rt+=Gc){let Ot=mt.slice(rt,rt+Gc).map(oe=>({trackId:b.id,event:oe}));if(!At(Ot))return}}}function St(K){!S||!K?.trackId||typeof K.id!="string"||At([{trackId:K.trackId,event:K}])}let nt=new Map;async function dt(K){let{reqId:b,method:v,path:P,headers:mt={},body:rt}=K,Ot=Object.fromEntries(Object.entries(mt).filter(([,Te])=>Te!=null)),oe=new AbortController;nt.set(b,oe);try{if(K.host){await Jo(K,Ot,oe);return}let Te=await fetch(c+P,{method:v,headers:Ot,body:rt?Buffer.from(rt,"base64"):void 0,signal:oe.signal}),pn=Object.fromEntries(Te.headers);for(let se of["connection","keep-alive","transfer-encoding","upgrade","content-encoding","content-length"])delete pn[se];if(pn["content-type"]||(pn["content-type"]="application/octet-stream"),O({v:Nt,ch:"control",type:"http_head",reqId:b,status:Te.status,headers:pn}),Te.body){for await(let se of Te.body)if(!O({v:Nt,ch:"control",type:"http_data",reqId:b,data:Buffer.from(se).toString("base64")}))break}O({v:Nt,ch:"control",type:"http_end",reqId:b,error:null})}finally{nt.delete(b)}}function Jo(K,b,v){let{reqId:P,method:mt,path:rt,body:Ot}=K,oe=new URL(c);return new Promise(Te=>{let pn=gN.request({host:oe.hostname,port:oe.port,method:mt,path:rt,headers:{...b,host:K.host},signal:v.signal},se=>{let{connection:N1,"keep-alive":B1,"transfer-encoding":D1,upgrade:j1,...Nv}=se.headers;O({v:Nt,ch:"control",type:"http_head",reqId:P,status:se.statusCode||502,headers:Nv}),se.on("data",Bv=>{O({v:Nt,ch:"control",type:"http_data",reqId:P,data:Buffer.from(Bv).toString("base64")})||se.destroy()}),se.on("end",()=>{O({v:Nt,ch:"control",type:"http_end",reqId:P,error:null}),Te()}),se.on("error",()=>{O({v:Nt,ch:"control",type:"http_end",reqId:P,error:"view upstream error"}),Te()})});pn.on("error",se=>{O({v:Nt,ch:"control",type:"http_end",reqId:P,error:se?.message||"view request failed"}),Te()}),Ot&&pn.write(Buffer.from(Ot,"base64")),pn.end()})}function Bt(){if($)return;k=new Kp(t,{headers:{authorization:`Bearer ${e}`}}),k.on("open",async()=>{let b=null;try{b=await s?.()||null}catch{b=null}O({v:Nt,ch:"ctl",type:"hello",nodeId:n,name:r,platform:process.platform,version:Kc,providers:xN(),...b?{agents:b}:{}})}),k.on("message",b=>{let v;try{v=JSON.parse(b)}catch{return}if(v.ch==="ctl"&&v.type==="hello_ok"){S=!0,R=Hx,J=null,l.log(`[plane-link] connected to plane as ${n}`),v.minNodeVersion&&Kc&&kN(Kc,v.minNodeVersion)&&l.error(`[plane-link] this node is bostrat-node ${Kc}; the plane asks for \u2265${v.minNodeVersion} \u2014 update with: npm install -g bostrat-node`),A&&clearInterval(A),A=setInterval(()=>{O({v:Nt,ch:"ctl",type:"ping"}),g()},_N),A.unref?.(),T(),_().catch(P=>l.error("[plane-link] backfill failed:",P?.message||P));return}if(v.ch==="ctl"&&v.type==="usage_caps"){Ni(v.caps??{},{source:"plane",updatedAt:v.updatedAt??Date.now()}).then(P=>l.log(`[plane-link] spend caps ${Object.keys(P.caps).length?`updated (${Object.keys(P.caps).join(", ")})`:"cleared"} from plane`)).catch(P=>l.error("[plane-link] spend-caps push rejected:",P?.message||P));return}if(v.ch==="events"&&v.type==="ack"&&Array.isArray(v.ids)){let P=new Set;for(let mt of v.ids){let rt=y.get(mt);rt&&(y.delete(mt),(w[rt.trackId]??0)<rt.seq&&(w[rt.trackId]=rt.seq),P.add(rt.trackId))}for(let mt of P)gt(mt);return}if(v.ch==="control"&&v.type==="http_open"){dt(v).catch(P=>O({v:Nt,ch:"control",type:"http_end",reqId:v.reqId,error:P?.message||"tunnel error"}));return}if(v.ch==="control"&&v.type==="http_cancel"){nt.get(v.reqId)?.abort();return}if(v.ch==="attach"&&v.type==="open"){let P=new Kp(u+v.path,Array.isArray(v.protocols)?v.protocols:[],v.host?{headers:{host:v.host}}:void 0);d.set(v.streamId,P),f.set(v.streamId,[]),P.on("open",()=>{let rt=f.get(v.streamId)||[];f.delete(v.streamId);for(let{buf:Ot,bin:oe}of rt)P.send(Ot,{binary:oe})}),P.on("message",(rt,Ot)=>{let oe=Ot?rt:Buffer.from(String(rt));O({v:Nt,ch:"attach",type:"data",streamId:v.streamId,data:oe.toString("base64"),...Ot?{bin:!0}:{}})});let mt=()=>{f.delete(v.streamId),d.delete(v.streamId)&&O({v:Nt,ch:"attach",type:"close",streamId:v.streamId})};P.on("close",mt),P.on("error",mt);return}if(v.ch==="attach"&&v.type==="data"){let P=d.get(v.streamId);if(!P)return;let mt=Buffer.from(v.data,"base64"),rt=v.bin===!0,Ot=f.get(v.streamId);Ot?Ot.push({buf:mt,bin:rt}):P.send(mt,{binary:rt});return}if(v.ch==="attach"&&v.type==="close"){let P=d.get(v.streamId);d.delete(v.streamId),f.delete(v.streamId),P?.close();return}});let K=()=>{S&&l.log("[plane-link] disconnected from plane"),S=!1,A&&(clearInterval(A),A=null),N&&(clearInterval(N),N=null),y.clear(),w={};for(let P of d.values())P.close();d.clear(),f.clear();for(let P of nt.values())P.abort();if(nt.clear(),$||C)return;J==null&&(J=Date.now());let b=Date.now()-J<vN,v=b?TN+Math.random()*AN:R;C=setTimeout(()=>{C=null,Bt()},v),C.unref?.(),b||(R=Math.min(R*2,SN))};k.on("close",K),k.on("error",b=>{let v=/Unexpected server response: (\d+)/.exec(b?.message||"")?.[1];(v==="401"||v==="403")&&Date.now()-at>=$N&&(at=Date.now(),l.error(`[plane-link] plane refused this node's credentials (HTTP ${v}) \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)`)),K()})}return Yt.on("event",St),it().then(Bt),{stop:()=>{$=!0,Yt.off("event",St),C&&clearTimeout(C),D&&clearTimeout(D),A&&clearInterval(A),N&&clearInterval(N),O({v:Nt,ch:"ctl",type:"bye",reason:"shutdown"}),k?.close()},status:()=>({connected:S,nodeId:n,cursor:{...m},inflight:y.size})}}import ON from"node:fs";import qx from"node:fs/promises";import Ta from"node:os";import CN from"node:path";hf();Ht();var MN=1024*1024,zc=t=>Math.round(t/MN);async function PN(t){try{let e=await qx.statfs(t),n=e.blocks*e.bsize,r=n-e.bavail*e.bsize;return{diskUsedMb:zc(r),diskTotalMb:zc(n)}}catch{return{diskUsedMb:null,diskTotalMb:null}}}async function NN(){try{return(await he()).filter(e=>e.isBostrat).length}catch{return null}}async function BN(){let t=0,e=!1;for(let n of["workspaces","worktrees"])try{let r=await qx.readdir(CN.join(va,n),{withFileTypes:!0});t+=r.filter(o=>o.isDirectory()).length,e=!0}catch{}return e?t:null}async function Kx({stateDir:t=va,now:e=Date.now}={}){let n=Ta.totalmem(),[r,o,s,a]=await Promise.all([fc().catch(()=>null),PN(ON.existsSync(t)?t:Ta.tmpdir()),NN(),BN()]),i=Ta.cpus()?.length||null,c=Ta.loadavg()?.[0]??null;return{ts:e(),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?zc(n-r):null,memTotalMb:zc(n),...o,boxes:s,worktrees:a,procUptimeS:Math.round(process.uptime()),osUptimeS:Math.round(Ta.uptime())}}ct();cu();Ya();ct();ur();function Gp(t){let e={};for(let n of t.boxes||[]){let r=n.role&&n.role!=="lead"?` \xB7 ${n.role}`:"";e[n.name]=`${n.name} (${n.agent||"?"}${r})`}return e}var Gx=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),Vx=(t,e)=>{for(let n of Object.keys(t))t[n]+=e?.[n]||0},Jc=t=>Math.round(t*1e4)/1e4;async function zx(t){let e=[],n={},r={},o=0,s=0,a=0,i=0,c=0,l=new Set,u=Gx(),d=0,f=[];for(let p of t||[]){let m=await L(p),w=Rn(m,{boxLabels:Gp(p)});if(w.turns===0){p.archivedAt?d++:f.push(p.name||p.id);continue}o+=w.totalUsd,s+=w.turns,a+=w.repricedTurns||0,i+=w.asRecordedUsd||0,c+=w.unpricedTurns||0;for(let y of w.unpricedModels||[])l.add(y);Vx(u,w.totalTokens);for(let[y,k]of Object.entries(w.byModel))n[y]||={usd:0,events:0,tokens:Gx()},n[y].usd=Jc(n[y].usd+k.usd),n[y].events+=k.events,Vx(n[y].tokens,k.tokens);for(let[y,k]of Object.entries(w.byProvider))r[y]||={usd:0,events:0},r[y].usd=Jc(r[y].usd+k.usd),r[y].events+=k.events;e.push({id:p.id,name:p.name,usd:w.totalUsd,rollup:w})}return e.sort((p,m)=>m.usd-p.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",fleet:{totalUsd:Jc(o),asRecordedUsd:Jc(i),turns:s,repricedTurns:a,unpricedTurns:c,unpricedModels:[...l],totalTokens:u,byModel:n,byProvider:r,tracksWithCost:e.length,tracksSilent:d+f.length,tracksSilentArchived:d,tracksSilentLive:f},tracks:e}}var Gn=t=>`$${t.toFixed(4)}`,Uo=(t,e)=>String(t).padEnd(e);function Jx(t){let{fleet:e,tracks:n}=t,r=[];r.push(`BOSTRAT COST READ-OUT \xB7 ${t.generatedAt}`),t.pricingBasis&&r.push(`basis: ${t.pricingBasis}`);let o=e.tracksSilentLive||[];r.push(`fleet total ${Gn(e.totalUsd)} over ${e.turns} turn(s) \xB7 ${e.tracksWithCost} track(s) with cost, ${e.tracksSilentArchived??e.tracksSilent} silent (archived)`+(o.length?`, ${o.length} LIVE with no cost data: ${o.join(", ")}`:"")),e.repricedTurns&&r.push(`${e.repricedTurns} turn(s) priced at current table rates (differs from as-recorded)`),e.asRecordedUsd!=null&&Math.abs(e.asRecordedUsd-e.totalUsd)>=.005&&r.push(`as-recorded total ${Gn(e.asRecordedUsd)} \xB7 current-rates total ${Gn(e.totalUsd)} (${e.totalUsd>=e.asRecordedUsd?"+":""}${Gn(e.totalUsd-e.asRecordedUsd)})`),e.unpricedTurns&&r.push(`\u26A0 ${e.unpricedTurns} turn(s) UNPRICED \u2014 total under-reports. Add PER_MTOK rate(s) for: ${(e.unpricedModels||[]).join(", ")}`),r.push(""),r.push("BY MODEL");let s=Object.entries(e.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(` ${Uo(a,26)} ${Uo(Gn(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(` ${Uo(a.name||a.id,30)} ${Gn(a.usd)}`);let i=Object.values(a.rollup.byBox).sort((c,l)=>l.usd-c.usd);for(let c of i)if(r.push(` ${Uo(c.label,40)} ${Uo(Gn(c.usd),10)} ${c.models.join(",")||"?"}`),c.epochs)for(let[l,u]of Object.entries(c.epochs).sort((d,f)=>Number(d[0])-Number(f[0])))r.push(` \u21B3 tenure ${l} (${u.provider||"?"})${" ".repeat(Math.max(1,24-String(u.provider||"?").length))}${Uo(Gn(u.usd),10)} ${u.models.join(",")||"?"}`)}return r.join(`
460
- `)}Ud();Bi();ct();vd();import UN from"node:fs/promises";import HN from"node:path";iu();ur();var Yc=t=>t.payload?.ts??t.ts,DN=12e4,Vn=t=>Math.round(t*1e4)/1e4,jN=()=>({usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},byTrack:new Map});function LN(t,{since:e}){let{track:n,events:r,brief:o}=t,s=S=>Yc(S)>=e,a=ir([ys(n?.name),ys(n?.workspace?.branch),o].filter(Boolean).join(" ")),i=new Map;for(let S of r)if(S.type==="subtask.delegated"&&S.boxId&&S.payload?.task){let $=ir(S.payload.task);$&&i.set(S.boxId,$)}let c=new Map,l=S=>{let $=S||"unattributed";return c.has($)||c.set($,{segments:[u(null)],lastTs:null,provider:null}),c.get($)},u=S=>({textCat:S,tools:{},usd:0,tokens:{input:0,output:0,cacheRead:0,cacheWrite:0},models:{},provider:null,activeMs:0,turns:0,toolCalls:0}),d=[...r].sort((S,$)=>Yc(S)-Yc($)),f=0,p=0,m=0,w={turns:0};for(let S of d){let $=l(S.boxId),R=$.segments[$.segments.length-1],J=Yc(S);switch($.lastTs!=null&&J>$.lastTs&&s(S)&&(R.activeMs+=Math.min(J-$.lastTs,DN)),$.lastTs=J,S.provider&&($.provider=S.provider),S.type){case"turn.user":{let C=S.payload?.text;if(S.source==="hook"||!String(C||"").trim())break;let D=u(ir(C));$.segments.push(D),s(S)&&(D.turns+=1);break}case"peer.message":{let C=S.payload?.text;if(!String(C||"").trim())break;let D=u(ir(C));$.segments.push(D),s(S)&&(D.turns+=1);break}case"tool.called":{if(S.source==="transcript")break;let C=S.payload?.tool;C&&(R.tools[C]=(R.tools[C]||0)+1),s(S)&&(R.toolCalls+=1);break}case"cost.recorded":{if(!s(S))break;let{usd:C,tokens:D,model:A,unpriced:N}=Ke(S);N&&(w.turns+=1),R.usd+=C,D&&(R.tokens.input+=D.input,R.tokens.output+=D.output,R.tokens.cacheRead+=D.cacheRead,R.tokens.cacheWrite+=D.cacheWrite),R.models[A]=(R.models[A]||0)+C,S.provider&&(R.provider=S.provider);break}case"handoff.done":s(S)&&(f+=1);break;case"subtask.merged":s(S)&&(p+=1);break;case"error":s(S)&&S.payload?.kind==="subtask-failed"&&(m+=1);break;default:break}}let y=new Map,k=!1;for(let[S,$]of c)for(let R of $.segments){if(!(R.usd>0||R.activeMs>0||R.turns>0||R.toolCalls>0))continue;let C=R.textCat?.category??i.get(S)?.category??Kh(R.tools)?.category??a?.category??"uncategorized";y.has(C)||y.set(C,{usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{}});let D=y.get(C);D.usd+=R.usd,D.activeMs+=R.activeMs,D.turns+=R.turns,D.toolCalls+=R.toolCalls;for(let[N,W]of Object.entries(R.models))D.models[N]=(D.models[N]||0)+W;let A=R.provider||$.provider;A&&(D.providers[A]=(D.providers[A]||0)+R.usd),A==="cursor"&&R.usd===0&&(k=!0)}return{perCategory:y,handoffs:f,merged:p,failed:m,sawCursorActivity:k,unpricedTurns:w.turns}}function Xx(t,{windowMs:e=null,now:n=Date.now()}={}){let r=e==null?0:n-e,o=new Map,s=[],a=0,i=!1,c=0;for(let w of t||[]){let{track:y,events:k}=w;if(!k?.length){a+=1;continue}let{perCategory:S,handoffs:$,merged:R,failed:J,sawCursorActivity:C,unpricedTurns:D}=LN(w,{since:r});C&&(i=!0),c+=D;let A={trackId:y?.id,name:y?.name||y?.id,archived:!!y?.archivedAt,usd:0,activeMs:0,turns:0,categories:{},models:{},providers:{},handoffs:$,subtasksMerged:R,subtasksFailed:J};for(let[N,W]of S){A.usd+=W.usd,A.activeMs+=W.activeMs,A.turns+=W.turns,A.categories[N]={usd:Vn(W.usd),activeMs:W.activeMs};for(let[E,O]of Object.entries(W.models))A.models[E]=Vn((A.models[E]||0)+O);for(let[E,O]of Object.entries(W.providers))A.providers[E]=Vn((A.providers[E]||0)+O);o.has(N)||o.set(N,jN());let at=o.get(N);at.usd+=W.usd,at.activeMs+=W.activeMs,at.turns+=W.turns,at.toolCalls+=W.toolCalls;for(let[E,O]of Object.entries(W.models))at.models[E]=(at.models[E]||0)+O;for(let[E,O]of Object.entries(W.providers))at.providers[E]=(at.providers[E]||0)+O;let it=at.byTrack.get(y?.id)||{usd:0,activeMs:0};it.usd+=W.usd,it.activeMs+=W.activeMs,at.byTrack.set(y?.id,it)}(A.usd>0||A.activeMs>0||A.turns>0)&&(A.usd=Vn(A.usd),A.dominantCategory=FN(A.categories),s.push(A))}let l=[...o.values()].reduce((w,y)=>w+y.usd,0),u=[...o.values()].reduce((w,y)=>w+y.activeMs,0),d=l>0?"usd":"time",f=d==="usd"?l:u,p=new Map((t||[]).map(w=>[w.track?.id,w.track?.name||w.track?.id])),m=[...o.entries()].map(([w,y])=>({category:w,sharePct:f>0?Math.round((d==="usd"?y.usd:y.activeMs)/f*100):0,shareBasis:d,usd:Vn(y.usd),activeMs:y.activeMs,turns:y.turns,toolCalls:y.toolCalls,models:Yx(y.models),providers:Yx(y.providers),topWorkstreams:[...y.byTrack.entries()].sort((k,S)=>S[1].usd-k[1].usd||S[1].activeMs-k[1].activeMs).slice(0,2).map(([k,S])=>({trackId:k,name:p.get(k),usd:Vn(S.usd),activeMs:S.activeMs}))})).sort((w,y)=>y.usd-w.usd||y.activeMs-w.activeMs);return s.sort((w,y)=>y.usd-w.usd||y.activeMs-w.activeMs),{since:r,capturedAt:n,totalUsd:Vn(l),activeMs:u,turns:[...o.values()].reduce((w,y)=>w+y.turns,0),bullets:m,workstreams:s,gaps:{tracksWithoutEvents:a,cursorCostUnknown:i,unpricedTurns:c}}}var FN=t=>{let e=null;for(let[n,r]of Object.entries(t))(!e||r.usd>e.v.usd||r.usd===e.v.usd&&r.activeMs>e.v.activeMs)&&(e={cat:n,v:r});return e?.cat??null},Yx=t=>Object.fromEntries(Object.entries(t).map(([e,n])=>[e,Vn(n)]));var Ho={"24h":24*36e5,"7d":168*36e5,"30d":720*36e5,all:null};function WN(t){let e=String(t||"7d");return e in Ho?{key:e,ms:Ho[e]}:{key:"7d",ms:Ho["7d"]}}function qN(t,e){let n=new Set((e||[]).filter(o=>o.source==="orchestrator").map(o=>`${o.type}|${o.payload?.ts??"?"}`)),r=[...e||[]];for(let o of t?.events||[]){let s=Li(o);!s||n.has(`${s.type}|${s.payload?.ts??"?"}`)||r.push({trackId:t.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 KN(t){if(!t?.cwd)return null;try{let n=(await UN.readFile(HN.join(t.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 Zx(t,{window:e="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}:WN(e),d=[];for(let f of t||[]){let p=await L(f),m=qN(f,p);i&&c<o&&(m=m.filter(w=>(w.ts??0)<=c)),d.push({track:f,events:m,brief:await KN(f)})}return{window:l,...Xx(d,{windowMs:u,now:c})}}ct();ur();var zn=36e5,nS=24*zn,GN=400,VN=12,Wo=t=>Math.round(t*1e4)/1e4;function zN({window:t,from:e,to:n,now:r=Date.now()}={}){let o=Number(e),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(t||"7d")in Ho?String(t||"7d"):"7d",i=Ho[a];return{key:a,since:i==null?null:r-i,until:r}}var JN=(t,e)=>t!=null&&e-t<=48*zn?zn:nS;function Qx(t,e){if(e===zn)return Math.floor(t/zn)*zn;let n=new Date(t);return n.setHours(0,0,0,0),n.getTime()}function YN(t,e){if(e===zn)return t+zn;let n=new Date(t);return n.setDate(n.getDate()+1),n.setHours(0,0,0,0),n.getTime()}var tS=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),eS=(t,e)=>{for(let n of Object.keys(t))t[n]+=e?.[n]||0},XN=t=>Object.fromEntries(Object.entries(t).map(([e,n])=>[e,Wo(n)]));async function rS(t,e={}){let n=e.now??Date.now(),r=zN({...e,now:n}),o=r.since==null?nS:JN(r.since,r.until),s=A=>(r.since==null||A>=r.since)&&A<r.until,a=r.since!=null?r.until-r.since:null,i=A=>a!=null&&A>=r.since-a&&A<r.since,c={},l={},u=tS(),d=0,f=0,p=0,m=0,w=0,y=new Set,k=new Map,S=[],$=[],R=[],J=null;for(let A of t||[]){let W=(await L(A)).filter(E=>E.type==="cost.recorded");if(!W.length){A.archivedAt||R.push(A.name||A.id);continue}let at=[];for(let E of W){let O=E.ts??0;s(O)?at.push(E):i(O)&&(w+=Ke(E).usd)}if(!at.length)continue;let it=Rn(at,{boxLabels:Gp(A)});d+=it.totalUsd,f+=it.turns,p+=it.repricedTurns||0,m+=it.unpricedTurns||0;for(let E of it.unpricedModels||[])y.add(E);eS(u,it.totalTokens);for(let[E,O]of Object.entries(it.byModel))c[E]||={usd:0,events:0,tokens:tS()},c[E].usd=Wo(c[E].usd+O.usd),c[E].events+=O.events,eS(c[E].tokens,O.tokens);for(let[E,O]of Object.entries(it.byProvider))l[E]||={usd:0,events:0},l[E].usd=Wo(l[E].usd+O.usd),l[E].events+=O.events;for(let E of at){let{usd:O}=Ke(E);if(!O)continue;let At=Qx(E.ts??0,o),Gt=k.get(At)??{t:At,total:0,byProvider:{}};Gt.total+=O;let gt=E.provider||"unknown";Gt.byProvider[gt]=(Gt.byProvider[gt]||0)+O,k.set(At,Gt),(J==null||At<J)&&(J=At)}S.push({id:A.id,name:A.name||A.id,archived:!!A.archivedAt,usd:it.totalUsd,turns:it.turns,providers:Object.keys(it.byProvider)});for(let[E,O]of Object.entries(it.byBox))$.push({trackId:A.id,trackName:A.name||A.id,boxId:E,...O})}let C=r.since!=null?Qx(r.since,o):J,D=[];for(let A=C,N=0;A!=null&&A<r.until&&N<GN;A=YN(A,o),N++){let W=k.get(A);D.push(W?{t:A,total:Wo(W.total),byProvider:XN(W.byProvider)}:{t:A,total:0,byProvider:{}})}return S.sort((A,N)=>N.usd-A.usd),$.sort((A,N)=>N.usd-A.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",window:r.key,since:r.since,until:r.until,bucketMs:o,series:D,fleet:{totalUsd:Wo(d),turns:f,repricedTurns:p,unpricedTurns:m,unpricedModels:[...y],totalTokens:u,byModel:c,byProvider:l,tracksWithCost:S.length,tracksSilentLive:R},prior:a!=null?{totalUsd:Wo(w),since:r.since-a,until:r.since}:null,tracks:S.slice(0,50),boxes:$.slice(0,VN)}}Qt();import qo from"node:fs/promises";import ZN from"node:fs";import Lt from"node:path";import QN from"node:os";import{execFile as tB}from"node:child_process";import{promisify as eB}from"node:util";var nB=eB(tB),oS=process.env.BOSTRAT_STATE_DIR||Lt.join(process.env.HOME||QN.tmpdir(),".bostrat"),Xc=!1,Vp=null;async function zp(t,e){let n=await qo.stat(t).catch(()=>null);if(!n?.isFile())return!1;let r=await qo.stat(e).catch(()=>null);return r&&r.size===n.size&&r.mtimeMs>=n.mtimeMs?!1:(await qo.mkdir(Lt.dirname(e),{recursive:!0}),await qo.copyFile(t,e),!0)}var rB=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 Zc(t,e,{skip:n=null}={}){let r=0,o=await qo.readdir(t,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(rB.has(s.name)||n?.has(s.name))continue;let a=Lt.join(t,s.name);s.isDirectory()?r+=await Zc(a,Lt.join(e,s.name)):s.isFile()&&(r+=await zp(a,Lt.join(e,s.name))?1:0)}return r}async function sS({stateDir:t=oS,dest:e=process.env.BOSTRAT_SYNC_DIR||`${oS}-sync`,remote:n=process.env.BOSTRAT_STATE_REMOTE||null,tracks:r=null}={}){try{await qo.mkdir(e,{recursive:!0});let o=0;o+=await zp(Lt.join(t,"tracks.json"),Lt.join(e,"tracks.json"))?1:0,o+=await zp(Lt.join(t,"events.jsonl"),Lt.join(e,"events.jsonl"))?1:0,o+=await Zc(Lt.join(t,"events"),Lt.join(e,"events")),o+=await Zc(Lt.join(t,"memory"),Lt.join(e,"memory"));let s=new Set(["mocks"]);for(let u of r||[])!u?.cwd||!u?.id||(o+=await Zc(Lt.join(u.cwd,".bostrat"),Lt.join(e,"workspaces",u.id,".bostrat"),{skip:s}));let a=(...u)=>nB("git",["-C",e,...u]);ZN.existsSync(Lt.join(e,".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 Al(e).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||Xc))try{await a("push","-q",n,"HEAD:refs/heads/main"),l=!0,Xc&&console.log("[state-sync] push recovered \u2014 off-box copy is current again"),Xc=!1,Vp=null}catch(u){Xc=!0;let d=(u?.stderr||u?.message||String(u)).trim().split(`
461
- `).slice(-3).join(" | ").slice(0,300);d!==Vp&&(Vp=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)}}}wd();ct();import{execFile as oB}from"node:child_process";import{promisify as sB}from"node:util";var aB=sB(oB),iB=12e4,cB=6e4;function lB(t){return`refs/bostrat/wip/${t}`}function cS(t=process.env){let e=String(t.BOSTRAT_WIP_SYNC_MS??"").trim().toLowerCase();return e!=="0"&&e!=="off"&&e!=="false"}function uB(t=process.env){let e=Number(t.BOSTRAT_WIP_SYNC_MS);return Number.isFinite(e)&&e>0?e:iB}var Qc=(t,e,n=15e3)=>aB("git",["-C",t,...e],{timeout:n,maxBuffer:4*1024*1024}),aS=new Map,iS=new Set;async function dB(t,{log:e=console}={}){let{id:n,cwd:r}=t??{};if(!n||!r)return{pushed:!1,reason:"no-workspace"};try{await Qc(r,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await Qc(r,["remote","get-url","origin"])}catch{return iS.has(r)||(iS.add(r),e.log?.(`[wip-sync] ${n}: no origin remote \u2014 durable code fidelity is chat/memory-only for this Track`)),{pushed:!1,reason:"no-origin"}}try{let o=await Rs(r,"bostrat: wip snapshot"),{stdout:s}=await Qc(r,["rev-parse",`${o}^{tree}`]),a=s.trim();if(aS.get(r)===a)return{pushed:!1,reason:"unchanged"};let i=lB(n);return await Qc(r,["push","--force","origin",`${o}:${i}`],cB),aS.set(r,a),await I({id:n,cwd:r},{type:"code.pushed",actor:"orchestrator",payload:{ref:i,sha:o,wip:!0,ts:Date.now()}}).catch(()=>{}),e.log?.(`[wip-sync] ${n}: pushed ${o.slice(0,7)} \u2192 ${i}`),{pushed:!0,sha:o,ref:i}}catch(o){return e.log?.(`[wip-sync] ${n}: push failed (will retry): ${String(o?.message||o).split(`
462
- `)[0]}`),{pushed:!1,reason:"push-failed"}}}function lS({listTracks:t,sweepMs:e=uB(),log:n=console}){let r=!1,o=async()=>{if(!r){r=!0;try{let a=await t()??[];for(let i of a)i?.archivedAt||i?.kind==="setup"||await dB(i,{log:n})}catch(a){n.log?.(`[wip-sync] sweep failed: ${a?.message||a}`)}finally{r=!1}}},s=setInterval(o,e);return s.unref?.(),o(),{stop:()=>clearInterval(s),cycle:o}}we();Qr();Ht();Qo();import{execFile as fB}from"node:child_process";import{promisify as pB}from"node:util";import{randomUUID as mB}from"node:crypto";import hB from"node:fs";import wB from"node:os";import gB from"node:path";var Yn=pB(fB),tl=t=>new Promise(e=>setTimeout(e,t)),Xn=Wl,Jp=process.env.BOSTRAT_USAGE_PROBE_CWD||gB.join(wB.homedir(),".bostrat","usage-probe"),yB=Number(process.env.BOSTRAT_USAGE_IDLE_REAP_MS)||5*6e4,bB=Number(process.env.BOSTRAT_USAGE_PANEL_TIMEOUT_MS)||15e3,kB=Number(process.env.BOSTRAT_USAGE_READY_TIMEOUT_MS)||45e3,uS=Number(process.env.BOSTRAT_USAGE_CACHE_MS)||2e4,Jn=null,Aa=null,Ea=null;async function xB(){try{return await Yn(B,j("has-session","-t",Xn)),!0}catch{return!1}}function SB(){Jn&&clearTimeout(Jn),Jn=setTimeout(()=>vB().catch(()=>{}),yB),Jn.unref&&Jn.unref()}async function vB(){Jn&&(clearTimeout(Jn),Jn=null);try{await Yn(B,j("kill-session","-t",Xn))}catch{}}async function TB(){let t=Date.now()+kB;for(;;){let e=await Yp().catch(()=>"");if(/for agents|for shortcuts|bypass permissions on/i.test(e)){await tl(500);return}if(Date.now()>t)throw new Error("usage probe didn't reach the prompt (trust/onboarding may be blocking)");await tl(500)}}async function AB(){if(await xB())return;if(!await xn())throw new Error("host tmux server not running \u2014 start globo-tmux.service");hB.mkdirSync(Jp,{recursive:!0}),await mn(Jp);let t=mB();await Yn(B,j("new-session","-d","-s",Xn,"-c",Jp,"-x","200","-y","60",...Hl()));let e=`${Ul} --session-id ${t}`;await Yn(B,j("send-keys","-t",Xn,e,"Enter")),await TB()}async function Yp(){let{stdout:t}=await Yn(B,j("capture-pane","-t",Xn,"-p"));return t}async function EB(){await AB(),await Yn(B,j("send-keys","-t",Xn,"-l","/usage")),await Yn(B,j("send-keys","-t",Xn,"Enter"));let t=Date.now()+bB,e="";for(;await tl(400),e=await Yp(),!(/Current\s+(session|week)/i.test(e)||/\d+%\s*used/i.test(e)||Date.now()>t););return await tl(900),e=await Yp(),await Yn(B,j("send-keys","-t",Xn,"Escape")).catch(()=>{}),SB(),e}function _B(t){let e=String(t||"").split(`
463
- `).map(s=>s.replace(/\s+$/,"").trim()),n=s=>{let a=null,i=null;for(let c=s+1;c<Math.min(s+5,e.length)&&!/^Current\s/i.test(e[c]);c++){let l=e[c].match(/(\d+)%\s*used/i);l&&a===null&&(a=Number(l[1]));let u=e[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=e.findIndex(i=>s.test(i));return a<0?null:n(a)},o=[];return e.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 IB(t){let e=String(t||"").split(`
464
- `).map(s=>s.replace(/\s+$/,"")),n=e.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<e.length&&!r.test(e[s]);s++)e[s].trim()&&o.push(e[s].trim());return o.length?o:null}async function dS({fresh:t=!1}={}){return!t&&Aa&&Date.now()-Aa.at<uS?Aa.data:Ea||(Ea=(async()=>{try{let e=await EB(),n=_B(e),r={...n,contributors:IB(e),subscription:!!(n.session||n.week||n.weekModels),capturedAt:Date.now()};return Aa={at:Date.now(),data:r},r}catch(e){let n={session:null,week:null,contributors:null,subscription:!1,error:e?.message||String(e),capturedAt:Date.now()};return Aa={at:Date.now()-(uS-3e3),data:n},n}finally{Ea=null}})(),Ea)}var RB=262144;function $B(t){let e=Number(t);if(!Number.isFinite(e)||e<0)return null;let n=Math.floor(e/3600),r=Math.round(e%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 OB=new Set([300]),CB=new Set([10080]);function MB(t){let e=Number(t);return!Number.isFinite(e)||e<=0?null:OB.has(e)?"session":CB.has(e)?"week":"other"}function PB(t){let e=Number(t);return!Number.isFinite(e)||e<=0?"Window":e%1440===0?`Window \xB7 ${e/1440}d`:e%60===0?`Window \xB7 ${e/60}h`:`Window \xB7 ${e}m`}function NB(t,e,n){if(!t||typeof t!="object")return null;let r=Number(t.used_percent);if(!Number.isFinite(r))return null;let o=null,s=Number(t.resets_at),a=Number(t.resets_in_seconds);return Number.isFinite(s)&&s>0?o=s*1e3:Number.isFinite(a)&&a>=0&&(o=(Number.isFinite(e)?e:n)+a*1e3),{pct:Math.round(r),resets:o!=null?$B((o-n)/1e3):null,resetsAt:o}}var _a=t=>({session:null,week:null,other:null,planType:null,credits:null,limitReached:null,sawTokenCount:t});function BB(t,e=Date.now()){let n=String(t||"").split(`
465
- `),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 _a(r);if(c.primary||c.secondary){let l=Date.parse(a.timestamp)||null,u=_a(r);[c.primary,c.secondary].forEach((p,m)=>{let w=NB(p,l,e);if(!w)return;let y=MB(p.window_minutes);y===null&&(y=m===0?"session":"week"),y==="session"&&!u.session?u.session=w:y==="week"&&!u.week?u.week=w:(u.other??=[]).push({label:PB(p.window_minutes),...w})}),u.planType=typeof c.plan_type=="string"?c.plan_type:null;let f=c.credits;return f&&(f.has_credits||f.unlimited)&&(u.credits={balance:String(f.balance??""),unlimited:!!f.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{..._a(r),session:l(c.primary_used_percent),week:l(c.secondary_used_percent)}}return _a(r)}return _a(r)}async function Xp(t){let e={provider:"codex",supported:!0,contributors:null};try{let n=await cr(t?.cwd,t?.sessionId);if(!n)return{...e,session:null,week:null,subscription:!1,error:"no codex rollout found for this box yet",capturedAt:Date.now()};let r=await Jt(n.file,RB),o=BB(r);return{...e,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{...e,session:null,week:null,subscription:!1,error:n?.message||String(n),capturedAt:Date.now()}}}async function fS(t,{fresh:e=!1}={}){let n=new Set;for(let o of t||[])for(let s of o.boxes||[])s.agent&&n.add(s.agent);let r=[];if((n.has("claude")||n.size===0)&&r.push(await el({agent:"claude"},{fresh:e})),n.has("codex")){let o=[],s=[...t||[]].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 Xp(i);if(c.subscription){a=c;break}(!a||a.error&&!c.error)&&(a=c)}r.push(a||await Xp(null))}return n.has("cursor")&&r.push(await el({agent:"cursor"})),{providers:r,capturedAt:Date.now()}}async function el(t,{fresh:e=!1}={}){let n=t?.agent||"claude";return n==="codex"?Xp(t):n==="cursor"?{provider:"cursor",supported:!1,subscription:!1,session:null,week:null,contributors:null,capturedAt:Date.now()}:{provider:"claude",supported:!0,...await dS({fresh:e})}}Qn();Qt();Qt();function DB(t=process.env){return!!(vt(t)&&t.BOSTRAT_PLANE_TOKEN)}var jB=t=>({authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`}),nl=(t,e)=>Object.assign(new Error(t),{status:e});async function pS(t,e){if(!DB(e))throw nl("node is not plane-linked \u2014 Gmail unavailable",503);let n;try{n=await fetch(`${vt(e)}${t}`,{headers:jB(e)})}catch(o){throw nl(`plane unreachable \u2014 Gmail unavailable (${o?.message||o})`,503)}let r=await n.json().catch(()=>({}));if(!n.ok)throw nl(r?.error||`plane replied ${n.status}`,n.status);return r}async function mS(t,{max:e=10,env:n=process.env}={}){let r=new URLSearchParams({q:t||""});return e&&r.set("max",String(e)),(await pS(`/v1/gmail/messages?${r.toString()}`,n)).messages||[]}async function hS(t,{env:e=process.env}={}){if(!t)throw nl("message id required",400);return(await pS(`/v1/gmail/messages/${encodeURIComponent(t)}`,e)).message}Cs();cc();function Zp(t){let e=t.split(".");if(e.length!==4)return null;let n=0;for(let r of e){let o=Number(r);if(!Number.isInteger(o)||o<0||o>255)return null;n=n*256+o}return n>>>0}function LB(t){let[e,n]=t.split("/"),r=Zp(e);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 wS(t){return(t||"").split(",").map(e=>e.trim()).filter(Boolean).map(LB).filter(Boolean)}function FB(t){let e=t.headers["fly-client-ip"];return typeof e=="string"&&e.trim()?e.trim():(t.socket&&t.socket.remoteAddress||"").replace(/^::ffff:/,"")}function gS(t){let e=wS(t),n=String(t||"").trim().toLowerCase()==="open";return{open:n,clientIp:FB,allowed(r){if(n)return!0;let o=Zp((r||"").replace(/^::ffff:/,""));return o==null?!1:e.some(s=>s(o))}}}function yS(t,e){let n=wS(t);return{active:n.length>0,allows(r){if(!n.length)return!1;let o=(r.socket&&r.socket.remoteAddress||"").replace(/^::ffff:/,""),s=Zp(o);if(s==null||!n.some(i=>i(s)))return!1;let a=e(r);return!!(a&&a.view)}}}import bS from"node:crypto";import rl from"node:fs";import UB from"node:path";function kS(t=process.env,{stateDir:e=va,log:n=console}={}){let r=String(t.BOSTRAT_NODE_API_TOKEN||"").trim();if(r)return r;let o=UB.join(e,"api-token");try{let a=rl.readFileSync(o,"utf8").trim();if(a)return a}catch{}let s=bS.randomBytes(32).toString("base64url");try{rl.mkdirSync(e,{recursive:!0}),rl.writeFileSync(o,s+`
466
- `,{mode:384}),rl.chmodSync(o,384)}catch(a){n.error?.(`[bostrat-agent] could not persist the node API token: ${a?.message||a}`)}return s}function Ia(t){let e=t?.socket?.remoteAddress||"";if(!e)return!1;let n=e.replace(/^::ffff:/,"");return n==="::1"||n==="127.0.0.1"||/^127\./.test(n)}function xS(t,e){if(!t||!e)return!1;let n=Buffer.from(String(t)),r=Buffer.from(String(e));return n.length!==r.length?!1:bS.timingSafeEqual(n,r)}function SS(t,e=null){let n=t?.headers?.["x-bostrat-token"];if(typeof n=="string"&&n.trim())return n.trim();let r=t?.headers?.authorization||"",o=/^Bearer\s+(.+)$/i.exec(r)?.[1];if(o)return o.trim();try{return(e??new URL(t.url,"http://node")).searchParams.get("token")||""}catch{return""}}var HB=[/^\/api\/github\/token\b/,/^\/api\/gmail\b/],WB=t=>HB.some(e=>e.test(t));function vS({token:t,enforce:e=!0,log:n=console}={}){return function(o,s,a){let i=o.path||o.url||"";if(!i.startsWith("/api"))return a();let c=SS(o);return xS(c,t)?a():WB(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"})):!e||Ia(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 TS(t,e,{enforce:n=!0}={}){return!n||xS(SS(t),e)?!0:Ia(t)}We();sc();sc();import qB from"node:http";import KB from"node:net";function ol(t){if(!t)return null;let e=String(t).replace(/:\d+$/,"").toLowerCase();if(/^[\d.]+$/.test(e)||e.includes(":"))return null;let n=e.split(".");if(n.length<3)return null;let r=n[0];return/^[a-z0-9-]+$/.test(r)?r:null}function sl(t){let e=ol(t.headers.host);return e?{slug:e,view:tf(e)}:null}var GB=t=>String(t??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;"),VB=t=>{let e=GB(t.name);return`<!doctype html><meta charset="utf-8">
483
+ _${o} archived_`:"")}async function _P(t,e){let n=await Fr();if(!n)return xt("Slack integration not configured.");let r=t.deps,o=(e.text||"").trim().split(/\s+/).filter(Boolean),s=(o[0]||"help").toLowerCase(),a=o.slice(1);switch(s){case"start":{if(!a.length)return xt("Usage: `/bostrat start <name> [repo]`");let i=await r.listRepos(),c=a[a.length-1]?.toLowerCase(),l=a.length>1?i.find(f=>f.name.toLowerCase()===c):null,u=(l?a.slice(0,-1):a).join(" ");return l?(Yn(uS(t,n,{name:u,repo:l.path,responseUrl:e.response_url})),xt(`Starting *${Q(u)}* on ${Q(l.name)}\u2026`)):{response_type:"ephemeral",text:`Pick a repo for \u201C${u}\u201D`,blocks:AP(u,i)}}case"archive":{if(!a.length)return xt("Usage: `/bostrat archive <track>`");let{match:i,live:c}=cm(await r.listTracks(),a.join(" "));return i?(Yn(SP(t,n,{track:i,responseUrl:e.response_url})),xt(`Archiving *${Q(i.name)}*\u2026`)):lm(c,a.join(" "))}case"handoff":{let i=r.knownAgents??xP,c=a.at(-1)?.toLowerCase();if(a.length<2||!i.includes(c))return xt(`Usage: \`/bostrat handoff <track> <${i.join("|")}>\``);let l=a.slice(0,-1).join(" "),{match:u,live:f}=cm(await r.listTracks(),l);return u?(Yn(vP(t,n,{track:u,agent:c,responseUrl:e.response_url})),xt(`Handing *${Q(u.name)}* to ${Q(c)}\u2026`)):lm(f,l)}case"stop":{if(!a.length)return xt("Usage: `/bostrat stop <track>`");let{match:i,live:c}=cm(await r.listTracks(),a.join(" "));return i?(Yn(TP(t,n,{track:i,responseUrl:e.response_url})),xt(`Stopping *${Q(i.name)}*\u2026`)):lm(c,a.join(" "))}case"list":return xt(await EP(r));default:return xt(kP)}}async function IP(t,e,n,r){let{trackId:o,promptId:s,label:a}=r,i=await pm(o);try{if(await t.deps.answerPrompt(o,{promptId:s,answers:[a]}),i?.prompt?.promptId===s){let{ts:c,question:l}=i.prompt;delete i.prompt,await Te(),await Wr(e.botToken,{channel:i.channel,ts:c,text:`\u2713 ${a}`,blocks:[{type:"section",text:{type:"mrkdwn",text:`~${Q(l||"question")}~
484
+ \u2713 *${Q(a)}*`}}]}).catch(()=>{})}}catch(c){await Vt(n.response_url,xt(`Couldn't answer: ${c?.message||c}`))}}async function RP(t,e,n,r){let{trackId:o,offerId:s,action:a}=r,i=t.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(d=>d.type==="pr.offered"&&d.payload?.offerId===s);if(!u)throw new Error("unknown offer");if(l.some(d=>d.type==="pr.offer.answered"&&d.payload?.offerId===s))throw new Error("offer already answered");let f=a==="pr"?["commit","push","pr"]:a==="push"?["commit","push"]:null;if(f?.includes("pr")&&i.divertShip&&await i.divertShip(c,u,{actions:f}))return;f&&await i.sayToLead(c.id,To(f,{branch:u.payload.branch,base:u.payload.base}),{kind:f.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:f?a:"dismiss",actions:f}})}catch(c){await Vt(n.response_url,xt(`Couldn't act on the offer: ${c?.message||c}`))}}async function $P(t,e,n,r){let{trackId:o,offerId:s,choice:a}=r;try{let i=await t.deps.resolveTrack(o);if(!i)throw new Error("track not found");await t.deps.answerPrExists(i,{offerId:s,choice:a})}catch(i){await Vt(n.response_url,xt(`Couldn't act on the offer: ${i?.message||i}`))}}async function OP(t,e){let n=e.actions?.[0];if(!n?.action_id)return;let r=await Fr();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 Vt(e.response_url,{...xt(`Starting *${Q(s)}*\u2026`),replace_original:!0}),Yn(uS(t,r,{name:s,repo:a==="__fresh__"?null:a,responseUrl:e.response_url}));return}let o;try{o=JSON.parse(n.value)}catch{return}n.action_id==="bostrat-prompt"?Yn(IP(t,r,e,o)):n.action_id==="bostrat-ship"?Yn(RP(t,r,e,o)):n.action_id==="bostrat-pr-exists"&&Yn($P(t,r,e,o))}async function CP(t,e){if(!e||e.type!=="message"||e.bot_id||e.subtype||!e.thread_ts||e.thread_ts===e.ts||!e.text?.trim())return;let n=await yP(e.channel,e.thread_ts);if(!n)return;let r=await Fr();if(r)try{await t.deps.sayToLead(n.trackId,e.text.trim())}catch(o){await Xn(r,n.rec,`Couldn't deliver that to the lead: ${o?.message||o}`).catch(()=>{})}}function MP(t){return async e=>{if(e.type==="slash_commands")return _P(t,e.payload);if(e.type==="interactive"){await OP(t,e.payload);return}if(e.type==="events_api"){await CP(t,e.payload?.event);return}}}var NP=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 PP(t,e){let n=[{type:"section",text:{type:"mrkdwn",text:`\u2753 ${Q(e.question||"The lead needs an answer")}`}}],r=(e.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:Ma(String(o),75)},value:JSON.stringify({trackId:t,promptId:e.promptId,label:String(o)})}))}):n.push({type:"context",elements:[{type:"mrkdwn",text:"_reply in this thread to answer_"}]}),n}async function DP(t,e,n){let r=n.payload||{};if(!r.promptId||e.prompt?.promptId===r.promptId)return;e.prompt&&await Wr(t.botToken,{channel:e.channel,ts:e.prompt.ts,text:"superseded",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${Q(e.prompt.question||"question")}~ _superseded_`}}]}).catch(()=>{});let o=await Xn(t,e,r.question||"The lead needs an answer",PP(n.trackId,r));e.prompt={promptId:r.promptId,ts:o.ts,question:r.question||null},await Te()}async function BP(t,e,n){let r=n.payload||{};if(!e.prompt||r.promptId&&e.prompt.promptId!==r.promptId)return;let{ts:o,question:s}=e.prompt;delete e.prompt,await Te(),await Wr(t.botToken,{channel:e.channel,ts:o,text:"answered",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${Q(s||"question")}~
485
+ \u2713 _answered_`}}]})}async function jP(t,e,n){let r=n.payload||{};if(!r.offerId||e.offers?.[r.offerId])return;let o=(i,c,l)=>({type:"button",action_id:"bostrat-ship",text:{type:"plain_text",text:c},value:JSON.stringify({trackId:n.trackId,offerId:r.offerId,action:i}),...l?{style:l}:{}}),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")],a=await Xn(t,e,r.excerpt||"Ship it?",[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${Q(Ma(r.excerpt||"The lead offered to ship.",300))}`}},{type:"actions",elements:s}]);e.offers=e.offers||{},e.offers[r.offerId]=a.ts,await Te()}async function LP(t,e,n){let r=n.payload||{},o=e.offers?.[r.offerId];if(!o)return;delete e.offers[r.offerId],await Te();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 Wr(t.botToken,{channel:e.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function FP(t,e,n){let r=n.payload||{};if(!r.offerId||e.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 Xn(t,e,`PR ${o} already open \u2014 push or new PR?`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${o}${r.branch?` (${Q(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")]}]);e.offers=e.offers||{},e.offers[r.offerId]=a.ts,await Te()}async function UP(t,e,n){let r=n.payload||{},o=e.offers?.[r.offerId];if(!o)return;delete e.offers[r.offerId],await Te();let s=r.choice==="dismiss"?"dismissed":r.choice==="new"?"\u2713 opening a new PR":"\u2713 pushing to the open PR";await Wr(t.botToken,{channel:e.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function HP(t,e,n,r){let o=n.payload||{};if(o.change==="ready"&&o.mockId){let s=await(r.readMockPng??WP)(o.mockId,o.version??null);if(!s)return;let a=(o.version??1)>1?` (v${o.version})`:"";await oS(t.botToken,{filename:s.filename,buffer:s.buffer,title:`${o.name}${a}`,channelId:e.channel,threadTs:e.ts,initialComment:`\u{1F3A8} mock *${Q(o.name)}*${a}${o.group?` (group \`${Q(o.group)}\`)`:""}`})}else if(o.change==="picked"){let s=(o.siblings??[]).map(a=>`*${Q(a.name)}*`).join(", ");await Xn(t,e,`Design decision: ${o.name} picked`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F3A8} design decision: *${Q(o.name)}* picked${s?` over ${s}`:""}`}}])}}async function WP(t,e){let n=await rn(t);if(!n)return null;let r=ve(n,e);if(!r)return null;let o=await Ca.readFile(fe(n,r.v).png).catch(()=>null);return o?{filename:`${n.name.replace(/[^\w.-]+/g,"-")}.v${r.v}.png`,buffer:o}:null}async function qP(t,e){if(!NP.has(e.type))return;let n=await pm(e.trackId);if(!n)return;let r=await Fr();if(!r)return;let o=e.payload||{};switch(e.type){case"turn.user":if(n.kickoff||e.actor!=="user"||!o.text)return;n.kickoff=o.text,await Te(),await dm(r,n);return;case"turn.agent":{if(!o.text)return;let s=bP(o.text);if(!s)return;await Xn(r,n,s,[{type:"section",text:{type:"mrkdwn",text:Q(s)}},{type:"context",elements:[{type:"mrkdwn",text:`<${tl(e.trackId)}|full turn \u2192>`}]}]);return}case"prompt.raised":return DP(r,n,e);case"prompt.answered":return BP(r,n,e);case"pr.offered":return jP(r,n,e);case"pr.offer.answered":return LP(r,n,e);case"pr.exists.offered":return FP(r,n,e);case"pr.exists.answered":return UP(r,n,e);case"pr.state.changed":{if(o.change!=="opened"&&o.change!=="merged")return;let s=o.change==="opened"?"PR opened":"PR merged";await Xn(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 Te(),await dm(r,n);return;case"view.state.changed":{if(o.change!=="created"||o.restarted||!o.slug)return;await Xn(r,n,`Live preview ${o.name}: ${el(o.slug)}`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F50D} live preview *${Q(o.name)}*: ${el(o.slug)}
486
+ _runs on the Track's branch; reachable on the operator's private network only_`}}]);return}case"mock.state.changed":return HP(r,n,e,t.deps)}}function dS(t){let e={deps:t};Zt.on("event",s=>{qP(e,s).catch(()=>{})});let n=null,r=null,o=async()=>{n||!await Fr()||(r&&clearInterval(r),r=null,n=sS({getToken:async()=>(await Fr())?.appToken,onEnvelope:MP(e),log:s=>console.log(`[slack] ${s}`)}))};return r=setInterval(()=>o().catch(()=>{}),3e4),r.unref?.(),o().catch(()=>{}),()=>{r&&clearInterval(r),n?.()}}ye();at();Ke();Vd();Ds();import KP from"node:fs/promises";function GP(t){let e=new Map;for(let n of String(t||"").split(`
487
+ `)){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;i&&e.set(i,{messageId:i,tokens:a,model:o.message?.model||o.model||null})}return[...e.values()]}function VP(t){let e=new Set;for(let n of t)if(n.type==="cost.recorded"){n.payload?.messageId&&e.add(n.payload.messageId);for(let r of n.payload?.messageIds||[])e.add(r)}return e}var zP=new Set(["Write","Edit","NotebookEdit"]),JP=220,YP=160;function XP(t,e){let n=t?.tool_name??null,r={tool:n},o=t?.tool_input;if(!o||typeof o!="object")return r;if(zP.has(n)&&typeof o.file_path=="string"&&o.file_path){let s=o.file_path,a=e?.cwd;a&&s.startsWith(`${a}/`)&&(s=s.slice(a.length+1)),r.path=s.slice(0,JP)}else n==="Bash"&&typeof o.command=="string"&&o.command.trim()&&(r.head=lr(o.command.trim().replace(/\s+/g," ")).slice(0,YP));return r}function ZP(t,e){return t?.transcript_path?t.transcript_path:e?.cwd&&e?.sessionId?Ge(e.cwd,e.sessionId):e?.cwd?au(e.cwd):null}async function fS(t,e){let n=await e(t?.session_id,t?.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 I(r,{...s,...c}))};switch(t?.hook_event_name){case"SessionStart":await i({type:"session.ready",actor:"system",payload:{sessionId:t.session_id}});break;case"UserPromptSubmit":{let c=String(t.prompt??t.user_prompt??""),l=dc(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:XP(t,o)});break;case"Stop":await QP(r,o,t,i);break;default:break}return a}async function QP(t,e,n,r){let o=[],s=ZP(n,e);if(s)try{o=GP(await KP.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??e?.model??null,messageId:a?.messageId??null}}),!o.length)return;let i=VP(await F(t)),c=o.filter(u=>!i.has(u.messageId));if(c.length){let u=new Map;for(let f of c){let d=f.model||"unknown",p=u.get(d)||{tokens:{input:0,output:0,cacheWrite:0,cacheRead:0},messageIds:[]};for(let h of Object.keys(p.tokens))p.tokens[h]+=f.tokens[h];p.messageIds.push(f.messageId),u.set(d,p)}for(let[f,d]of u)await r({type:"cost.recorded",actor:"system",source:"transcript",payload:{model:f,usd:Cn(f,d.tokens),tokens:d.tokens,messageId:d.messageIds[d.messageIds.length-1],messageIds:d.messageIds,apiCalls:d.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}})}cs();at();Ji();import nD from"node:fs";import hm from"node:fs/promises";import rD from"node:http";import Xo from"node:path";import il from"node:os";import{createRequire as oD}from"node:module";import wm from"ws";import tD from"node:path";import eD from"node:os";var Na=process.env.BOSTRAT_STATE_DIR||tD.join(process.env.HOME||eD.tmpdir(),".bostrat");function mm(t=process.env){let e=(t.BOSTRAT_HOST||"").trim();if(e!=="all")return e||(t.BOSTRAT_PLANE_URL?"127.0.0.1":void 0)}function pS(t=process.env){if(!t.BOSTRAT_PLANE_URL)return null;let e=mm(t);return e==="127.0.0.1"||e==="::1"||e==="localhost"?null:{host:e}}function mS(t){let e=String(t||"").trim();if(!e)return"";let n=/^[a-z][a-z0-9+.-]*:\/\//i.test(e)?e:`wss://${e}`,r;try{r=new URL(n)}catch{return e}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()):e}var sl=(()=>{try{return oD(import.meta.url)("../package.json").version||null}catch{return null}})(),sD=process.env.BOSTRAT_STATE_DIR||Xo.join(process.env.HOME||il.tmpdir(),".bostrat");function aD(t,e){let n=String(t).split(".").map(Number),r=String(e).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 iD({home:t=process.env.HOME||il.homedir(),env:e=process.env}={}){let n=r=>{try{return nD.statSync(r),!0}catch{return!1}};return{claude:n(Xo.join(t,".claude",".credentials.json")),codex:n(Xo.join(e.CODEX_HOME||Xo.join(t,".codex"),"auth.json"))}}var Bt=1,hS=1e3,cD=3e4,lD=6e4,uD=1500,dD=500,al=100,fD=2e3,pD=25e3,mD=6e4,hD=6e4,wD=6e4;function wS({url:t,token:e,nodeId:n=il.hostname(),name:r=il.hostname(),listTracks:o,detectAgents:s=null,onTracksTransferred:a=null,sampleMetrics:i=null,metricsMs:c=hD,selfUrl:l=`http://127.0.0.1:${process.env.PORT||3362}`,log:u=console}){if(!t||!e)throw new Error("plane-link: url and token are required");if(typeof o!="function")throw new Error("plane-link: listTracks is required");t=mS(t);let f=l.replace(/^http/,"ws"),d=new Map,p=new Map,h=Xo.join(sD,"plane-link","cursor.json"),w={},y={},k=new Map,x=null,E=!1,O=!1,z=hS,C=null,N=null,T=null,D=null,j=null,st=!1,rt=0;async function A(){try{w=JSON.parse(await hm.readFile(h,"utf8"))}catch{w={}}}function B(){st=!0,!T&&(T=setTimeout(async()=>{if(T=null,!!st){st=!1;try{await hm.mkdir(Xo.dirname(h),{recursive:!0}),await hm.writeFile(h,JSON.stringify(w))}catch(b){u.error("[plane-link] cursor flush failed:",b?.message||b)}}},fD),T.unref?.())}function X(b){return!x||x.readyState!==wm.OPEN?!1:(x.send(JSON.stringify(b)),!0)}function yt(b){let _=Date.now();for(let{trackId:R,event:P}of b){let wt=k.get(P.id);k.set(P.id,{trackId:R,seq:P.seq,event:P,sentAt:_,tries:(wt?.tries??0)+1})}return X({v:Bt,ch:"events",type:"append",events:b})}function dt(b){let _=null;for(let R of k.values())R.trackId===b&&(_==null||R.seq<_)&&(_=R.seq);return _}function bt(b){let _=y[b];if(_==null)return;let R=dt(b),P=R==null?_:Math.min(_,R-1);P>(w[b]??0)&&(w[b]=P,B())}function kt(){if(!E)return;let b=Date.now(),_=[...k.values()].filter(R=>R.event&&b-R.sentAt>=mD);if(_.length){_.sort((R,P)=>R.trackId===P.trackId?R.seq-P.seq:R.trackId<P.trackId?-1:1),u.log(`[plane-link] re-sending ${_.length} unacked event(s) the plane never confirmed`);for(let R=0;R<_.length;R+=al){let P=_.slice(R,R+al).map(wt=>({trackId:wt.trackId,event:wt.event}));if(!yt(P))return}}}async function g(){if(!i)return;let b;try{b=await i()}catch(_){u.error("[plane-link] metrics sample failed:",_?.message||_);return}b&&X({v:Bt,ch:"ctl",type:"metrics",metrics:b})}function m(){i&&(j&&clearInterval(j),g(),j=setInterval(g,c),j.unref?.())}async function v(){let b;try{b=await o()}catch(_){u.error("[plane-link] backfill listTracks failed:",_?.message||_);return}X({v:Bt,ch:"ctl",type:"tracks",ids:b.filter(_=>!_.transferredTo).map(_=>_.id).filter(_=>typeof _=="string")});for(let _ of b){if(!E)return;let R;try{R=await F(_)}catch{continue}let P=w[_.id]??0,wt=R.filter(ht=>ht.seq>P&&typeof ht.id=="string");for(let ht=0;ht<wt.length;ht+=al){let Ht=wt.slice(ht,ht+al).map(ce=>({trackId:_.id,event:ce}));if(!yt(Ht))return}}}function $(b){!E||!b?.trackId||typeof b.id!="string"||yt([{trackId:b.trackId,event:b}])}let it=new Map;async function ct(b){let{reqId:_,method:R,path:P,headers:wt={},body:ht}=b,Ht=Object.fromEntries(Object.entries(wt).filter(([,Ee])=>Ee!=null)),ce=new AbortController;it.set(_,ce);try{if(b.host){await mt(b,Ht,ce);return}let Ee=await fetch(l+P,{method:R,headers:Ht,body:ht?Buffer.from(ht,"base64"):void 0,signal:ce.signal}),wn=Object.fromEntries(Ee.headers);for(let le of["connection","keep-alive","transfer-encoding","upgrade","content-encoding","content-length"])delete wn[le];if(wn["content-type"]||(wn["content-type"]="application/octet-stream"),X({v:Bt,ch:"control",type:"http_head",reqId:_,status:Ee.status,headers:wn}),Ee.body){for await(let le of Ee.body)if(!X({v:Bt,ch:"control",type:"http_data",reqId:_,data:Buffer.from(le).toString("base64")}))break}X({v:Bt,ch:"control",type:"http_end",reqId:_,error:null})}finally{it.delete(_)}}function mt(b,_,R){let{reqId:P,method:wt,path:ht,body:Ht}=b,ce=new URL(l);return new Promise(Ee=>{let wn=rD.request({host:ce.hostname,port:ce.port,method:wt,path:ht,headers:{..._,host:b.host},signal:R.signal},le=>{let{connection:yj,"keep-alive":bj,"transfer-encoding":kj,upgrade:xj,...uT}=le.headers;X({v:Bt,ch:"control",type:"http_head",reqId:P,status:le.statusCode||502,headers:uT}),le.on("data",dT=>{X({v:Bt,ch:"control",type:"http_data",reqId:P,data:Buffer.from(dT).toString("base64")})||le.destroy()}),le.on("end",()=>{X({v:Bt,ch:"control",type:"http_end",reqId:P,error:null}),Ee()}),le.on("error",()=>{X({v:Bt,ch:"control",type:"http_end",reqId:P,error:"view upstream error"}),Ee()})});wn.on("error",le=>{X({v:Bt,ch:"control",type:"http_end",reqId:P,error:le?.message||"view request failed"}),Ee()}),Ht&&wn.write(Buffer.from(Ht,"base64")),wn.end()})}function sr(){if(O)return;x=new wm(t,{headers:{authorization:`Bearer ${e}`}}),x.on("open",async()=>{let _=null;try{_=await s?.()||null}catch{_=null}X({v:Bt,ch:"ctl",type:"hello",nodeId:n,name:r,platform:process.platform,version:sl,providers:iD(),..._?{agents:_}:{}})}),x.on("message",_=>{let R;try{R=JSON.parse(_)}catch{return}if(R.ch==="ctl"&&R.type==="hello_ok"){E=!0,z=hS,C=null,u.log(`[plane-link] connected to plane as ${n}`),R.minNodeVersion&&sl&&aD(sl,R.minNodeVersion)&&u.error(`[plane-link] this node is bostrat-node ${sl}; the plane asks for \u2265${R.minNodeVersion} \u2014 update with: npm install -g bostrat-node`),D&&clearInterval(D),D=setInterval(()=>{X({v:Bt,ch:"ctl",type:"ping"}),kt()},pD),D.unref?.(),m(),v().catch(P=>u.error("[plane-link] backfill failed:",P?.message||P));return}if(R.ch==="ctl"&&R.type==="usage_caps"){zi(R.caps??{},{source:"plane",updatedAt:R.updatedAt??Date.now()}).then(P=>u.log(`[plane-link] spend caps ${Object.keys(P.caps).length?`updated (${Object.keys(P.caps).join(", ")})`:"cleared"} from plane`)).catch(P=>u.error("[plane-link] spend-caps push rejected:",P?.message||P));return}if(R.ch==="ctl"&&R.type==="transferred"&&Array.isArray(R.tracks)){Promise.resolve().then(()=>a?.(R.tracks)).catch(P=>u.error("[plane-link] transfer notice failed:",P?.message||P));return}if(R.ch==="events"&&R.type==="ack"&&Array.isArray(R.ids)){let P=new Set;for(let wt of R.ids){let ht=k.get(wt);ht&&(k.delete(wt),(y[ht.trackId]??0)<ht.seq&&(y[ht.trackId]=ht.seq),P.add(ht.trackId))}for(let wt of P)bt(wt);return}if(R.ch==="control"&&R.type==="http_open"){ct(R).catch(P=>X({v:Bt,ch:"control",type:"http_end",reqId:R.reqId,error:P?.message||"tunnel error"}));return}if(R.ch==="control"&&R.type==="http_cancel"){it.get(R.reqId)?.abort();return}if(R.ch==="attach"&&R.type==="open"){let P=new wm(f+R.path,Array.isArray(R.protocols)?R.protocols:[],R.host?{headers:{host:R.host}}:void 0);d.set(R.streamId,P),p.set(R.streamId,[]),P.on("open",()=>{let ht=p.get(R.streamId)||[];p.delete(R.streamId);for(let{buf:Ht,bin:ce}of ht)P.send(Ht,{binary:ce})}),P.on("message",(ht,Ht)=>{let ce=Ht?ht:Buffer.from(String(ht));X({v:Bt,ch:"attach",type:"data",streamId:R.streamId,data:ce.toString("base64"),...Ht?{bin:!0}:{}})});let wt=()=>{p.delete(R.streamId),d.delete(R.streamId)&&X({v:Bt,ch:"attach",type:"close",streamId:R.streamId})};P.on("close",wt),P.on("error",wt);return}if(R.ch==="attach"&&R.type==="data"){let P=d.get(R.streamId);if(!P)return;let wt=Buffer.from(R.data,"base64"),ht=R.bin===!0,Ht=p.get(R.streamId);Ht?Ht.push({buf:wt,bin:ht}):P.send(wt,{binary:ht});return}if(R.ch==="attach"&&R.type==="close"){let P=d.get(R.streamId);d.delete(R.streamId),p.delete(R.streamId),P?.close();return}});let b=()=>{E&&u.log("[plane-link] disconnected from plane"),E=!1,D&&(clearInterval(D),D=null),j&&(clearInterval(j),j=null),k.clear(),y={};for(let P of d.values())P.close();d.clear(),p.clear();for(let P of it.values())P.abort();if(it.clear(),O||N)return;C==null&&(C=Date.now());let _=Date.now()-C<lD,R=_?uD+Math.random()*dD:z;N=setTimeout(()=>{N=null,sr()},R),N.unref?.(),_||(z=Math.min(z*2,cD))};x.on("close",b),x.on("error",_=>{let R=/Unexpected server response: (\d+)/.exec(_?.message||"")?.[1];(R==="401"||R==="403")&&Date.now()-rt>=wD&&(rt=Date.now(),u.error(`[plane-link] plane refused this node's credentials (HTTP ${R}) \u2014 the token was revoked or is unknown to the plane; mint a new node token and update this node's BOSTRAT_PLANE_TOKEN (still retrying)`)),b()})}return Zt.on("event",$),A().then(sr),{stop:()=>{O=!0,Zt.off("event",$),N&&clearTimeout(N),T&&clearTimeout(T),D&&clearInterval(D),j&&clearInterval(j),X({v:Bt,ch:"ctl",type:"bye",reason:"shutdown"}),x?.close()},status:()=>({connected:E,nodeId:n,cursor:{...w},inflight:k.size})}}import gD from"node:fs";import gS from"node:fs/promises";import Pa from"node:os";import yD from"node:path";If();qt();var bD=1024*1024,cl=t=>Math.round(t/bD);async function kD(t){try{let e=await gS.statfs(t),n=e.blocks*e.bsize,r=n-e.bavail*e.bsize;return{diskUsedMb:cl(r),diskTotalMb:cl(n)}}catch{return{diskUsedMb:null,diskTotalMb:null}}}async function xD(){try{return(await ge()).filter(e=>e.isBostrat).length}catch{return null}}async function SD(){let t=0,e=!1;for(let n of["workspaces","worktrees"])try{let r=await gS.readdir(yD.join(Na,n),{withFileTypes:!0});t+=r.filter(o=>o.isDirectory()).length,e=!0}catch{}return e?t:null}async function yS({stateDir:t=Na,now:e=Date.now}={}){let n=Pa.totalmem(),[r,o,s,a]=await Promise.all([Ac().catch(()=>null),kD(gD.existsSync(t)?t:Pa.tmpdir()),xD(),SD()]),i=Pa.cpus()?.length||null,c=Pa.loadavg()?.[0]??null;return{ts:e(),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?cl(n-r):null,memTotalMb:cl(n),...o,boxes:s,worktrees:a,procUptimeS:Math.round(process.uptime()),osUptimeS:Math.round(Pa.uptime())}}at();yu();ci();at();wr();function gm(t){let e={};for(let n of t.boxes||[]){let r=n.role&&n.role!=="lead"?` \xB7 ${n.role}`:"";e[n.name]=`${n.name} (${n.agent||"?"}${r})`}return e}var bS=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),kS=(t,e)=>{for(let n of Object.keys(t))t[n]+=e?.[n]||0},ll=t=>Math.round(t*1e4)/1e4;async function xS(t){let e=[],n={},r={},o=0,s=0,a=0,i=0,c=0,l=new Set,u=bS(),f=0,d=[];for(let p of t||[]){let h=await F(p),w=Mn(h,{boxLabels:gm(p)});if(w.turns===0){p.archivedAt?f++:d.push(p.name||p.id);continue}o+=w.totalUsd,s+=w.turns,a+=w.repricedTurns||0,i+=w.asRecordedUsd||0,c+=w.unpricedTurns||0;for(let y of w.unpricedModels||[])l.add(y);kS(u,w.totalTokens);for(let[y,k]of Object.entries(w.byModel))n[y]||={usd:0,events:0,tokens:bS()},n[y].usd=ll(n[y].usd+k.usd),n[y].events+=k.events,kS(n[y].tokens,k.tokens);for(let[y,k]of Object.entries(w.byProvider))r[y]||={usd:0,events:0},r[y].usd=ll(r[y].usd+k.usd),r[y].events+=k.events;e.push({id:p.id,name:p.name,usd:w.totalUsd,rollup:w})}return e.sort((p,h)=>h.usd-p.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",fleet:{totalUsd:ll(o),asRecordedUsd:ll(i),turns:s,repricedTurns:a,unpricedTurns:c,unpricedModels:[...l],totalTokens:u,byModel:n,byProvider:r,tracksWithCost:e.length,tracksSilent:f+d.length,tracksSilentArchived:f,tracksSilentLive:d},tracks:e}}var Zn=t=>`$${t.toFixed(4)}`,Zo=(t,e)=>String(t).padEnd(e);function SS(t){let{fleet:e,tracks:n}=t,r=[];r.push(`BOSTRAT COST READ-OUT \xB7 ${t.generatedAt}`),t.pricingBasis&&r.push(`basis: ${t.pricingBasis}`);let o=e.tracksSilentLive||[];r.push(`fleet total ${Zn(e.totalUsd)} over ${e.turns} turn(s) \xB7 ${e.tracksWithCost} track(s) with cost, ${e.tracksSilentArchived??e.tracksSilent} silent (archived)`+(o.length?`, ${o.length} LIVE with no cost data: ${o.join(", ")}`:"")),e.repricedTurns&&r.push(`${e.repricedTurns} turn(s) priced at current table rates (differs from as-recorded)`),e.asRecordedUsd!=null&&Math.abs(e.asRecordedUsd-e.totalUsd)>=.005&&r.push(`as-recorded total ${Zn(e.asRecordedUsd)} \xB7 current-rates total ${Zn(e.totalUsd)} (${e.totalUsd>=e.asRecordedUsd?"+":""}${Zn(e.totalUsd-e.asRecordedUsd)})`),e.unpricedTurns&&r.push(`\u26A0 ${e.unpricedTurns} turn(s) UNPRICED \u2014 total under-reports. Add PER_MTOK rate(s) for: ${(e.unpricedModels||[]).join(", ")}`),r.push(""),r.push("BY MODEL");let s=Object.entries(e.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(` ${Zo(a,26)} ${Zo(Zn(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(` ${Zo(a.name||a.id,30)} ${Zn(a.usd)}`);let i=Object.values(a.rollup.byBox).sort((c,l)=>l.usd-c.usd);for(let c of i)if(r.push(` ${Zo(c.label,40)} ${Zo(Zn(c.usd),10)} ${c.models.join(",")||"?"}`),c.epochs)for(let[l,u]of Object.entries(c.epochs).sort((f,d)=>Number(f[0])-Number(d[0])))r.push(` \u21B3 tenure ${l} (${u.provider||"?"})${" ".repeat(Math.max(1,24-String(u.provider||"?").length))}${Zo(Zn(u.usd),10)} ${u.models.join(",")||"?"}`)}return r.join(`
488
+ `)}tf();Ji();at();Dd();import _D from"node:fs/promises";import ID from"node:path";gu();wr();var ul=t=>t.payload?.ts??t.ts,vD=12e4,Qn=t=>Math.round(t*1e4)/1e4,TD=()=>({usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},byTrack:new Map});function AD(t,{since:e}){let{track:n,events:r,brief:o}=t,s=x=>ul(x)>=e,a=pr([Is(n?.name),Is(n?.workspace?.branch),o].filter(Boolean).join(" ")),i=new Map;for(let x of r)if(x.type==="subtask.delegated"&&x.boxId&&x.payload?.task){let E=pr(x.payload.task);E&&i.set(x.boxId,E)}let c=new Map,l=x=>{let E=x||"unattributed";return c.has(E)||c.set(E,{segments:[u(null)],lastTs:null,provider:null}),c.get(E)},u=x=>({textCat:x,tools:{},usd:0,tokens:{input:0,output:0,cacheRead:0,cacheWrite:0},models:{},provider:null,activeMs:0,turns:0,toolCalls:0}),f=[...r].sort((x,E)=>ul(x)-ul(E)),d=0,p=0,h=0,w={turns:0};for(let x of f){let E=l(x.boxId),O=E.segments[E.segments.length-1],z=ul(x);switch(E.lastTs!=null&&z>E.lastTs&&s(x)&&(O.activeMs+=Math.min(z-E.lastTs,vD)),E.lastTs=z,x.provider&&(E.provider=x.provider),x.type){case"turn.user":{let C=x.payload?.text;if(x.source==="hook"||!String(C||"").trim())break;let N=u(pr(C));E.segments.push(N),s(x)&&(N.turns+=1);break}case"peer.message":{let C=x.payload?.text;if(!String(C||"").trim())break;let N=u(pr(C));E.segments.push(N),s(x)&&(N.turns+=1);break}case"tool.called":{if(x.source==="transcript")break;let C=x.payload?.tool;C&&(O.tools[C]=(O.tools[C]||0)+1),s(x)&&(O.toolCalls+=1);break}case"cost.recorded":{if(!s(x))break;let{usd:C,tokens:N,model:T,unpriced:D}=Ve(x);D&&(w.turns+=1),O.usd+=C,N&&(O.tokens.input+=N.input,O.tokens.output+=N.output,O.tokens.cacheRead+=N.cacheRead,O.tokens.cacheWrite+=N.cacheWrite),O.models[T]=(O.models[T]||0)+C,x.provider&&(O.provider=x.provider);break}case"handoff.done":s(x)&&(d+=1);break;case"subtask.merged":s(x)&&(p+=1);break;case"error":s(x)&&x.payload?.kind==="subtask-failed"&&(h+=1);break;default:break}}let y=new Map,k=!1;for(let[x,E]of c)for(let O of E.segments){if(!(O.usd>0||O.activeMs>0||O.turns>0||O.toolCalls>0))continue;let C=O.textCat?.category??i.get(x)?.category??hw(O.tools)?.category??a?.category??"uncategorized";y.has(C)||y.set(C,{usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{}});let N=y.get(C);N.usd+=O.usd,N.activeMs+=O.activeMs,N.turns+=O.turns,N.toolCalls+=O.toolCalls;for(let[D,j]of Object.entries(O.models))N.models[D]=(N.models[D]||0)+j;let T=O.provider||E.provider;T&&(N.providers[T]=(N.providers[T]||0)+O.usd),T==="cursor"&&O.usd===0&&(k=!0)}return{perCategory:y,handoffs:d,merged:p,failed:h,sawCursorActivity:k,unpricedTurns:w.turns}}function TS(t,{windowMs:e=null,now:n=Date.now()}={}){let r=e==null?0:n-e,o=new Map,s=[],a=0,i=!1,c=0;for(let w of t||[]){let{track:y,events:k}=w;if(!k?.length){a+=1;continue}let{perCategory:x,handoffs:E,merged:O,failed:z,sawCursorActivity:C,unpricedTurns:N}=AD(w,{since:r});C&&(i=!0),c+=N;let T={trackId:y?.id,name:y?.name||y?.id,archived:!!y?.archivedAt,usd:0,activeMs:0,turns:0,categories:{},models:{},providers:{},handoffs:E,subtasksMerged:O,subtasksFailed:z};for(let[D,j]of x){T.usd+=j.usd,T.activeMs+=j.activeMs,T.turns+=j.turns,T.categories[D]={usd:Qn(j.usd),activeMs:j.activeMs};for(let[A,B]of Object.entries(j.models))T.models[A]=Qn((T.models[A]||0)+B);for(let[A,B]of Object.entries(j.providers))T.providers[A]=Qn((T.providers[A]||0)+B);o.has(D)||o.set(D,TD());let st=o.get(D);st.usd+=j.usd,st.activeMs+=j.activeMs,st.turns+=j.turns,st.toolCalls+=j.toolCalls;for(let[A,B]of Object.entries(j.models))st.models[A]=(st.models[A]||0)+B;for(let[A,B]of Object.entries(j.providers))st.providers[A]=(st.providers[A]||0)+B;let rt=st.byTrack.get(y?.id)||{usd:0,activeMs:0};rt.usd+=j.usd,rt.activeMs+=j.activeMs,st.byTrack.set(y?.id,rt)}(T.usd>0||T.activeMs>0||T.turns>0)&&(T.usd=Qn(T.usd),T.dominantCategory=ED(T.categories),s.push(T))}let l=[...o.values()].reduce((w,y)=>w+y.usd,0),u=[...o.values()].reduce((w,y)=>w+y.activeMs,0),f=l>0?"usd":"time",d=f==="usd"?l:u,p=new Map((t||[]).map(w=>[w.track?.id,w.track?.name||w.track?.id])),h=[...o.entries()].map(([w,y])=>({category:w,sharePct:d>0?Math.round((f==="usd"?y.usd:y.activeMs)/d*100):0,shareBasis:f,usd:Qn(y.usd),activeMs:y.activeMs,turns:y.turns,toolCalls:y.toolCalls,models:vS(y.models),providers:vS(y.providers),topWorkstreams:[...y.byTrack.entries()].sort((k,x)=>x[1].usd-k[1].usd||x[1].activeMs-k[1].activeMs).slice(0,2).map(([k,x])=>({trackId:k,name:p.get(k),usd:Qn(x.usd),activeMs:x.activeMs}))})).sort((w,y)=>y.usd-w.usd||y.activeMs-w.activeMs);return s.sort((w,y)=>y.usd-w.usd||y.activeMs-w.activeMs),{since:r,capturedAt:n,totalUsd:Qn(l),activeMs:u,turns:[...o.values()].reduce((w,y)=>w+y.turns,0),bullets:h,workstreams:s,gaps:{tracksWithoutEvents:a,cursorCostUnknown:i,unpricedTurns:c}}}var ED=t=>{let e=null;for(let[n,r]of Object.entries(t))(!e||r.usd>e.v.usd||r.usd===e.v.usd&&r.activeMs>e.v.activeMs)&&(e={cat:n,v:r});return e?.cat??null},vS=t=>Object.fromEntries(Object.entries(t).map(([e,n])=>[e,Qn(n)]));var Qo={"24h":24*36e5,"7d":168*36e5,"30d":720*36e5,all:null};function RD(t){let e=String(t||"7d");return e in Qo?{key:e,ms:Qo[e]}:{key:"7d",ms:Qo["7d"]}}function $D(t,e){let n=new Set((e||[]).filter(o=>o.source==="orchestrator").map(o=>`${o.type}|${o.payload?.ts??"?"}`)),r=[...e||[]];for(let o of t?.events||[]){let s=Zi(o);!s||n.has(`${s.type}|${s.payload?.ts??"?"}`)||r.push({trackId:t.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 OD(t){if(!t?.cwd)return null;try{let n=(await _D.readFile(ID.join(t.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 AS(t,{window:e="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}:RD(e),f=[];for(let d of t||[]){let p=await F(d),h=$D(d,p);i&&c<o&&(h=h.filter(w=>(w.ts??0)<=c)),f.push({track:d,events:h,brief:await OD(d)})}return{window:l,...TS(f,{windowMs:u,now:c})}}at();wr();var tr=36e5,RS=24*tr,CD=400,MD=12,ts=t=>Math.round(t*1e4)/1e4;function ND({window:t,from:e,to:n,now:r=Date.now()}={}){let o=Number(e),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(t||"7d")in Qo?String(t||"7d"):"7d",i=Qo[a];return{key:a,since:i==null?null:r-i,until:r}}var PD=(t,e)=>t!=null&&e-t<=48*tr?tr:RS;function ES(t,e){if(e===tr)return Math.floor(t/tr)*tr;let n=new Date(t);return n.setHours(0,0,0,0),n.getTime()}function DD(t,e){if(e===tr)return t+tr;let n=new Date(t);return n.setDate(n.getDate()+1),n.setHours(0,0,0,0),n.getTime()}var _S=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),IS=(t,e)=>{for(let n of Object.keys(t))t[n]+=e?.[n]||0},BD=t=>Object.fromEntries(Object.entries(t).map(([e,n])=>[e,ts(n)]));async function $S(t,e={}){let n=e.now??Date.now(),r=ND({...e,now:n}),o=r.since==null?RS:PD(r.since,r.until),s=T=>(r.since==null||T>=r.since)&&T<r.until,a=r.since!=null?r.until-r.since:null,i=T=>a!=null&&T>=r.since-a&&T<r.since,c={},l={},u=_S(),f=0,d=0,p=0,h=0,w=0,y=new Set,k=new Map,x=[],E=[],O=[],z=null;for(let T of t||[]){let j=(await F(T)).filter(A=>A.type==="cost.recorded");if(!j.length){T.archivedAt||O.push(T.name||T.id);continue}let st=[];for(let A of j){let B=A.ts??0;s(B)?st.push(A):i(B)&&(w+=Ve(A).usd)}if(!st.length)continue;let rt=Mn(st,{boxLabels:gm(T)});f+=rt.totalUsd,d+=rt.turns,p+=rt.repricedTurns||0,h+=rt.unpricedTurns||0;for(let A of rt.unpricedModels||[])y.add(A);IS(u,rt.totalTokens);for(let[A,B]of Object.entries(rt.byModel))c[A]||={usd:0,events:0,tokens:_S()},c[A].usd=ts(c[A].usd+B.usd),c[A].events+=B.events,IS(c[A].tokens,B.tokens);for(let[A,B]of Object.entries(rt.byProvider))l[A]||={usd:0,events:0},l[A].usd=ts(l[A].usd+B.usd),l[A].events+=B.events;for(let A of st){let{usd:B}=Ve(A);if(!B)continue;let X=ES(A.ts??0,o),yt=k.get(X)??{t:X,total:0,byProvider:{}};yt.total+=B;let dt=A.provider||"unknown";yt.byProvider[dt]=(yt.byProvider[dt]||0)+B,k.set(X,yt),(z==null||X<z)&&(z=X)}x.push({id:T.id,name:T.name||T.id,archived:!!T.archivedAt,usd:rt.totalUsd,turns:rt.turns,providers:Object.keys(rt.byProvider)});for(let[A,B]of Object.entries(rt.byBox))E.push({trackId:T.id,trackName:T.name||T.id,boxId:A,...B})}let C=r.since!=null?ES(r.since,o):z,N=[];for(let T=C,D=0;T!=null&&T<r.until&&D<CD;T=DD(T,o),D++){let j=k.get(T);N.push(j?{t:T,total:ts(j.total),byProvider:BD(j.byProvider)}:{t:T,total:0,byProvider:{}})}return x.sort((T,D)=>D.usd-T.usd),E.sort((T,D)=>D.usd-T.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",window:r.key,since:r.since,until:r.until,bucketMs:o,series:N,fleet:{totalUsd:ts(f),turns:d,repricedTurns:p,unpricedTurns:h,unpricedModels:[...y],totalTokens:u,byModel:c,byProvider:l,tracksWithCost:x.length,tracksSilentLive:O},prior:a!=null?{totalUsd:ts(w),since:r.since-a,until:r.since}:null,tracks:x.slice(0,50),boxes:E.slice(0,MD)}}Jt();import es from"node:fs/promises";import jD from"node:fs";import Ft from"node:path";import LD from"node:os";import{execFile as FD}from"node:child_process";import{promisify as UD}from"node:util";var HD=UD(FD),OS=process.env.BOSTRAT_STATE_DIR||Ft.join(process.env.HOME||LD.tmpdir(),".bostrat"),dl=!1,ym=null;async function bm(t,e){let n=await es.stat(t).catch(()=>null);if(!n?.isFile())return!1;let r=await es.stat(e).catch(()=>null);return r&&r.size===n.size&&r.mtimeMs>=n.mtimeMs?!1:(await es.mkdir(Ft.dirname(e),{recursive:!0}),await es.copyFile(t,e),!0)}var WD=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 fl(t,e,{skip:n=null}={}){let r=0,o=await es.readdir(t,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(WD.has(s.name)||n?.has(s.name))continue;let a=Ft.join(t,s.name);s.isDirectory()?r+=await fl(a,Ft.join(e,s.name)):s.isFile()&&(r+=await bm(a,Ft.join(e,s.name))?1:0)}return r}async function CS({stateDir:t=OS,dest:e=process.env.BOSTRAT_SYNC_DIR||`${OS}-sync`,remote:n=process.env.BOSTRAT_STATE_REMOTE||null,tracks:r=null}={}){try{await es.mkdir(e,{recursive:!0});let o=0;o+=await bm(Ft.join(t,"tracks.json"),Ft.join(e,"tracks.json"))?1:0,o+=await bm(Ft.join(t,"events.jsonl"),Ft.join(e,"events.jsonl"))?1:0,o+=await fl(Ft.join(t,"events"),Ft.join(e,"events")),o+=await fl(Ft.join(t,"memory"),Ft.join(e,"memory"));let s=new Set(["mocks"]);for(let u of r||[])!u?.cwd||!u?.id||(o+=await fl(Ft.join(u.cwd,".bostrat"),Ft.join(e,"workspaces",u.id,".bostrat"),{skip:s}));let a=(...u)=>HD("git",["-C",e,...u]);jD.existsSync(Ft.join(e,".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 jl(e).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||dl))try{await a("push","-q",n,"HEAD:refs/heads/main"),l=!0,dl&&console.log("[state-sync] push recovered \u2014 off-box copy is current again"),dl=!1,ym=null}catch(u){dl=!0;let f=(u?.stderr||u?.message||String(u)).trim().split(`
489
+ `).slice(-3).join(" | ").slice(0,300);f!==ym&&(ym=f,console.warn(`[state-sync] PUSH FAILING (retrying each cycle; off-box copy is STALE): ${f}`))}return{staged:o,committed:i,pushed:l}}catch(o){return{staged:0,committed:!1,pushed:!1,error:o?.message||String(o)}}}Vf();ye();lo();qt();ls();import{execFile as qD}from"node:child_process";import{promisify as KD}from"node:util";import{randomUUID as GD}from"node:crypto";import VD from"node:fs";import zD from"node:os";import JD from"node:path";var nr=KD(qD),pl=t=>new Promise(e=>setTimeout(e,t)),rr=tu,km=process.env.BOSTRAT_USAGE_PROBE_CWD||JD.join(zD.homedir(),".bostrat","usage-probe"),YD=Number(process.env.BOSTRAT_USAGE_IDLE_REAP_MS)||5*6e4,XD=Number(process.env.BOSTRAT_USAGE_PANEL_TIMEOUT_MS)||15e3,ZD=Number(process.env.BOSTRAT_USAGE_READY_TIMEOUT_MS)||45e3,MS=Number(process.env.BOSTRAT_USAGE_CACHE_MS)||2e4,er=null,Da=null,Ba=null;async function QD(){try{return await nr(L,U("has-session","-t",rr)),!0}catch{return!1}}function tB(){er&&clearTimeout(er),er=setTimeout(()=>eB().catch(()=>{}),YD),er.unref&&er.unref()}async function eB(){er&&(clearTimeout(er),er=null);try{await nr(L,U("kill-session","-t",rr))}catch{}}async function nB(){let t=Date.now()+ZD;for(;;){let e=await xm().catch(()=>"");if(/for agents|for shortcuts|bypass permissions on/i.test(e)){await pl(500);return}if(Date.now()>t)throw new Error("usage probe didn't reach the prompt (trust/onboarding may be blocking)");await pl(500)}}async function rB(){if(await QD())return;if(!await Tn())throw new Error("host tmux server not running \u2014 start globo-tmux.service");VD.mkdirSync(km,{recursive:!0}),await gn(km);let t=GD();await nr(L,U("new-session","-d","-s",rr,"-c",km,"-x","200","-y","60",...Ql()));let e=`${Zl} --session-id ${t}`;await nr(L,U("send-keys","-t",rr,e,"Enter")),await nB()}async function xm(){let{stdout:t}=await nr(L,U("capture-pane","-t",rr,"-p"));return t}async function oB(){await rB(),await nr(L,U("send-keys","-t",rr,"-l","/usage")),await nr(L,U("send-keys","-t",rr,"Enter"));let t=Date.now()+XD,e="";for(;await pl(400),e=await xm(),!(/Current\s+(session|week)/i.test(e)||/\d+%\s*used/i.test(e)||Date.now()>t););return await pl(900),e=await xm(),await nr(L,U("send-keys","-t",rr,"Escape")).catch(()=>{}),tB(),e}function sB(t){let e=String(t||"").split(`
490
+ `).map(s=>s.replace(/\s+$/,"").trim()),n=s=>{let a=null,i=null;for(let c=s+1;c<Math.min(s+5,e.length)&&!/^Current\s/i.test(e[c]);c++){let l=e[c].match(/(\d+)%\s*used/i);l&&a===null&&(a=Number(l[1]));let u=e[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=e.findIndex(i=>s.test(i));return a<0?null:n(a)},o=[];return e.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 aB(t){let e=String(t||"").split(`
491
+ `).map(s=>s.replace(/\s+$/,"")),n=e.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<e.length&&!r.test(e[s]);s++)e[s].trim()&&o.push(e[s].trim());return o.length?o:null}async function NS({fresh:t=!1}={}){return!t&&Da&&Date.now()-Da.at<MS?Da.data:Ba||(Ba=(async()=>{try{let e=await oB(),n=sB(e),r={...n,contributors:aB(e),subscription:!!(n.session||n.week||n.weekModels),capturedAt:Date.now()};return Da={at:Date.now(),data:r},r}catch(e){let n={session:null,week:null,contributors:null,subscription:!1,error:e?.message||String(e),capturedAt:Date.now()};return Da={at:Date.now()-(MS-3e3),data:n},n}finally{Ba=null}})(),Ba)}var iB=262144;function cB(t){let e=Number(t);if(!Number.isFinite(e)||e<0)return null;let n=Math.floor(e/3600),r=Math.round(e%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 lB=new Set([300]),uB=new Set([10080]);function dB(t){let e=Number(t);return!Number.isFinite(e)||e<=0?null:lB.has(e)?"session":uB.has(e)?"week":"other"}function fB(t){let e=Number(t);return!Number.isFinite(e)||e<=0?"Window":e%1440===0?`Window \xB7 ${e/1440}d`:e%60===0?`Window \xB7 ${e/60}h`:`Window \xB7 ${e}m`}function pB(t,e,n){if(!t||typeof t!="object")return null;let r=Number(t.used_percent);if(!Number.isFinite(r))return null;let o=null,s=Number(t.resets_at),a=Number(t.resets_in_seconds);return Number.isFinite(s)&&s>0?o=s*1e3:Number.isFinite(a)&&a>=0&&(o=(Number.isFinite(e)?e:n)+a*1e3),{pct:Math.round(r),resets:o!=null?cB((o-n)/1e3):null,resetsAt:o}}var ja=t=>({session:null,week:null,other:null,planType:null,credits:null,limitReached:null,sawTokenCount:t});function mB(t,e=Date.now()){let n=String(t||"").split(`
492
+ `),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 ja(r);if(c.primary||c.secondary){let l=Date.parse(a.timestamp)||null,u=ja(r);[c.primary,c.secondary].forEach((p,h)=>{let w=pB(p,l,e);if(!w)return;let y=dB(p.window_minutes);y===null&&(y=h===0?"session":"week"),y==="session"&&!u.session?u.session=w:y==="week"&&!u.week?u.week=w:(u.other??=[]).push({label:fB(p.window_minutes),...w})}),u.planType=typeof c.plan_type=="string"?c.plan_type:null;let d=c.credits;return d&&(d.has_credits||d.unlimited)&&(u.credits={balance:String(d.balance??""),unlimited:!!d.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{...ja(r),session:l(c.primary_used_percent),week:l(c.secondary_used_percent)}}return ja(r)}return ja(r)}async function Sm(t){let e={provider:"codex",supported:!0,contributors:null};try{let n=await mr(t?.cwd,t?.sessionId);if(!n)return{...e,session:null,week:null,subscription:!1,error:"no codex rollout found for this box yet",capturedAt:Date.now()};let r=await Xt(n.file,iB),o=mB(r);return{...e,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{...e,session:null,week:null,subscription:!1,error:n?.message||String(n),capturedAt:Date.now()}}}async function PS(t,{fresh:e=!1}={}){let n=new Set;for(let o of t||[])for(let s of o.boxes||[])s.agent&&n.add(s.agent);let r=[];if((n.has("claude")||n.size===0)&&r.push(await ml({agent:"claude"},{fresh:e})),n.has("codex")){let o=[],s=[...t||[]].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 Sm(i);if(c.subscription){a=c;break}(!a||a.error&&!c.error)&&(a=c)}r.push(a||await Sm(null))}return n.has("cursor")&&r.push(await ml({agent:"cursor"})),{providers:r,capturedAt:Date.now()}}async function ml(t,{fresh:e=!1}={}){let n=t?.agent||"claude";return n==="codex"?Sm(t):n==="cursor"?{provider:"cursor",supported:!1,subscription:!1,session:null,week:null,contributors:null,capturedAt:Date.now()}:{provider:"claude",supported:!0,...await NS({fresh:e})}}ar();Jt();Jt();function hB(t=process.env){return!!(St(t)&&t.BOSTRAT_PLANE_TOKEN)}var wB=t=>({authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`}),hl=(t,e)=>Object.assign(new Error(t),{status:e});async function DS(t,e){if(!hB(e))throw hl("node is not plane-linked \u2014 Gmail unavailable",503);let n;try{n=await fetch(`${St(e)}${t}`,{headers:wB(e)})}catch(o){throw hl(`plane unreachable \u2014 Gmail unavailable (${o?.message||o})`,503)}let r=await n.json().catch(()=>({}));if(!n.ok)throw hl(r?.error||`plane replied ${n.status}`,n.status);return r}async function BS(t,{max:e=10,env:n=process.env}={}){let r=new URLSearchParams({q:t||""});return e&&r.set("max",String(e)),(await DS(`/v1/gmail/messages?${r.toString()}`,n)).messages||[]}async function jS(t,{env:e=process.env}={}){if(!t)throw hl("message id required",400);return(await DS(`/v1/gmail/messages/${encodeURIComponent(t)}`,e)).message}Us();xc();function vm(t){let e=t.split(".");if(e.length!==4)return null;let n=0;for(let r of e){let o=Number(r);if(!Number.isInteger(o)||o<0||o>255)return null;n=n*256+o}return n>>>0}function gB(t){let[e,n]=t.split("/"),r=vm(e);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 LS(t){return(t||"").split(",").map(e=>e.trim()).filter(Boolean).map(gB).filter(Boolean)}function yB(t){let e=t.headers["fly-client-ip"];return typeof e=="string"&&e.trim()?e.trim():(t.socket&&t.socket.remoteAddress||"").replace(/^::ffff:/,"")}function FS(t){let e=LS(t),n=String(t||"").trim().toLowerCase()==="open";return{open:n,clientIp:yB,allowed(r){if(n)return!0;let o=vm((r||"").replace(/^::ffff:/,""));return o==null?!1:e.some(s=>s(o))}}}function US(t,e){let n=LS(t);return{active:n.length>0,allows(r){if(!n.length)return!1;let o=(r.socket&&r.socket.remoteAddress||"").replace(/^::ffff:/,""),s=vm(o);if(s==null||!n.some(i=>i(s)))return!1;let a=e(r);return!!(a&&a.view)}}}import HS from"node:crypto";import wl from"node:fs";import bB from"node:path";function WS(t=process.env,{stateDir:e=Na,log:n=console}={}){let r=String(t.BOSTRAT_NODE_API_TOKEN||"").trim();if(r)return r;let o=bB.join(e,"api-token");try{let a=wl.readFileSync(o,"utf8").trim();if(a)return a}catch{}let s=HS.randomBytes(32).toString("base64url");try{wl.mkdirSync(e,{recursive:!0}),wl.writeFileSync(o,s+`
493
+ `,{mode:384}),wl.chmodSync(o,384)}catch(a){n.error?.(`[bostrat-agent] could not persist the node API token: ${a?.message||a}`)}return s}function La(t){let e=t?.socket?.remoteAddress||"";if(!e)return!1;let n=e.replace(/^::ffff:/,"");return n==="::1"||n==="127.0.0.1"||/^127\./.test(n)}function qS(t,e){if(!t||!e)return!1;let n=Buffer.from(String(t)),r=Buffer.from(String(e));return n.length!==r.length?!1:HS.timingSafeEqual(n,r)}function KS(t,e=null){let n=t?.headers?.["x-bostrat-token"];if(typeof n=="string"&&n.trim())return n.trim();let r=t?.headers?.authorization||"",o=/^Bearer\s+(.+)$/i.exec(r)?.[1];if(o)return o.trim();try{return(e??new URL(t.url,"http://node")).searchParams.get("token")||""}catch{return""}}var kB=[/^\/api\/github\/token\b/,/^\/api\/gmail\b/],xB=t=>kB.some(e=>e.test(t));function GS({token:t,enforce:e=!0,log:n=console}={}){return function(o,s,a){let i=o.path||o.url||"";if(!i.startsWith("/api"))return a();let c=KS(o);return qS(c,t)?a():xB(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"})):!e||La(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 VS(t,e,{enforce:n=!0}={}){return!n||qS(KS(t),e)?!0:La(t)}Ke();yc();yc();import SB from"node:http";import vB from"node:net";function gl(t){if(!t)return null;let e=String(t).replace(/:\d+$/,"").toLowerCase();if(/^[\d.]+$/.test(e)||e.includes(":"))return null;let n=e.split(".");if(n.length<3)return null;let r=n[0];return/^[a-z0-9-]+$/.test(r)?r:null}function yl(t){let e=gl(t.headers.host);return e?{slug:e,view:mf(e)}:null}var TB=t=>String(t??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;"),AB=t=>{let e=TB(t.name);return`<!doctype html><meta charset="utf-8">
467
494
  <meta http-equiv="refresh" content="3">
468
495
  <title>${e} \u2014 starting</title>
469
496
  <body style="font-family:system-ui;background:#0b0e14;color:#dce3f0;display:grid;place-items:center;height:100vh;margin:0">
470
497
  <div style="text-align:center"><p style="font-size:2rem;margin:0">\u23F3</p>
471
- <p><b>${e}</b> is waking up\u2026</p><p style="opacity:.6">auto-refreshing</p></div>`};function AS(t,e,n){let r=sl(t);if(!r)return n();let{view:o,slug:s}=r;if(!o)return e.statusCode=404,e.setHeader("content-type","text/plain"),e.end(`bostrat: no view named "${s}"`);if(o.state==="starting")return e.statusCode=503,e.setHeader("content-type","text/html"),e.end(VB(o));if(o.state!=="live"&&o.state!=="unhealthy")return e.statusCode=404,e.setHeader("content-type","text/plain"),e.end(`bostrat: view "${s}" is ${o.state} \u2014 restart it from the Views tab`);let a={...t.headers,host:`127.0.0.1:${o.port}`,"x-forwarded-host":t.headers.host,"x-forwarded-proto":t.headers["x-forwarded-proto"]||"http"};delete a.authorization,delete a.cookie;let i=qB.request({host:"127.0.0.1",port:o.port,method:t.method,path:t.url,headers:a},c=>{e.writeHead(c.statusCode||502,c.headers),c.pipe(e)});i.on("error",()=>{e.headersSent?e.destroy():(e.statusCode=502,e.setHeader("content-type","text/plain"),e.end(`bostrat: view "${s}" did not answer on :${o.port}`))}),t.pipe(i),t.on("aborted",()=>i.destroy())}function ES(t,e,n){let r=sl(t);if(!r)return!1;let{view:o,slug:s}=r;if(!o||o.state!=="live"&&o.state!=="unhealthy")return e.write(`HTTP/1.1 404 Not Found\r
498
+ <p><b>${e}</b> is waking up\u2026</p><p style="opacity:.6">auto-refreshing</p></div>`};function zS(t,e,n){let r=yl(t);if(!r)return n();let{view:o,slug:s}=r;if(!o)return e.statusCode=404,e.setHeader("content-type","text/plain"),e.end(`bostrat: no view named "${s}"`);if(o.state==="starting")return e.statusCode=503,e.setHeader("content-type","text/html"),e.end(AB(o));if(o.state!=="live"&&o.state!=="unhealthy")return e.statusCode=404,e.setHeader("content-type","text/plain"),e.end(`bostrat: view "${s}" is ${o.state} \u2014 restart it from the Views tab`);let a={...t.headers,host:`127.0.0.1:${o.port}`,"x-forwarded-host":t.headers.host,"x-forwarded-proto":t.headers["x-forwarded-proto"]||"http"};delete a.authorization,delete a.cookie;let i=SB.request({host:"127.0.0.1",port:o.port,method:t.method,path:t.url,headers:a},c=>{e.writeHead(c.statusCode||502,c.headers),c.pipe(e)});i.on("error",()=>{e.headersSent?e.destroy():(e.statusCode=502,e.setHeader("content-type","text/plain"),e.end(`bostrat: view "${s}" did not answer on :${o.port}`))}),t.pipe(i),t.on("aborted",()=>i.destroy())}function JS(t,e,n){let r=yl(t);if(!r)return!1;let{view:o,slug:s}=r;if(!o||o.state!=="live"&&o.state!=="unhealthy")return e.write(`HTTP/1.1 404 Not Found\r
472
499
  \r
473
500
  bostrat: no live view "${s}"\r
474
- `),e.destroy(),!0;let a=KB.connect(o.port,"127.0.0.1",()=>{let c=[`${t.method} ${t.url} HTTP/1.1`];for(let[l,u]of Object.entries(t.headers))l!=="host"&&(l==="authorization"||l==="cookie"||c.push(`${l}: ${Array.isArray(u)?u.join(", "):u}`));c.push(`host: 127.0.0.1:${o.port}`),a.write(c.join(`\r
501
+ `),e.destroy(),!0;let a=vB.connect(o.port,"127.0.0.1",()=>{let c=[`${t.method} ${t.url} HTTP/1.1`];for(let[l,u]of Object.entries(t.headers))l!=="host"&&(l==="authorization"||l==="cookie"||c.push(`${l}: ${Array.isArray(u)?u.join(", "):u}`));c.push(`host: 127.0.0.1:${o.port}`),a.write(c.join(`\r
475
502
  `)+`\r
476
503
  \r
477
- `),n?.length&&a.write(n),e.pipe(a),a.pipe(e)}),i=()=>{a.destroy(),e.destroy()};return a.on("error",i),e.on("error",i),!0}function _S(t,e){let n=typeof e=="string"?{host:e}:e||{},r=n["x-bostrat-view-base"];return typeof r=="string"&&r?`${n["x-forwarded-proto"]==="https"?"https":"http"}://${t.slug}.${r.replace(/:\d+$/,"")}/`:`http://${t.slug}.${zB(n.host)}/`}function zB(t){if(process.env.BOSTRAT_PUBLIC_HOST)return String(process.env.BOSTRAT_PUBLIC_HOST).replace(/:\d+$/,"");let e=String(t||"").replace(/:\d+$/,"").toLowerCase();if(!e||!e.includes(".")||/^[\d.]+$/.test(e))return"bostrat.globopi";let n=e.split(".");return ol(e)&&tf(n[0])?n.slice(1).join("."):e}Ao();vf();gc();Qt();var IS=1e4,RS=(...t)=>fetch(...t);function $S(t=process.env){return!!(vt(t)&&t.BOSTRAT_PLANE_TOKEN)}async function OS({loopId:t,outcome:e,note:n=null,env:r=process.env}={}){if(!$S(r))return{ok:!1,source:"unconfigured"};let o=new AbortController,s=setTimeout(()=>o.abort(),IS);try{let a=await RS(`${vt(r)}/v1/loops/${encodeURIComponent(t)}/report`,{method:"POST",headers:{authorization:`Bearer ${r.BOSTRAT_PLANE_TOKEN||""}`,"content-type":"application/json"},body:JSON.stringify({outcome:e,...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 Qp({env:t=process.env}={}){if(!$S(t))return{loops:[],source:"unconfigured"};let e=new AbortController,n=setTimeout(()=>e.abort(),IS);try{let r=await RS(`${vt(t)}/v1/loops`,{headers:{authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`},signal:e.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)}}bn();ct();Bn();gc();var CS=10,MS=200,JB=120,YB=24,XB=/^\d{4}-\d{2}-\d{2}$/;function tm(t=process.env){return(t.CHANGELOG_REPOS||"globocodes/bostrat").split(",").map(e=>e.trim()).filter(Boolean)}var ZB=(t=Date.now())=>new Date(t).toISOString().slice(0,10);function PS(t,e=Date.now()){if(!t)return e-24*36e5;let n=/^(\d+)\s*([hd])$/.exec(String(t).trim());if(n)return e-Number(n[1])*(n[2]==="h"?36e5:24*36e5);let r=Date.parse(t);if(!Number.isNaN(r))return r;throw new Error(`unparseable since "${t}" \u2014 use 24h, 7d, or an ISO date`)}var QB=/^\*\*([^*]+?)\*\*\s*[:.]?\s*[—–-]?\s*(.*)$/;function tD(t){if(typeof t!="string"||!t.trim())throw new Error("md (markdown string) required");let e=Zs(t);if(e.length)throw new Error(`changelog entry appears to contain a secret VALUE (${e.join(", ")}) \u2014 entries ship off-box; never put a credential in one. Replace it and retry.`);let n=null,r=[];for(let o of t.split(`
478
- `)){let s=o.trim();if(!s)continue;if(s.startsWith("#")){n==null&&(n=s.replace(/^#+\s*/,"").trim().slice(0,JB)||null);continue}let a=/^[-*]\s+(.*)$/.exec(s);if(!a)continue;let i=a[1].trim(),c=null,l=new RegExp(`^\\[([^\\]]{1,${YB}})\\]\\s+(.*)$`).exec(i);if(l&&(c=l[1].trim(),i=l[2].trim()),!i)continue;let u=QB.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.`);if(i=`**${u[1].trim().replace(/[:.]\s*$/,"")}** \u2014 ${u[2].trim()}`,i.length>MS)throw new Error(`bullet ${r.length+1} is ${i.length} chars \u2014 over the ${MS}-char cap; a changelog bullet is one line`);r.push({text:i,...c?{area:c}:{}})}if(!r.length)throw new Error("no `- ` bullets found \u2014 an entry is a bullet list, optionally under a `# headline`");if(r.length>CS)throw new Error(`${r.length} bullets \u2014 over the ${CS}-bullet cap; group related changes into one line`);return{title:n||null,bullets:r}}async function NS(t,{repos:e=tm()}={}){let n=new Set(e);return(await kr()).filter(r=>r.state==="merged"&&(r.resolvedAt??0)>=t&&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,mergedAt:r.resolvedAt??null}))}async function BS(t,{md:e,day:n=null}){let r=tD(e),o=n==null||n===""?ZB():String(n);if(!XB.test(o)||Number.isNaN(Date.parse(o)))throw new Error(`invalid day "${n}" \u2014 expected YYYY-MM-DD`);let s=await I({id:t.id,cwd:t.cwd},{type:"changelog.published",actor:"agent",source:"orchestrator",boxId:t.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}}zs();Bn();ct();zs();Qt();xr();Bn();Cs();cc();import{execFile as eD}from"node:child_process";import{promisify as nD}from"node:util";var nm=nD(eD),DS=3e4,rD=30*6e4,oD=DS,sD=10*6e4,aD=10080*6e4,iD=60*6e4,cD=8,lD=1440*6e4,uD=3,jS="number,url,title,headRefName,headRefOid,state,mergedAt,closedAt",em=60*6e4,dD=15*6e4,al=new Map,il=new Map,fD=/could not resolve|not found|no pull requests?/i,pD=t=>fD.test(String(t?.message||t||""));function mD(t,e){return[t.ciFix?.delegatedAt,t.reconcile?.delegatedAt,t.ciFixAwait?.since,t.reconcileAwait?.since].some(n=>n&&e-n<em)}var LS={fast:oD,slow:sD,decay:iD};function FS(t,e){return t.armedAt&&e-t.armedAt<rD||mD(t,e)?"fast":e-(t.firstSeen||0)>aD?"decay":"slow"}function hD(t,e){return LS[FS(t,e)]}function Ca(t,e,n,r){let o=t.lanes?.get(V(e.repo,e.number))||{};return ic({change:n,repo:e.repo,number:Number(e.number),githubAt:r||null,lane:o.lane||null,intervalMs:o.intervalMs||null,source:"watch"})}async function wD(t,e){ze("watch");try{let{stdout:n}=await nm("gh",["pr","view",String(e),"--repo",t,"--json",jS],{timeout:3e4,maxBuffer:4194304,env:{...process.env,...await Ae({slug:t})}});return JSON.parse(n||"null")}catch(n){throw Cn(n)&&Mn(n),n}}async function gD(t){ze("watch");try{let{stdout:e}=await nm("gh",["pr","list","--repo",t,"--state","all","--limit","100","--json",jS],{timeout:3e4,maxBuffer:8388608,env:{...process.env,...await Ae({slug:t})}}),n=new Map;for(let r of JSON.parse(e||"[]"))n.set(Number(r.number),r);return n}catch(e){throw Cn(e)&&Mn(e),e}}async function yD(){let t=new Map;for(let e of await et().catch(()=>[]))t.set(e.id,e);return t}async function bD(t,e){await I({id:t.id,cwd:t.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"merged",...e}})}async function kD(t,e){let n=await vr(t);return n?xo(n,e):null}async function xD(t,e,n){let r=await vr(t);if(!r)throw new Error(`no local checkout for ${t}`);return So(r,e,{method:n})}async function SD(t,e){let n=await vr(t);if(!n)throw new Error(`no local checkout for ${t}`);return Vs(n,e)}async function vD(t,e){await I({id:t.id,cwd:t.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"auto-canceled",...e}})}async function Ko(t,e,n,r,o){if(!await r.disarm(t.repo,t.number).catch(()=>null))return;let a=n.get(t.trackId);a&&await r.emitDisarmed(a,{number:Number(t.number),url:e?.url||t.url,title:e?.title||t.title,branch:e?.headRefName||t.headRef,repo:t.repo,reason:o}).catch(()=>{})}var TD=10*6e4;async function AD(t,e,n){let r=t.autoMerge?.armedAt||0;if(r&&(n.now??Date.now())-r>lD){await Ko(t,null,e,n,"auto-merge expired \u2014 checks never settled within 24h");return}let o=await n.detail(t.repo,t.number).catch(()=>null);if(!o)return;if(o.checks.failed>0){let a=o.checks.failing.map(i=>i.name).join(", ");await Ko(t,o,e,n,`check${o.checks.failed===1?"":"s"} failed: ${a}`);return}if(o.mergeable==="CONFLICTING"){await Ko(t,o,e,n,`conflicts with ${o.baseRefName}`);return}if(!o.checks.total){let a=Math.max(t.autoMerge?.armedAt||0,Date.parse(o.updatedAt||"")||0);if((n.now??Date.now())-a<TD)return;await Ko(t,o,e,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(t.repo,t.number).catch(()=>null);if(s?.autoMerge){if(o.mergeStateStatus==="BEHIND"){try{await n.updateBranch(t.repo,t.number)}catch(a){let i=String(a?.message||a).trim();/no new commits|already up.to.date/i.test(i)||await Ko(t,o,e,n,i||`couldn't update with ${o.baseRefName}`)}return}try{await n.merge(t.repo,t.number,s.autoMerge.method||"merge")}catch(a){if(/already merged|not open|is closed/i.test(String(a?.message||a)))return;await Ko(t,o,e,n,String(a?.message||a).trim()||"merge failed");return}await US(t,{...o,state:"MERGED"},e,n,{change:"auto-merged",githubAt:o.checks.settledAt||null})}}async function Ra(t,e,n){await I({id:t.id,cwd:t.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:e,...n}})}async function ED(t,e){try{return await nm("git",["-C",t.cwd,"cat-file","-e",`${e}^{commit}`],{timeout:1e4}),!0}catch{return!1}}async function $a(t,e,n,r=()=>!0){return(await L(t).catch(()=>[])).some(s=>s.type==="pr.state.changed"&&s.payload?.change===e&&s.payload?.number===Number(n)&&r(s))}var Oa=(t,e)=>({number:Number(t.number),url:e?.url||t.url,title:e?.title||t.title,branch:e?.headRefName||t.headRef,repo:t.repo});async function _D(t,e,n,r){let o=r.now??Date.now(),s=e.headRefOid||null,a=n.get(t.trackId)||null;if(s&&(t.ciFix?.headSha&&s!==t.ciFix.headSha&&await Ki(t.repo,t.number,{headSha:s}).catch(()=>{}),t.reconcile?.headSha&&s!==t.reconcile.headSha&&await Vi(t.repo,t.number,{headSha:s}).catch(()=>{})),s&&s!==t.lastHeadSha){let i=!t.lastHeadSha,c=!!(t.ciFix||t.reconcile||t.ciFixAwait||t.reconcileAwait),l=!!t.baseFoldAt&&o-t.baseFoldAt<dD;await ab(t.repo,t.number,s).catch(()=>{}),t.baseFoldAt&&await sb(t.repo,t.number).catch(()=>{}),!i&&!c&&!l&&a&&!await r.localHasCommit(a,s).catch(()=>!1)&&!await $a(a,"pushed",t.number,d=>d.payload?.sha===s)&&await Ra(a,"pushed",{...Oa(t,e),sha:s}).catch(()=>{})}if(t.ciFixAwait)if(o-(t.ciFixAwait.since||0)>em)await Gi(t.repo,t.number).catch(()=>{});else{let i=await r.detail(t.repo,t.number).catch(()=>null);if(i?.checks){if(i.checks.failed>0)await Gi(t.repo,t.number).catch(()=>{});else if(i.checks.total>0&&i.checks.pending===0){let c=Ca(r,t,"ci-fixed",i.checks.settledAt||null),l=t.ciFixAwait.since||0;a&&!await $a(a,"ci-fixed",t.number,u=>(u.payload?.ts||0)>=l)&&await Ra(a,"ci-fixed",{...Oa(t,e),passed:i.checks.passed,githubAt:c.githubAt,latencyMs:c.latencyMs,lane:c.lane}).catch(()=>{}),await Gi(t.repo,t.number).catch(()=>{})}}}if(t.reconcileAwait)if(o-(t.reconcileAwait.since||0)>em)await zi(t.repo,t.number).catch(()=>{});else{let i=await r.detail(t.repo,t.number).catch(()=>null);if(i){if(i.mergeable==="CONFLICTING")await zi(t.repo,t.number).catch(()=>{});else if(i.mergeable==="MERGEABLE"){Ca(r,t,"reconciled",null);let c=t.reconcileAwait.since||0;a&&!await $a(a,"reconciled",t.number,l=>(l.payload?.ts||0)>=c)&&await Ra(a,"reconciled",{...Oa(t,e),base:i.baseRefName||null}).catch(()=>{}),await zi(t.repo,t.number).catch(()=>{})}}}}async function ID(t,e,n,r){let o=Ca(r,t,"closed",Date.parse(e?.closedAt||"")||null),s=n.get(t.trackId);s&&!await $a(s,"closed",t.number)&&await Ra(s,"closed",{...Oa(t,e),githubAt:o.githubAt,latencyMs:o.latencyMs,lane:o.lane}).catch(()=>{}),await r.notifyIfResolved(t.repo,t.number,"closed").catch(()=>{}),await r.mark(t.repo,t.number,"closed").catch(()=>{})}async function RD(t,e,n){Ca(n,t,"lost",null);let r=e.get(t.trackId);r&&!await $a(r,"lost",t.number)&&await Ra(r,"lost",Oa(t,null)).catch(()=>{}),await n.notifyIfResolved(t.repo,t.number,"lost").catch(()=>{}),await n.mark(t.repo,t.number,"lost").catch(()=>{})}async function US(t,e,n,r,o={}){let s=Ca(r,t,o.change||"merged",o.githubAt??(Date.parse(e.mergedAt||"")||null)),a=n.get(t.trackId);a&&((await L(a).catch(()=>[])).some(l=>l.type==="pr.state.changed"&&l.payload?.change==="merged"&&l.payload?.number===Number(t.number))||await r.emitMerged(a,{number:Number(t.number),url:e.url||t.url,title:e.title||t.title,branch:e.headRefName||t.headRef,repo:t.repo,githubAt:s.githubAt,latencyMs:s.latencyMs,lane:s.lane}).catch(()=>{})),await r.notifyIfArmed(t.repo,t.number).catch(()=>{}),await r.archiveIfArmed(t.repo,t.number).catch(()=>{}),await r.mark(t.repo,t.number,"merged").catch(()=>{})}async function $D(t={}){let{now:e=Date.now(),auth:n=sf,view:r=wD,list:o=gD,links:s=cb,trackMap:a=yD,emitMerged:i=bD,mark:c=Nn,archiveIfArmed:l=Je,notifyIfArmed:u=Ye,notifyIfResolved:d=Ic,batchThreshold:f=uD,detail:p=kD,merge:m=xD,updateBranch:w=SD,lookup:y=Wt,disarm:k=Bs,emitDisarmed:S=vD,localHasCommit:$=ED}=t;if(!(await n().catch(()=>null))?.authenticated||Wi()>0)return 0;let C=(await s().catch(()=>[])).filter(E=>e-(al.get(V(E.repo,E.number))||0)>=hD(E,e));if(!C.length)return 0;let D=Date.now(),A=new Map,N=new Map;for(let E of C){let O=FS(E,e);A.set(V(E.repo,E.number),{lane:O,intervalMs:LS[O]}),al.set(V(E.repo,E.number),e),N.has(E.repo)||N.set(E.repo,[]),N.get(E.repo).push(E)}let W=await a().catch(()=>new Map),at={now:e,lanes:A,emitMerged:i,mark:c,archiveIfArmed:l,notifyIfArmed:u,notifyIfResolved:d,detail:p,merge:m,updateBranch:w,lookup:y,disarm:k,emitDisarmed:S,localHasCommit:$};for(let[E,O]of N){let At,Gt=new Set;if(O.length>f)At=await o(E).catch(()=>null);else{At=new Map;for(let gt of O)try{let g=await r(E,gt.number);g?.number!=null&&At.set(Number(g.number),g)}catch(g){pD(g)&&Gt.add(V(gt.repo,gt.number))}}if(At)for(let gt of O){let g=V(gt.repo,gt.number),h=At.get(Number(gt.number));if(!h){if(Gt.has(g)){let T=(il.get(g)||0)+1;il.set(g,T),T>=cD&&(await RD(gt,W,at),il.delete(g),al.delete(g))}continue}il.delete(g),h.state==="MERGED"||h.state==="CLOSED"?(h.state==="MERGED"?await US(gt,h,W,at):await ID(gt,h,W,at),al.delete(g)):(await _D(gt,h,W,at).catch(()=>{}),gt.autoMerge&&await AD(gt,W,at).catch(()=>{}))}}let it={};for(let{lane:E}of A.values())it[E]=(it[E]||0)+1;return console.log(`[pr-watch] probed ${C.length} link(s) (${Object.entries(it).map(([E,O])=>`${E} ${O}`).join(", ")}) in ${Date.now()-D}ms`),C.length}function HS(){let t=!1;setInterval(async()=>{if(!t){t=!0;try{await $D()}catch{}finally{t=!1}}},DS)}Ht();ct();xr();import{randomUUID as OD}from"node:crypto";var CD=2e4,WS=3,Go=new Map,rm=new Set;async function qS(t,e,n){let r=await n(t).catch(()=>[]),o=null;for(let s of r)s.type==="box.fullscreen.detected"&&s.boxId===e?o=s.payload?.offerId||null:s.type==="box.fullscreen.answered"&&o&&s.payload?.offerId===o&&(o=null);return o}async function MD(t={}){let{sessions:e=null,tracks:n=null,append:r=I,read:o=L,now:s=Date.now()}=t;if(process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1")return;let a,i;try{a=e??await he(),i=n??await et()}catch{return}let c=new Map(a.map(u=>[u.name,u])),l=new Set;for(let u of i){if(u.archivedAt||!u.leadBox)continue;let d=(u.boxes||[]).find(p=>p.name===u.leadBox);if(!d||d.agent!=="claude"||d.state!=="live")continue;let f=c.get(d.name);if(f)if(l.add(d.name),f.alternateOn){let p=(Go.get(d.name)||0)+1;Go.set(d.name,p),p===WS&&(rm.add(d.name),await qS(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:OD(),box:d.name,agent:d.agent}}).catch(()=>{}))}else{let p=(Go.get(d.name)||0)>=WS;if(Go.delete(d.name),p||!rm.has(d.name)){rm.add(d.name);let m=await qS(u,d.name,o);m&&await r(u,{type:"box.fullscreen.answered",actor:"system",source:"orchestrator",boxId:d.name,provider:d.agent,payload:{ts:s,offerId:m,action:"cleared"}}).catch(()=>{})}}}for(let u of[...Go.keys()])l.has(u)||Go.delete(u)}var Ma=null,om=!1;function KS(){return Ma?()=>{}:(Ma=setInterval(()=>{om||(om=!0,MD().catch(()=>{}).finally(()=>{om=!1}))},CD),Ma.unref?.(),()=>{clearInterval(Ma),Ma=null})}ho();pf();ct();zs();ho();import{randomUUID as PD}from"node:crypto";async function ND(){let t=await Promise.resolve().then(()=>(xr(),J0));return{sayToLead:t.sayToLead,queueShipCompleteNotify:t.queueShipCompleteNotify}}var sm={listRepoPrs:Sr,readEvents:L,appendEvent:I,sayDeps:ND};async function BD(t,e=sm){let n=t?.workspace?.branch;if(!n||!t?.cwd)return null;let r;try{r=await e.listRepoPrs(t.cwd,{caller:"pr-exists"})}catch{return null}let o=(r||[]).find(s=>s.headRefName===n);return o?{number:o.number,url:o.url??null,title:o.title??null}:null}async function am(t,e,{actions:n,notify:r=!1}={},o=sm){let s=e?.payload||{};if(!Array.isArray(n)||!n.includes("pr")||s.toPr||Array.isArray(s.repos)&&s.repos.length||!s.branch)return null;let a=await BD(t,o);if(!a)return null;let i={id:t.id,cwd:t.cwd};await o.appendEvent(i,{type:"pr.offer.answered",actor:"user",source:"orchestrator",boxId:e.boxId,payload:{ts:Date.now(),offerId:s.offerId,action:"pr-exists",actions:n,...r?{notify:!0}:{},existingPr:{number:a.number}}});let c=PD();return await o.appendEvent(i,{type:"pr.exists.offered",actor:"system",source:"orchestrator",boxId:e.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 im(t,{offerId:e,choice:n}={},r=sm){if(!e)throw new Error("offerId required");if(!["push","new","dismiss"].includes(n))throw new Error('choice "push" | "new" | "dismiss" required');let o=await r.readEvents(t),s=o.find(u=>u.type==="pr.exists.offered"&&u.payload?.offerId===e);if(!s)throw new Error("unknown offer");if(o.some(u=>u.type==="pr.exists.answered"&&u.payload?.offerId===e))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=Fi.filter(d=>d!=="pr"&&(i.includes(d)||d==="push")),c=await u(t.id,mo(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(t.id,Fy(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:t.id,cwd:t.cwd},{type:"pr.exists.answered",actor:"user",source:"orchestrator",boxId:s.boxId,payload:{ts:Date.now(),offerId:e,choice:n}}),n!=="dismiss"&&a.notify===!0){let{queueShipCompleteNotify:u}=await r.sayDeps();u(t.id,{actions:l})}return{say:c,choice:n}}import fn from"node:fs/promises";import Vo from"node:path";import ZS from"node:os";import GS from"node:fs/promises";import cl from"node:path";import{execFile as DD}from"node:child_process";import{promisify as jD}from"node:util";import{fileURLToPath as LD}from"node:url";var FD=jD(DD),zS=cl.dirname(LD(import.meta.url)),UD=cl.resolve(zS,"..","..","client","dist"),HD="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",WD=new Map([...HD].map((t,e)=>[t,e]));function qD(t){let e=[],n=0,r=0;for(let o of t){let s=WD.get(o);if(s===void 0)return e;n+=(s&31)<<r,s&32?r+=5:(e.push(n&1?-(n>>>1):n>>>1),n=0,r=0)}return e}function KD(t){let e=[],n=0,r=0,o=0;for(let s of t.split(";")){let a=[],i=0;if(s)for(let c of s.split(",")){let l=qD(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])))}e.push(a)}return e}function GD(t,e){if(!t||t.length===0||t[0][0]>e)return null;let n=0,r=t.length-1;for(;n<r;){let o=n+r+1>>1;t[o][0]<=e?n=o:r=o-1}return t[n]}var VS=new Map;async function VD(t){let e;try{e=await GS.stat(t)}catch{return null}let n=VS.get(t);if(n&&n.mtimeMs===e.mtimeMs)return n;try{let r=JSON.parse(await GS.readFile(t,"utf8")),o={mtimeMs:e.mtimeMs,sources:r.sources||[],lines:KD(r.mappings||"")};return VS.set(t,o),o}catch{return null}}var cm=null;function zD(){return cm||(cm=process.env.BOSTRAT_RELEASE?Promise.resolve(process.env.BOSTRAT_RELEASE):FD("git",["rev-parse","--short","HEAD"],{cwd:cl.resolve(zS,"..","..")}).then(t=>t.stdout.trim()).catch(()=>null)),cm}var JD=/(?:https?:\/\/[^\s()]*)?\/assets\/([^\s()/]+\.js):(\d+):(\d+)/g;async function YD(t,{distDir:e=UD}={}){let n=[],r=0,o=!1;for(let s of t.matchAll(JD)){let[a,i,c,l]=s,u=await VD(cl.join(e,"assets",`${i}.map`)),d=u?GD(u.lines[Number(c)-1],Number(l)-1):null;if(n.push(t.slice(r,s.index)),d&&u.sources[d[1]]){let f=u.sources[d[1]].replace(/^(\.\.\/)+/,"");n.push(`${f}:${d[2]+1}:${d[3]+1}`),o=!0}else n.push(a);r=s.index+a.length}return n.push(t.slice(r)),{stack:n.join(""),symbolicated:o}}async function JS(t,e={}){try{if(!t?.error?.stack||!t.release||t.release==="unknown")return t;let n=e.release??await zD();if(!n||t.release!==n)return t;let{stack:r,symbolicated:o}=await YD(t.error.stack,e);o&&(t.error.stack=r,t.error.symbolicated=!0)}catch{}return t}var XD=()=>process.env.BOSTRAT_STATE_DIR||Vo.join(process.env.HOME||ZS.tmpdir(),".bostrat"),Zn=()=>Vo.join(XD(),"telemetry"),QS=()=>Vo.join(Zn(),".relay-offsets.json"),ZD=50,QD=14,t1=3e4,YS=500,re=(t,e)=>typeof t=="string"?t.slice(0,e):"";function e1(t,e){if(!t||typeof t!="object")return null;let n=re(t.name,64);if(!n)return null;let r=Number.isFinite(t.ts)?t.ts:e,o={name:n,ts:Math.abs(r-e)<168*3600*1e3?r:e,receivedAt:e,anonId:re(t.anonId,64),sessionId:re(t.sessionId,64),userId:re(t.userId,64),release:re(t.release,64),appVersion:re(t.appVersion,32),route:re(t.route,128),deviceClass:t.deviceClass==="phone"||t.deviceClass==="desktop"?t.deviceClass:""};return t.props&&typeof t.props=="object"&&!Array.isArray(t.props)&&(JSON.stringify(t.props).length<=8192?o.props=t.props:o.props={clamped:!0}),t.error&&typeof t.error=="object"&&(o.error={kind:re(t.error.kind,256),message:re(t.error.message,8192),stack:re(t.error.stack,32768),fingerprint:re(t.error.fingerprint,64)}),Array.isArray(t.breadcrumbs)&&(o.breadcrumbs=t.breadcrumbs.slice(-50).map(s=>({t:Number.isFinite(s?.t)?s.t:0,n:re(s?.n,64),r:re(s?.r,128)}))),o}var tv=t=>new Date(t).toISOString().slice(0,10),XS=0;async function ev(t,e=Date.now()){let r=(Array.isArray(t?.events)?t.events.slice(0,ZD):[]).map(s=>e1(s,e)).filter(Boolean);if(!r.length)return 0;for(let s of r)s.error?.stack&&await JS(s);await fn.mkdir(Zn(),{recursive:!0});let o=Vo.join(Zn(),`${tv(e)}.ndjson`);return await fn.appendFile(o,r.map(s=>JSON.stringify(s)+`
479
- `).join(""),"utf8"),e-XS>6*3600*1e3&&(XS=e,n1(e).catch(()=>{})),r.length}async function n1(t=Date.now()){let e=tv(t-QD*24*3600*1e3),n=[];try{n=await fn.readdir(Zn())}catch{return}let r=n.filter(s=>s.endsWith(".ndjson")&&s.slice(0,10)<e);if(!r.length)return;for(let s of r)await fn.rm(Vo.join(Zn(),s),{force:!0});let o=await rv();for(let s of r)delete o[s];await ov(o)}var ll=new Map;function nv(t,e=Date.now()){let n=t||"unknown",r=ll.get(n);return r||(ll.size>512&&ll.clear(),r={tokens:40,at:e},ll.set(n,r)),r.tokens=Math.min(40,r.tokens+(e-r.at)/6e4*20),r.at=e,r.tokens<1?!1:(r.tokens-=1,!0)}async function rv(){try{return JSON.parse(await fn.readFile(QS(),"utf8"))||{}}catch{return{}}}async function ov(t){await fn.mkdir(Zn(),{recursive:!0}),await fn.writeFile(QS(),JSON.stringify(t),"utf8")}function r1(t,{env:e,host:n}={}){let r=t.name==="app.error"&&t.error,o={};for(let[a,i]of[["event",t.name],["route",t.route],["session",t.sessionId],["anon",t.anonId],["user",t.userId],["release",t.release],["appVersion",t.appVersion],["device",t.deviceClass]])i&&(o[a]=i);let s={timestamp:new Date(t.ts).toISOString(),service:"bostrat-client",source:"treetop-js",env:e||process.env.BOSTRAT_ENV||"pi",host:n||ZS.hostname(),level:r?"error":"info",message:r?`${t.error.kind||"Error"}: ${t.error.message||"(no message)"}`.slice(0,8192):t.name,tags:o,attributes:{...t.props?{props:t.props}:{},receivedAt:t.receivedAt}};return r&&(s.error={kind:t.error.kind,message:t.error.message,stack:t.error.stack},t.error.fingerprint&&(s.fingerprint=t.error.fingerprint),t.error.symbolicated&&(s.attributes.symbolicated=!0),t.breadcrumbs&&(s.attributes.breadcrumbs=t.breadcrumbs)),s}async function o1({fetchImpl:t=fetch}={}){let e=await rx();if(!e)return{sent:0,disabled:!0};let n;try{n=(await fn.readdir(Zn())).filter(s=>s.endsWith(".ndjson")).sort()}catch{return{sent:0,disabled:!1}}let r=await rv(),o=0;for(let s of n){let a=Vo.join(Zn(),s),i=r[s]||0,c;try{let f=await fn.open(a,"r");try{let p=(await f.stat()).size;if(p<=i)continue;c=Buffer.alloc(p-i),await f.read(c,0,c.length,i)}finally{await f.close()}}catch{continue}let l=c.lastIndexOf(10);if(l<0)continue;let u=c.toString("utf8",0,l+1).split(`
480
- `).filter(Boolean),d=[];for(let f of u)try{d.push(JSON.parse(f))}catch{}for(let f=0;f<d.length;f+=YS){let p=d.slice(f,f+YS).map(w=>r1(w)),m=await t(`${e.url.replace(/\/$/,"")}/v1/logs`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${e.ingestKey}`},body:JSON.stringify({events:p})}).catch(()=>null);if(!m||!m.ok)return{sent:o,disabled:!1};o+=p.length}r[s]=i+l+1,await ov(r)}return{sent:o,disabled:!1}}var lm=null,um=!1;function sv(){lm||(lm=setInterval(async()=>{if(!um){um=!0;try{await o1()}catch(t){console.error("[telemetry] relay failed:",t?.message||t)}finally{um=!1}}},t1),lm.unref?.())}import dl from"node:fs/promises";import uv from"node:path";import s1 from"node:os";var dv=()=>process.env.BOSTRAT_STATE_DIR||uv.join(process.env.HOME||s1.tmpdir(),".bostrat"),fv=()=>uv.join(dv(),"dictation-glossary.json"),a1=100,i1=500,c1=["bostrat","globopi","codex","tmux","worktree","Deepgram","Linear","Firecracker","Tigris","WireGuard","misous","postyx","cedar","gerbil","Anthropic","Opus","Haiku","Sonnet","keyterm","monorepo","dogfood"],fl=null,dm=null,fm=Promise.resolve();function av(){let t={},e=Date.now();for(let n of c1)t[n.toLowerCase()]={term:n,count:1,lastUsed:e,source:"seed"};return t}async function pv(){return fl||(dm??=dl.readFile(fv(),"utf8").then(t=>JSON.parse(t)?.terms??av()).catch(()=>av()).then(t=>fl=t).finally(()=>dm=null),dm)}async function iv(){let t=JSON.stringify({terms:fl},null,2),e=fv(),n=`${e}.${process.pid}.tmp`;await dl.mkdir(dv(),{recursive:!0}),await dl.writeFile(n,t),await dl.rename(n,e)}function l1(){return fm=fm.then(iv,iv),fm.catch(()=>{})}async function pm(){return Object.values(await pv()).sort((e,n)=>n.count-e.count||n.lastUsed-e.lastUsed)}var u1=t=>Math.max(1,Math.ceil(t.length/4));async function d1(){let t=[],e=0;for(let{term:n}of await pm()){let r=u1(n);if(!(e+r>i1)&&(t.push(n),e+=r,t.length>=a1))break}return t}async function f1(t,e){let n=await pv(),r=t.toLowerCase(),o=n[r];n[r]={term:t,count:(o?.count??0)+1,lastUsed:Date.now(),source:o?.source??e}}var cv=t=>(t||"").split(/\s+/).map(e=>e.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"")).filter(Boolean),ul=t=>t.toLowerCase();function lv(t){return!new RegExp("\\p{L}","u").test(t)||t.length<3?!1:/^[a-z]+$/.test(t)?t.length>=4:!0}async function mv(t,e){let n=cv(t),r=cv(e);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]=ul(n[u])===ul(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;)ul(n[c])===ul(r[l])?(c++,l++):a[c+1][l]>=a[c][l+1]?c++:(lv(r[l])&&i.add(r[l]),l++);for(;l<s;l++)lv(r[l])&&i.add(r[l]);if(!i.size)return[];for(let u of i)await f1(u,"learned");return await l1(),[...i]}var Pa=null;function p1(t,e){let n=null;try{n=JSON.parse(e)}catch{}let r=n?.err_code||n?.error_code||n?.category||"";return t===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."}:t===401||t===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 ${t}: ${e.slice(0,300)}`}}async function hv(){if(!Pa)return null;let t=await wa();if(!t||t.apiKey.slice(-6)!==Pa.keyTail)return null;let{keyTail:e,...n}=Pa;return n}async function wv(t,e){let n=await wa();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 d1())r.searchParams.append("keyterm",i);let o=await fetch(r,{method:"POST",headers:{Authorization:`Token ${n.apiKey}`,"Content-Type":e||"application/octet-stream"},body:t});if(!o.ok){let i=await o.text().catch(()=>""),c=p1(o.status,i);c.persistent&&(Pa={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 Pa=null,{transcript:(await o.json())?.results?.channels?.[0]?.alternatives?.[0]?.transcript??""}}ct();var mm={"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 m1(t){if(!t)return null;let e=String(t).trim();if(mm[e])return e;let n=null;for(let r of Object.keys(mm))e.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function h1(t,e={}){let n=mm[m1(t)];if(!n)return 0;let r=0;for(let o of Object.keys(n))r+=(Number(e[o])||0)*n[o];return r/1e6}function w1(t,e){let n=null;try{n=JSON.parse(e)}catch{}let r=n?.error?.code||n?.error?.type||"";return t===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."}:t===401||t===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 (${t}): ${e.slice(0,300)}`}}var Na=null;async function g1(){if(!Na)return null;let t=await Lc();if(!t||t.apiKey.slice(-6)!==Na.keyTail)return null;let{keyTail:e,...n}=Na;return n}async function y1(t){let e=await fetch("https://api.openai.com/v1/realtime/client_secrets",{method:"POST",headers:{Authorization:`Bearer ${t.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify({session:{type:"realtime",model:t.model,audio:{output:{voice:t.voice}}}})});if(!e.ok){let o=await e.text().catch(()=>""),s=w1(e.status,o);s.persistent&&(Na={code:s.code,message:s.message,at:Date.now(),keyTail:t.apiKey.slice(-6)});let a=new Error(s.message);throw a.status=s.status,a.code=s.code,a}Na=null;let n=await e.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 b1={openai:y1};async function gv(){let t=await Lc();return t?{configured:!0,provider:t.provider,model:t.model,voice:t.voice,problem:await g1()}:{configured:!1}}async function yv(){let t=await Lc();if(!t){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 e=await b1[t.provider](t);return{provider:t.provider,model:t.model,voice:t.voice,...e}}async function bv(t,{model:e,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=h1(e,s),i=await I(t,{type:"cost.recorded",actor:"user",provider:"openai-realtime",payload:{model:e||"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}}var Av=ut.dirname(x1(import.meta.url)),kv=Number(process.env.PORT)||3362,pl=Wp(process.env),Ev=Number(process.env.BOSTRAT_AUTO_TRIGGER_PCT)||80,zo=gS(process.env.BOSTRAT_ALLOW_IPS),bm=yS(process.env.BOSTRAT_VIEW_FRONT_CIDRS,sl),_v=kS(),Iv=process.env.BOSTRAT_ALLOW_LAN_TOKENLESS!=="1",x=ve();x.disable("x-powered-by");x.use((t,e,n)=>{e.setHeader("x-content-type-options","nosniff"),ol(t.headers.host)||(e.setHeader("x-frame-options","DENY"),e.setHeader("referrer-policy","strict-origin-when-cross-origin")),n()});x.use((t,e,n)=>{if(Ia(t)||zo.allowed(zo.clientIp(t))||bm.allows(t))return n();e.status(403).type("text/plain").send("bostrat: access restricted to the allowlist")});x.use(AS);x.use(vS({token:_v,enforce:Iv}));x.use("/api/mocks",ve.json({limit:"1mb"}));x.use("/api/mocks",ve.raw({type:"image/png",limit:"24mb"}));x.use("/api/mocks",ve.raw({type:["video/mp4","video/webm"],limit:"105mb"}));x.use("/api/runbooks",ve.json({limit:"1mb"}));x.use("/api/telemetry",ve.json({limit:"256kb"}));x.use("/api/hook",ve.json({limit:"2mb"}));x.use("/api/dictation",ve.raw({type:["audio/*","video/mp4","application/octet-stream"],limit:"32mb"}));x.use("/api/tracks/:id/upload",ve.raw({type:()=>!0,limit:"25mb"}));x.use(ve.json({limit:"64kb"}));x.get("/api/health",async(t,e)=>{e.json({ok:!0,tmuxSocket:te,hostTmuxAlive:await xn(),autoTriggerPct:Ev})});x.get("/api/sessions",async(t,e)=>{e.json({sessions:await he()})});x.post("/api/sessions",async(t,e)=>{let{displayName:n,cwd:r}=t.body||{};if(typeof n!="string")return e.status(400).json({error:"displayName (string) required"});try{let o=await or(n,r||void 0);e.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;e.status(a).json({error:s})}});x.delete("/api/sessions/:name",async(t,e)=>{let n=decodeURIComponent(t.params.name);if(!bt(n))return e.status(400).json({error:"invalid session name"});if(!await tt(n))return e.status(404).json({error:"session not found"});try{await _e(n),e.json({ok:!0})}catch(r){e.status(500).json({error:`failed to kill: ${r?.message||r}`})}});x.get("/api/context/:name",async(t,e)=>{let n=decodeURIComponent(t.params.name);if(!bt(n))return e.status(400).json({error:"invalid session name"});let r=await tt(n);if(!r)return e.status(404).json({error:"session not found"});let o=await ps(r.cwd,r.sessionId);if(!o)return e.json({available:!1,cwd:r.cwd,sessionId:r.sessionId||null});e.json({available:!0,...o})});x.post("/api/handoff/:name",async(t,e)=>{let n=decodeURIComponent(t.params.name);if(!bt(n))return e.status(400).json({error:"invalid session name"});try{let r=await ng(n);e.json({ok:!0,step:r.step,file:r.file,startedAt:r.startedAt})}catch(r){e.status(409).json({error:r?.message||String(r)})}});x.get("/api/handoff/:name",(t,e)=>{let n=decodeURIComponent(t.params.name),r=Ai(n);if(!r)return e.json({running:!1});e.json({running:!r.finishedAt,step:r.step,error:r.error,file:r.file,startedAt:r.startedAt,finishedAt:r.finishedAt})});var xv=10;x.get("/api/idle-guard",async(t,e)=>{try{e.json(Y0({tracks:await et(),views:await Qd(),queuedOf:n=>Co(n)}))}catch{e.status(500).json({busy:!0,reasons:["error"]})}});x.get("/api/tracks",async(t,e)=>{let n=await et(),r=n.filter(s=>s.archivedAt&&!s.archiving),o=n;if(t.query.archived!=="all"&&r.length>xv){let s=new Set([...r].sort((a,i)=>(i.archivedAt||0)-(a.archivedAt||0)).slice(0,xv).map(a=>a.id));o=n.filter(a=>!a.archivedAt||a.archiving||s.has(a.id))}e.json({tracks:o,archivedTotal:r.length,agents:ua,agentAvailability:await xc(),tickets:await gx()})});x.get("/api/cost",async(t,e)=>{try{let n=await et();t.query.track&&(n=n.filter(o=>o.id===t.query.track));let r=await zx(n);if(r.cursorUsage=Fd(),t.query.format==="text")return e.type("text/plain").send(Jx(r));e.json(r)}catch(n){e.status(500).json({error:n?.message||String(n)})}});x.get("/api/usage/roundup",async(t,e)=>{try{e.json(await Zx(await et(),{window:t.query.window,from:t.query.from,to:t.query.to}))}catch(n){e.status(500).json({error:n?.message||String(n)})}});x.get("/api/usage/spend",async(t,e)=>{try{let n=await rS(await et(),{window:t.query.window,from:t.query.from,to:t.query.to});n.cursorUsage=Fd(),n.subscriptionMonthlyUsd=Number(process.env.BOSTRAT_SUBSCRIPTION_MONTHLY_USD)||null,n.caps=$s(),e.json(n)}catch(n){e.status(500).json({error:n?.message||String(n)})}});x.get("/api/usage/caps",(t,e)=>{e.json($s())});x.post("/api/usage/caps",async(t,e)=>{try{e.json(await Ni(t.body?.caps??{},{source:"local"}))}catch(n){e.status(400).json({error:n?.message||String(n)})}});x.get("/api/usage/limits",async(t,e)=>{try{let n=t.query.fresh==="1"||t.query.fresh==="true";e.json(await fS(await et(),{fresh:n}))}catch(n){e.status(500).json({error:n?.message||String(n)})}});x.post("/api/hook",async(t,e)=>{try{let{mode:n,target:r}=await vm(t.get(Fa),{byToken:Wf,legacy:()=>Ls(t.body?.session_id,t.body?.cwd)});if(n==="refused")return Xo("refused",{reason:"unknown-token",hook:t.body?.hook_event_name}),e.json({ok:!1,error:"unknown hook token"});if(n==="legacy-denied")return Xo("legacy-denied",{reason:"tokenless-denied",hook:t.body?.hook_event_name}),e.status(401).json({ok:!1,error:"tokenless hook ingest is disabled (BOSTRAT_HOOK_LEGACY_DENY)"});n==="token"&&t.body?.session_id&&r.box?.sessionId&&t.body.session_id!==r.box.sessionId&&Xo("mismatch",{track:r.track.id,box:r.box.name}),Xo(n,{track:r?.track?.id,hook:t.body?.hook_event_name,...n==="legacy"?{reason:"tokenless-body-resolved",deny_with:"BOSTRAT_HOOK_LEGACY_DENY=1"}:{}});let o=await Lx(t.body||{},()=>r);e.json({ok:!0,events:o.length})}catch(n){e.json({ok:!1,error:n?.message||String(n)})}});x.post("/api/telemetry",async(t,e)=>{try{if(!nv(zo.clientIp(t)))return e.json({ok:!0,dropped:!0});let n=await ev(t.body||{});e.json({ok:!0,events:n})}catch(n){e.json({ok:!1,error:n?.message||String(n)})}});x.get("/api/repos",async(t,e)=>{try{let n=await Ue(),r=new Set((await Promise.all(n.map(a=>st(a.path)))).filter(Boolean).map(a=>a.toLowerCase())),s=((await rs()).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}));e.json({repos:[...n,...s]})}catch(n){e.status(500).json({error:n?.message||String(n)})}});x.get("/api/github/token",async(t,e)=>{try{e.json(await Ga(String(t.query.repo||"")))}catch(n){e.status(n?.status||502).json({error:n?.message||String(n)})}});x.get("/api/github/status",(t,e)=>{e.json({configured:Ka(),calls:Zy(),latency:ek()})});x.post("/api/github/refresh",(t,e)=>{Mm(),e.json({ok:!0})});x.get("/api/gmail/search",async(t,e)=>{try{let n=await mS(String(t.query.q||""),{max:Number(t.query.max)||10});e.json({messages:n})}catch(n){e.status(n?.status||502).json({error:n?.message||String(n)})}});x.get("/api/gmail/messages/:id",async(t,e)=>{try{e.json({message:await hS(String(t.params.id))})}catch(n){e.status(n?.status||502).json({error:n?.message||String(n)})}});function km(t,e,n){let r=t.workspace;return r?.kind==="multi"?(r.repos??[]).some(o=>e&&o?.base===e||n&&o?.repo===n):!r?.base||!e||r.base===e||n&&r.repo===n}async function ml({repo:t=null,number:e=null,branch:n=null}){let r=t?await st(t):null;if(r&&e!=null){let s=await Wt(r,e),a=s&&await z(s.trackId);if(a)return a}return n?(await et()).find(s=>s.workspace?.branch===n&&km(s,t,r))??null:null}async function Rv({repo:t=null,number:e=null,branch:n=null}){let r=await ml({repo:t,number:e,branch:n}).catch(()=>null);if(r&&!r.archivedAt)return r;if(!n)return null;let o=t?await st(t).catch(()=>null):null;return(await et()).find(a=>!a.archivedAt&&a.workspace?.branch===n&&km(a,t,o))??null}async function Se(t,{number:e,url:n=null,title:r=null,branch:o=null,repo:s=null,track:a=null,extra:i={}}){let c=a||await ml({repo:s,number:e,branch:o}).catch(()=>null);if(!c)return;let l=i.repo??(s?await st(s).catch(()=>null):null);await I({id:c.id,cwd:c.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",payload:{ts:Date.now(),change:t,number:e,url:n,title:r,branch:o??c.workspace?.branch??null,...l?{repo:l}:{},...i}}).catch(()=>{})}async function A1(t){let e=(await et()).filter(n=>!n.archivedAt);for(let n of t??[]){if(!n.prs?.length)continue;let r=await st(n.path);if(r)for(let o of n.prs){if(await Wt(r,o.number))continue;let s=e.find(a=>a.workspace?.branch===o.headRefName&&km(a,n.path,r));s&&await ne({repo:r,number:o.number,trackId:s.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"})}}}x.get("/api/git/prs",async(t,e)=>{try{let n=await ck();await A1(n.repos).catch(()=>{}),e.json(n)}catch(n){e.status(500).json({error:n?.message||String(n)})}});x.post("/api/git/prs/merge",async(t,e)=>{let{repo:n,number:r,method:o,auto:s,update:a,archive:i,notify:c,headRefName:l,title:u,url:d}=t.body||{};try{if(s){let w=o||"merge";if(!Gs.has(w))throw new Error(`invalid merge method: ${w}`);let y=Number(r);if(!Number.isInteger(y)||y<=0)throw new Error("invalid PR number");let k=await st((await tn(n)).path);if(!k)throw new Error("repo has no GitHub remote");let S=await ml({repo:n,number:y,branch:l}).catch(()=>null);if(!S)throw new Error("auto-merge needs a Track to watch this PR \u2014 none owns it");if(a&&await Vs(n,y),await ne({repo:k,number:y,trackId:S.id,url:d,headRef:l,title:u,source:"matched"}).catch(()=>{}),!await Ps(k,y,{merge:{method:w}}))throw new Error("couldn't record the auto-merge arm");return await br(k,y,i===!0),await Ns(k,y,c===!0&&i!==!0),Pe(),await Se("auto-armed",{number:y,url:d,title:u,branch:l,repo:n,track:S,...a?{extra:{updated:!0}}:{}}),e.json({ok:!0,number:y,auto:!0})}let f=await So(n,r,{method:o||"squash"});await Se("merged",{number:f.number,url:d,title:u,branch:l,repo:n});let p=await st(n).catch(()=>null),m=!1;if(p&&(i===!0&&await br(p,f.number,!0).catch(()=>{}),c===!0&&i!==!0&&await Ns(p,f.number,!0).catch(()=>{}),await Ye(p,f.number).catch(()=>{}),m=await Je(p,f.number).catch(()=>!1),await Nn(p,f.number,"merged").catch(()=>{})),i===!0&&!m){let w=await ml({repo:n,number:f.number,branch:l}).catch(()=>null);w&&!w.archivedAt&&await Rr(w.id).catch(()=>{})}e.json(f)}catch(f){let p=f?.message||String(f),m=/invalid|unknown repo|required|needs a Track|no GitHub remote/i.test(p)?400:502;e.status(m).json({error:p})}});x.post("/api/git/prs/disarm-auto",async(t,e)=>{let{repo:n,number:r,headRefName:o,title:s,url:a}=t.body||{};try{let i=Number(r);if(!Number.isInteger(i)||i<=0)throw new Error("invalid PR number");let c=await st((await tn(n)).path).catch(()=>null),l=c?await Bs(c,i).catch(()=>null):null;try{await lf(n,i)}catch(u){if(!l)throw u}Pe(),await Se("auto-canceled",{number:i,url:a,title:s,branch:o,repo:n}),e.json({ok:!0,number:i})}catch(i){let c=i?.message||String(i),l=/invalid|unknown repo|required/i.test(c)?400:502;e.status(l).json({error:c})}});x.post("/api/git/prs/merge-all",async(t,e)=>{let{repo:n,method:r}=t.body||{};try{let o=await st(n).catch(()=>null),s=await fk(n,{method:r||"merge",onMerged:a=>{Se("merged",{number:a.number,url:a.url,title:a.title,branch:a.headRefName,repo:n}),o&&Ye(o,a.number).catch(()=>{}).then(()=>Je(o,a.number)).catch(()=>{}).then(()=>Nn(o,a.number,"merged")).catch(()=>{})}});e.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;e.status(a).json({error:s})}});x.get("/api/git/prs/merge-all",(t,e)=>{e.json({jobs:dk()})});x.post("/api/git/prs/merge-track",async(t,e)=>{let{trackId:n,update:r,archive:o,notify:s,method:a}=t.body||{};try{let i=a||"merge";if(!Gs.has(i))throw new Error(`invalid merge method: ${i}`);if(!n)return e.status(400).json({error:"trackId required"});let c=await z(n);if(!c)return e.status(404).json({error:`Track ${n} isn't on this node`});let l=(await kr()).filter(f=>f.trackId===c.id&&f.state!=="merged"&&f.state!=="closed");if(!l.length)return e.status(409).json({error:"no open PRs on this Track"});for(let f of l)await br(f.repo,f.number,o===!0).catch(()=>{}),await Ns(f.repo,f.number,s===!0&&o!==!0).catch(()=>{});let u=[],d=[];for(let f of l){let p={repo:f.repo,number:f.number,ok:!0,action:"armed"};u.push(p);try{let m=await vr(f.repo);if(!m)throw new Error(`no local checkout for ${f.repo}`);let w=await xo(m,f.number);d.push({r:p,l:f,repoPath:m,pr:w,plan:lk(w,{update:r!==!1})})}catch(m){p.ok=!1,p.action="failed",p.reason=m?.message||String(m)}}for(let{r:f,l:p,repoPath:m,pr:w,plan:y}of uk(d))try{if(y.action==="skip")f.action="skipped",f.reason=y.reason;else if(y.action==="merge")await So(m,p.number,{method:i}),await Se("merged",{number:p.number,url:w.url,title:w.title,branch:w.headRefName,repo:m,track:c}),await Ye(p.repo,p.number).catch(()=>{}),await Je(p.repo,p.number).catch(()=>{}),await Nn(p.repo,p.number,"merged").catch(()=>{}),f.action="merged";else{if(y.action==="update-arm"&&(await Vs(m,p.number).catch(()=>{}),f.action="updated-armed"),!await Ps(p.repo,p.number,{merge:{method:i}}))throw new Error("couldn't record the auto-merge arm");await Se("auto-armed",{number:p.number,url:w.url,title:w.title,branch:w.headRefName,repo:m,track:c,...f.action==="updated-armed"?{extra:{updated:!0}}:{}})}}catch(k){f.ok=!1,f.action="failed",f.reason=k?.message||String(k)}if(Pe(),!u.some(f=>f.ok)){if(o===!0)for(let f of l)await br(f.repo,f.number,!1).catch(()=>{});if(s===!0&&o!==!0)for(let f of l)await Ns(f.repo,f.number,!1).catch(()=>{});return e.status(502).json({error:u.map(f=>`${f.repo}#${f.number}: ${f.reason}`).join("; "),results:u})}e.json({ok:!0,trackId:c.id,results:u})}catch(i){let c=i?.message||String(i),l=/invalid|required/i.test(c)?400:502;e.status(l).json({error:c})}});x.post("/api/git/prs/disarm-track",async(t,e)=>{let{trackId:n}=t.body||{};try{if(!n)return e.status(400).json({error:"trackId required"});let r=await z(n);if(!r)return e.status(404).json({error:`Track ${n} isn't on this node`});let o=(await kr()).filter(a=>a.trackId===r.id&&a.state!=="merged"&&a.state!=="closed"),s=[];for(let a of o){let i=await Bs(a.repo,a.number).catch(()=>null),c=await vr(a.repo).catch(()=>null);c&&await lf(c,a.number).catch(()=>{}),i&&(await Se("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}))}Pe(),e.json({ok:!0,trackId:r.id,canceled:s})}catch(r){let o=r?.message||String(r),s=/invalid|required/i.test(o)?400:502;e.status(s).json({error:o})}});x.post("/api/git/prs/open",async(t,e)=>{let{trackId:n,title:r,body:o,base:s,repos:a}=t.body||{};try{if(!n)return e.status(400).json({error:"trackId required"});let i=await z(n);if(!i)return e.status(404).json({error:`Track ${n} isn't on this node`});if(i.workspace?.kind==="multi"){let u=pe(i.workspace),d,f=Array.isArray(a)?a.filter(Boolean):[];if(f.length)d=f.map(w=>{let y=u.find(k=>k.name===w||k.repo===w||k.base===w||k.dir===w);if(!y)throw new Error(`invalid repo "${w}" \u2014 not tagged on this Track`);return y});else if(d=await go(i),!d.length)return e.status(409).json({error:"no tagged repo has work to ship"});let p=[];for(let w of d)try{let y=await df(w.dir,{title:r,body:o,base:s}),k=w.repo||await st(w.dir).catch(()=>null);k&&y.number&&await ne({repo:k,number:y.number,trackId:i.id,url:y.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await Se("opened",{number:y.number,url:y.url,title:r,track:i,branch:i.workspace?.branch,extra:{repo:k??w.name}}),p.push({repo:w.name,slug:k??null,ok:!0,url:y.url,number:y.number})}catch(y){p.push({repo:w.name,slug:w.repo??null,ok:!1,error:y?.message||String(y)})}let m=p.filter(w=>w.ok);return m.length?e.json({ok:!0,multi:!0,results:p,url:m[0].url,number:m[0].number}):e.status(502).json({error:p.map(w=>`${w.repo}: ${w.error}`).join("; "),results:p})}let c=await df(i.cwd,{title:r,body:o,base:s}),l=await st(i.cwd).catch(()=>null);l&&c.number&&await ne({repo:l,number:c.number,trackId:i.id,url:c.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await Se("opened",{number:c.number,url:c.url,title:r,track:i,branch:i.workspace?.branch,extra:{...l?{repo:l}:{}}}),e.json(c)}catch(i){let c=i?.message||String(i),l=/required|invalid/i.test(c)?400:502;e.status(l).json({error:c})}});x.get("/api/tracks/:id/repos",async(t,e)=>{try{let n=await z(t.params.id);if(!n)return e.status(404).json({error:"track not found"});let r=await go(n),o=new Map(r.map(a=>[a.base,a])),s=pe(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}});e.json({repos:s,branch:n.workspace?.branch??null,kind:n.workspace?.kind??null})}catch(n){e.status(500).json({error:n?.message||String(n)})}});x.post("/api/tracks/:id/repos",async(t,e)=>{let{repo:n}=t.body||{};try{if(!n||typeof n!="string")return e.status(400).json({error:"repo (path or owner/name) required"});let r=await Zf(t.params.id,n);e.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;e.status(s).json({error:o})}});x.delete("/api/tracks/:id/repos/:name",async(t,e)=>{try{let n=await Qf(t.params.id,t.params.name);e.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;e.status(o).json({error:r})}});x.post("/api/git/prs/fix",async(t,e)=>{let{repo:n,number:r}=t.body||{};try{let o=await xo(n,r),s=await st(n).catch(()=>null),a=await Rv({repo:n,number:r,branch:o.headRefName});if(!a)return e.status(404).json({error:`no active Track owns PR #${o.number} (branch "${o.headRefName}")`});let i=pe(a.workspace).find(k=>k.base===n||s&&k.repo===s)??null,c=a.workspace?.kind==="multi",l=await pk(n,o.number);if(!l.length)return e.status(409).json({error:"no failing checks on this PR"});let u=c&&i?ut.join("ci",i.name):"ci",d=ut.join(a.cwd,".bostrat",u),f=ut.join(".bostrat",u,`pr-${o.number}-fail.log`);await Ft.promises.mkdir(d,{recursive:!0}),await Ft.promises.writeFile(ut.join(a.cwd,f),l.map(k=>`\u2550\u2550\u2550\u2550 ${k.name}${k.link?` \xB7 ${k.link}`:""} \u2550\u2550\u2550\u2550
504
+ `),n?.length&&a.write(n),e.pipe(a),a.pipe(e)}),i=()=>{a.destroy(),e.destroy()};return a.on("error",i),e.on("error",i),!0}function YS(t,e){let n=typeof e=="string"?{host:e}:e||{},r=n["x-bostrat-view-base"];return typeof r=="string"&&r?`${n["x-forwarded-proto"]==="https"?"https":"http"}://${t.slug}.${r.replace(/:\d+$/,"")}/`:`http://${t.slug}.${EB(n.host)}/`}function EB(t){if(process.env.BOSTRAT_PUBLIC_HOST)return String(process.env.BOSTRAT_PUBLIC_HOST).replace(/:\d+$/,"");let e=String(t||"").replace(/:\d+$/,"").toLowerCase();if(!e||!e.includes(".")||/^[\d.]+$/.test(e))return"bostrat.globopi";let n=e.split(".");return gl(e)&&mf(n[0])?n.slice(1).join("."):e}Po();Df();$c();Jt();var XS=1e4,ZS=(...t)=>fetch(...t);function QS(t=process.env){return!!(St(t)&&t.BOSTRAT_PLANE_TOKEN)}async function tv({loopId:t,outcome:e,note:n=null,env:r=process.env}={}){if(!QS(r))return{ok:!1,source:"unconfigured"};let o=new AbortController,s=setTimeout(()=>o.abort(),XS);try{let a=await ZS(`${St(r)}/v1/loops/${encodeURIComponent(t)}/report`,{method:"POST",headers:{authorization:`Bearer ${r.BOSTRAT_PLANE_TOKEN||""}`,"content-type":"application/json"},body:JSON.stringify({outcome:e,...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 Tm({env:t=process.env}={}){if(!QS(t))return{loops:[],source:"unconfigured"};let e=new AbortController,n=setTimeout(()=>e.abort(),XS);try{let r=await ZS(`${St(t)}/v1/loops`,{headers:{authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`},signal:e.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)}}at();import{randomUUID as _B}from"node:crypto";var ev=32768,nv=120,rv=1e3,ov=new Set(["claude","codex","cursor"]),IB=new Set(["off","transition","nag"]),RB=[[0,59],[0,23],[1,31],[1,12],[0,6]];function $B(t){let e=String(t??"").trim().split(/\s+/);return e.length!==5?!1:e.every((n,r)=>{let[o,s]=RB[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=t=>String(t??"").trim();function OB(t,e){let n=t&&typeof t=="object"?t:{},r=mn(n.name);if(!r)throw new Error("a loop plan needs a name");if(r.length>nv)throw new Error(`name is too long (${r.length}); cap is ${nv}`);let o=mn(n.schedule);if(!o)throw new Error('a loop plan needs a schedule (5-field UTC crontab, e.g. "0 7 * * *")');if(!$B(o))throw new Error(`invalid cron schedule: "${o}" \u2014 5 UTC fields, e.g. "0 7 * * *"`);let s=mn(n.prompt);if(!s)throw new Error("a loop plan needs a prompt \u2014 it is what the run does");if(s.length>ev)throw new Error(`prompt is too long (${s.length} chars); cap is ${ev}`);let a=mn(n.expectation)||null;if(a&&a.length>rv)throw new Error(`expectation is too long (${a.length}); cap is ${rv}`);let i=mn(n.notify)||"off";if(!IB.has(i))throw new Error(`notify must be one of off | transition | nag, got "${n.notify}"`);let c=n.assignment??null,l=mn(typeof c=="string"?c:c?.provider)||"claude";if(!ov.has(l))throw new Error(`unknown provider "${l}" \u2014 one of ${[...ov].join(", ")}`);let u=typeof c=="object"&&c&&mn(c.model)||null,f=mn(e?.workspace?.repo)||mn(e?.workspace?.base)||null;if(!f)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");return{name:r,schedule:o,prompt:s,expectation:a,notify:i,assignment:u?{provider:l,model:u}:{provider:l},repo:f}}async function sv(t,e){let n=OB(e,t),r=_B();return await I({id:t.id,cwd:t.cwd},{type:"loop.create.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),proposalId:r,...n}}),{proposalId:r,...n}}async function av(t,e,n,{loopId:r=null,nextFireAt:o=null}={}){if(!e)throw new Error("proposalId required");let s=await F({id:t.id,cwd:t.cwd}),a=s.find(c=>c.type==="loop.create.offered"&&c.payload?.proposalId===e);if(!a)throw new Error("unknown proposal");if(s.some(c=>c.type==="loop.create.answered"&&c.payload?.proposalId===e))throw new Error("proposal already answered");if(!n)return await I({id:t.id,cwd:t.cwd},{type:"loop.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:e,action:"dismiss"}}),{proposalId:e,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 I({id:t.id,cwd:t.cwd},{type:"loop.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:e,loopId:String(r),name:i.name,schedule:i.schedule,provider:i.assignment?.provider??"claude",repo:i.repo??null,nextFireAt:Number.isFinite(Number(o))?Number(o):null}}),await I({id:t.id,cwd:t.cwd},{type:"loop.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:e,action:"created",loopId:String(r)}}),{proposalId:e,action:"created",loopId:String(r)}}Sn();at();Fn();$c();var iv=10,cv=200,CB=120,MB=24,NB=/^\d{4}-\d{2}-\d{2}$/;function Am(t=process.env){return(t.CHANGELOG_REPOS||"globocodes/bostrat").split(",").map(e=>e.trim()).filter(Boolean)}var PB=(t=Date.now())=>new Date(t).toISOString().slice(0,10);function lv(t,e=Date.now()){if(!t)return e-24*36e5;let n=/^(\d+)\s*([hd])$/.exec(String(t).trim());if(n)return e-Number(n[1])*(n[2]==="h"?36e5:24*36e5);let r=Date.parse(t);if(!Number.isNaN(r))return r;throw new Error(`unparseable since "${t}" \u2014 use 24h, 7d, or an ISO date`)}var DB=/^\*\*([^*]+?)\*\*\s*[:.]?\s*[—–-]?\s*(.*)$/;function BB(t){if(typeof t!="string"||!t.trim())throw new Error("md (markdown string) required");let e=ia(t);if(e.length)throw new Error(`changelog entry appears to contain a secret VALUE (${e.join(", ")}) \u2014 entries ship off-box; never put a credential in one. Replace it and retry.`);let n=null,r=[];for(let o of t.split(`
505
+ `)){let s=o.trim();if(!s)continue;if(s.startsWith("#")){n==null&&(n=s.replace(/^#+\s*/,"").trim().slice(0,CB)||null);continue}let a=/^[-*]\s+(.*)$/.exec(s);if(!a)continue;let i=a[1].trim(),c=null,l=new RegExp(`^\\[([^\\]]{1,${MB}})\\]\\s+(.*)$`).exec(i);if(l&&(c=l[1].trim(),i=l[2].trim()),!i)continue;let u=DB.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.`);if(i=`**${u[1].trim().replace(/[:.]\s*$/,"")}** \u2014 ${u[2].trim()}`,i.length>cv)throw new Error(`bullet ${r.length+1} is ${i.length} chars \u2014 over the ${cv}-char cap; a changelog bullet is one line`);r.push({text:i,...c?{area:c}:{}})}if(!r.length)throw new Error("no `- ` bullets found \u2014 an entry is a bullet list, optionally under a `# headline`");if(r.length>iv)throw new Error(`${r.length} bullets \u2014 over the ${iv}-bullet cap; group related changes into one line`);return{title:n||null,bullets:r}}async function uv(t,{repos:e=Am()}={}){let n=new Set(e);return(await Ir()).filter(r=>r.state==="merged"&&(r.resolvedAt??0)>=t&&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,mergedAt:r.resolvedAt??null}))}async function dv(t,{md:e,day:n=null}){let r=BB(e),o=n==null||n===""?PB():String(n);if(!NB.test(o)||Number.isNaN(Date.parse(o)))throw new Error(`invalid day "${n}" \u2014 expected YYYY-MM-DD`);let s=await I({id:t.id,cwd:t.cwd},{type:"changelog.published",actor:"agent",source:"orchestrator",boxId:t.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}}ra();Fn();at();ra();Jt();Rr();Fn();Us();xc();import{execFile as jB}from"node:child_process";import{promisify as LB}from"node:util";var _m=LB(jB),fv=3e4,FB=30*6e4,UB=fv,HB=10*6e4,WB=10080*6e4,qB=60*6e4,KB=8,GB=1440*6e4,VB=3,pv="number,url,title,headRefName,headRefOid,state,mergedAt,closedAt",Em=60*6e4,zB=15*6e4,bl=new Map,kl=new Map,JB=/could not resolve|not found|no pull requests?/i,YB=t=>JB.test(String(t?.message||t||""));function XB(t,e){return[t.ciFix?.delegatedAt,t.reconcile?.delegatedAt,t.ciFixAwait?.since,t.reconcileAwait?.since].some(n=>n&&e-n<Em)}var mv={fast:UB,slow:HB,decay:qB};function hv(t,e){return t.armedAt&&e-t.armedAt<FB||XB(t,e)?"fast":e-(t.firstSeen||0)>WB?"decay":"slow"}function ZB(t,e){return mv[hv(t,e)]}function Wa(t,e,n,r){let o=t.lanes?.get(V(e.repo,e.number))||{};return kc({change:n,repo:e.repo,number:Number(e.number),githubAt:r||null,lane:o.lane||null,intervalMs:o.intervalMs||null,source:"watch"})}async function QB(t,e){Ye("watch");try{let{stdout:n}=await _m("gh",["pr","view",String(e),"--repo",t,"--json",pv],{timeout:3e4,maxBuffer:4194304,env:{...process.env,...await _e({slug:t})}});return JSON.parse(n||"null")}catch(n){throw Dn(n)&&Bn(n),n}}async function t1(t){Ye("watch");try{let{stdout:e}=await _m("gh",["pr","list","--repo",t,"--state","all","--limit","100","--json",pv],{timeout:3e4,maxBuffer:8388608,env:{...process.env,...await _e({slug:t})}}),n=new Map;for(let r of JSON.parse(e||"[]"))n.set(Number(r.number),r);return n}catch(e){throw Dn(e)&&Bn(e),e}}async function e1(){let t=new Map;for(let e of await nt().catch(()=>[]))t.set(e.id,e);return t}async function n1(t,e){await I({id:t.id,cwd:t.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"merged",...e}})}async function r1(t,e){let n=await Or(t);return n?Oo(n,e):null}async function o1(t,e,n){let r=await Or(t);if(!r)throw new Error(`no local checkout for ${t}`);return Co(r,e,{method:n})}async function s1(t,e){let n=await Or(t);if(!n)throw new Error(`no local checkout for ${t}`);return na(n,e)}async function a1(t,e){await I({id:t.id,cwd:t.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"auto-canceled",...e}})}async function ns(t,e,n,r,o){if(!await r.disarm(t.repo,t.number).catch(()=>null))return;let a=n.get(t.trackId);a&&await r.emitDisarmed(a,{number:Number(t.number),url:e?.url||t.url,title:e?.title||t.title,branch:e?.headRefName||t.headRef,repo:t.repo,reason:o}).catch(()=>{})}var i1=10*6e4;async function c1(t,e,n){let r=t.autoMerge?.armedAt||0;if(r&&(n.now??Date.now())-r>GB){await ns(t,null,e,n,"auto-merge expired \u2014 checks never settled within 24h");return}let o=await n.detail(t.repo,t.number).catch(()=>null);if(!o)return;if(o.checks.failed>0){let a=o.checks.failing.map(i=>i.name).join(", ");await ns(t,o,e,n,`check${o.checks.failed===1?"":"s"} failed: ${a}`);return}if(o.mergeable==="CONFLICTING"){await ns(t,o,e,n,`conflicts with ${o.baseRefName}`);return}if(!o.checks.total){let a=Math.max(t.autoMerge?.armedAt||0,Date.parse(o.updatedAt||"")||0);if((n.now??Date.now())-a<i1)return;await ns(t,o,e,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(t.repo,t.number).catch(()=>null);if(s?.autoMerge){if(o.mergeStateStatus==="BEHIND"){try{await n.updateBranch(t.repo,t.number)}catch(a){let i=String(a?.message||a).trim();/no new commits|already up.to.date/i.test(i)||await ns(t,o,e,n,i||`couldn't update with ${o.baseRefName}`)}return}try{await n.merge(t.repo,t.number,s.autoMerge.method||"merge")}catch(a){if(/already merged|not open|is closed/i.test(String(a?.message||a)))return;await ns(t,o,e,n,String(a?.message||a).trim()||"merge failed");return}await wv(t,{...o,state:"MERGED"},e,n,{change:"auto-merged",githubAt:o.checks.settledAt||null})}}async function Fa(t,e,n){await I({id:t.id,cwd:t.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:e,...n}})}async function l1(t,e){try{return await _m("git",["-C",t.cwd,"cat-file","-e",`${e}^{commit}`],{timeout:1e4}),!0}catch{return!1}}async function Ua(t,e,n,r=()=>!0){return(await F(t).catch(()=>[])).some(s=>s.type==="pr.state.changed"&&s.payload?.change===e&&s.payload?.number===Number(n)&&r(s))}var Ha=(t,e)=>({number:Number(t.number),url:e?.url||t.url,title:e?.title||t.title,branch:e?.headRefName||t.headRef,repo:t.repo});async function u1(t,e,n,r){let o=r.now??Date.now(),s=e.headRefOid||null,a=n.get(t.trackId)||null;if(s&&(t.ciFix?.headSha&&s!==t.ciFix.headSha&&await oc(t.repo,t.number,{headSha:s}).catch(()=>{}),t.reconcile?.headSha&&s!==t.reconcile.headSha&&await ac(t.repo,t.number,{headSha:s}).catch(()=>{})),s&&s!==t.lastHeadSha){let i=!t.lastHeadSha,c=!!(t.ciFix||t.reconcile||t.ciFixAwait||t.reconcileAwait),l=!!t.baseFoldAt&&o-t.baseFoldAt<zB;await Eb(t.repo,t.number,s).catch(()=>{}),t.baseFoldAt&&await Ab(t.repo,t.number).catch(()=>{}),!i&&!c&&!l&&a&&!await r.localHasCommit(a,s).catch(()=>!1)&&!await Ua(a,"pushed",t.number,f=>f.payload?.sha===s)&&await Fa(a,"pushed",{...Ha(t,e),sha:s}).catch(()=>{})}if(t.ciFixAwait)if(o-(t.ciFixAwait.since||0)>Em)await sc(t.repo,t.number).catch(()=>{});else{let i=await r.detail(t.repo,t.number).catch(()=>null);if(i?.checks){if(i.checks.failed>0)await sc(t.repo,t.number).catch(()=>{});else if(i.checks.total>0&&i.checks.pending===0){let c=Wa(r,t,"ci-fixed",i.checks.settledAt||null),l=t.ciFixAwait.since||0;a&&!await Ua(a,"ci-fixed",t.number,u=>(u.payload?.ts||0)>=l)&&await Fa(a,"ci-fixed",{...Ha(t,e),passed:i.checks.passed,githubAt:c.githubAt,latencyMs:c.latencyMs,lane:c.lane}).catch(()=>{}),await sc(t.repo,t.number).catch(()=>{})}}}if(t.reconcileAwait)if(o-(t.reconcileAwait.since||0)>Em)await ic(t.repo,t.number).catch(()=>{});else{let i=await r.detail(t.repo,t.number).catch(()=>null);if(i){if(i.mergeable==="CONFLICTING")await ic(t.repo,t.number).catch(()=>{});else if(i.mergeable==="MERGEABLE"){Wa(r,t,"reconciled",null);let c=t.reconcileAwait.since||0;a&&!await Ua(a,"reconciled",t.number,l=>(l.payload?.ts||0)>=c)&&await Fa(a,"reconciled",{...Ha(t,e),base:i.baseRefName||null}).catch(()=>{}),await ic(t.repo,t.number).catch(()=>{})}}}}async function d1(t,e,n,r){let o=Wa(r,t,"closed",Date.parse(e?.closedAt||"")||null),s=n.get(t.trackId);s&&!await Ua(s,"closed",t.number)&&await Fa(s,"closed",{...Ha(t,e),githubAt:o.githubAt,latencyMs:o.latencyMs,lane:o.lane}).catch(()=>{}),await r.notifyIfResolved(t.repo,t.number,"closed").catch(()=>{}),await r.mark(t.repo,t.number,"closed").catch(()=>{})}async function f1(t,e,n){Wa(n,t,"lost",null);let r=e.get(t.trackId);r&&!await Ua(r,"lost",t.number)&&await Fa(r,"lost",Ha(t,null)).catch(()=>{}),await n.notifyIfResolved(t.repo,t.number,"lost").catch(()=>{}),await n.mark(t.repo,t.number,"lost").catch(()=>{})}async function wv(t,e,n,r,o={}){let s=Wa(r,t,o.change||"merged",o.githubAt??(Date.parse(e.mergedAt||"")||null)),a=n.get(t.trackId);a&&((await F(a).catch(()=>[])).some(l=>l.type==="pr.state.changed"&&l.payload?.change==="merged"&&l.payload?.number===Number(t.number))||await r.emitMerged(a,{number:Number(t.number),url:e.url||t.url,title:e.title||t.title,branch:e.headRefName||t.headRef,repo:t.repo,githubAt:s.githubAt,latencyMs:s.latencyMs,lane:s.lane}).catch(()=>{})),await r.notifyIfArmed(t.repo,t.number).catch(()=>{}),await r.archiveIfArmed(t.repo,t.number).catch(()=>{}),await r.mark(t.repo,t.number,"merged").catch(()=>{})}async function p1(t={}){let{now:e=Date.now(),auth:n=bf,view:r=QB,list:o=t1,links:s=Ib,trackMap:a=e1,emitMerged:i=n1,mark:c=Ln,archiveIfArmed:l=Xe,notifyIfArmed:u=Ze,notifyIfResolved:f=Fc,batchThreshold:d=VB,detail:p=r1,merge:h=o1,updateBranch:w=s1,lookup:y=Kt,disarm:k=Ks,emitDisarmed:x=a1,localHasCommit:E=l1}=t;if(!(await n().catch(()=>null))?.authenticated||nc()>0)return 0;let C=(await s().catch(()=>[])).filter(A=>e-(bl.get(V(A.repo,A.number))||0)>=ZB(A,e));if(!C.length)return 0;let N=Date.now(),T=new Map,D=new Map;for(let A of C){let B=hv(A,e);T.set(V(A.repo,A.number),{lane:B,intervalMs:mv[B]}),bl.set(V(A.repo,A.number),e),D.has(A.repo)||D.set(A.repo,[]),D.get(A.repo).push(A)}let j=await a().catch(()=>new Map),st={now:e,lanes:T,emitMerged:i,mark:c,archiveIfArmed:l,notifyIfArmed:u,notifyIfResolved:f,detail:p,merge:h,updateBranch:w,lookup:y,disarm:k,emitDisarmed:x,localHasCommit:E};for(let[A,B]of D){let X,yt=new Set;if(B.length>d)X=await o(A).catch(()=>null);else{X=new Map;for(let dt of B)try{let bt=await r(A,dt.number);bt?.number!=null&&X.set(Number(bt.number),bt)}catch(bt){YB(bt)&&yt.add(V(dt.repo,dt.number))}}if(X)for(let dt of B){let bt=V(dt.repo,dt.number),kt=X.get(Number(dt.number));if(!kt){if(yt.has(bt)){let g=(kl.get(bt)||0)+1;kl.set(bt,g),g>=KB&&(await f1(dt,j,st),kl.delete(bt),bl.delete(bt))}continue}kl.delete(bt),kt.state==="MERGED"||kt.state==="CLOSED"?(kt.state==="MERGED"?await wv(dt,kt,j,st):await d1(dt,kt,j,st),bl.delete(bt)):(await u1(dt,kt,j,st).catch(()=>{}),dt.autoMerge&&await c1(dt,j,st).catch(()=>{}))}}let rt={};for(let{lane:A}of T.values())rt[A]=(rt[A]||0)+1;return console.log(`[pr-watch] probed ${C.length} link(s) (${Object.entries(rt).map(([A,B])=>`${A} ${B}`).join(", ")}) in ${Date.now()-N}ms`),C.length}function gv(){let t=!1;setInterval(async()=>{if(!t){t=!0;try{await p1()}catch{}finally{t=!1}}},fv)}qt();at();Rr();import{randomUUID as m1}from"node:crypto";var h1=2e4,yv=3,rs=new Map,Im=new Set;async function bv(t,e,n){let r=await n(t).catch(()=>[]),o=null;for(let s of r)s.type==="box.fullscreen.detected"&&s.boxId===e?o=s.payload?.offerId||null:s.type==="box.fullscreen.answered"&&o&&s.payload?.offerId===o&&(o=null);return o}async function w1(t={}){let{sessions:e=null,tracks:n=null,append:r=I,read:o=F,now:s=Date.now()}=t;if(process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1")return;let a,i;try{a=e??await ge(),i=n??await nt()}catch{return}let c=new Map(a.map(u=>[u.name,u])),l=new Set;for(let u of i){if(u.archivedAt||u.transferredTo||!u.leadBox)continue;let f=(u.boxes||[]).find(p=>p.name===u.leadBox);if(!f||f.agent!=="claude"||f.state!=="live")continue;let d=c.get(f.name);if(d)if(l.add(f.name),d.alternateOn){let p=(rs.get(f.name)||0)+1;rs.set(f.name,p),p===yv&&(Im.add(f.name),await bv(u,f.name,o)||await r(u,{type:"box.fullscreen.detected",actor:"system",source:"orchestrator",boxId:f.name,provider:f.agent,payload:{ts:s,offerId:m1(),box:f.name,agent:f.agent}}).catch(()=>{}))}else{let p=(rs.get(f.name)||0)>=yv;if(rs.delete(f.name),p||!Im.has(f.name)){Im.add(f.name);let h=await bv(u,f.name,o);h&&await r(u,{type:"box.fullscreen.answered",actor:"system",source:"orchestrator",boxId:f.name,provider:f.agent,payload:{ts:s,offerId:h,action:"cleared"}}).catch(()=>{})}}}for(let u of[...rs.keys()])l.has(u)||rs.delete(u)}var qa=null,Rm=!1;function kv(){return qa?()=>{}:(qa=setInterval(()=>{Rm||(Rm=!0,w1().catch(()=>{}).finally(()=>{Rm=!1}))},h1),qa.unref?.(),()=>{clearInterval(qa),qa=null})}Ao();Ef();at();ra();Ao();import{randomUUID as g1}from"node:crypto";async function y1(){let t=await Promise.resolve().then(()=>(Rr(),Sx));return{sayToLead:t.sayToLead,queueShipCompleteNotify:t.queueShipCompleteNotify}}var $m={listRepoPrs:$r,readEvents:F,appendEvent:I,sayDeps:y1};async function b1(t,e=$m){let n=t?.workspace?.branch;if(!n||!t?.cwd)return null;let r;try{r=await e.listRepoPrs(t.cwd,{caller:"pr-exists"})}catch{return null}let o=(r||[]).find(s=>s.headRefName===n);return o?{number:o.number,url:o.url??null,title:o.title??null}:null}async function Om(t,e,{actions:n,notify:r=!1}={},o=$m){let s=e?.payload||{};if(!Array.isArray(n)||!n.includes("pr")||s.toPr||Array.isArray(s.repos)&&s.repos.length||!s.branch)return null;let a=await b1(t,o);if(!a)return null;let i={id:t.id,cwd:t.cwd};await o.appendEvent(i,{type:"pr.offer.answered",actor:"user",source:"orchestrator",boxId:e.boxId,payload:{ts:Date.now(),offerId:s.offerId,action:"pr-exists",actions:n,...r?{notify:!0}:{},existingPr:{number:a.number}}});let c=g1();return await o.appendEvent(i,{type:"pr.exists.offered",actor:"system",source:"orchestrator",boxId:e.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 Cm(t,{offerId:e,choice:n}={},r=$m){if(!e)throw new Error("offerId required");if(!["push","new","dismiss"].includes(n))throw new Error('choice "push" | "new" | "dismiss" required');let o=await r.readEvents(t),s=o.find(u=>u.type==="pr.exists.offered"&&u.payload?.offerId===e);if(!s)throw new Error("unknown offer");if(o.some(u=>u.type==="pr.exists.answered"&&u.payload?.offerId===e))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=Qi.filter(f=>f!=="pr"&&(i.includes(f)||f==="push")),c=await u(t.id,To(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(t.id,ab(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:t.id,cwd:t.cwd},{type:"pr.exists.answered",actor:"user",source:"orchestrator",boxId:s.boxId,payload:{ts:Date.now(),offerId:e,choice:n}}),n!=="dismiss"&&a.notify===!0){let{queueShipCompleteNotify:u}=await r.sayDeps();u(t.id,{actions:l})}return{say:c,choice:n}}import hn from"node:fs/promises";import os from"node:path";import _v from"node:os";import xv from"node:fs/promises";import xl from"node:path";import{execFile as k1}from"node:child_process";import{promisify as x1}from"node:util";import{fileURLToPath as S1}from"node:url";var v1=x1(k1),vv=xl.dirname(S1(import.meta.url)),T1=xl.resolve(vv,"..","..","client","dist"),A1="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",E1=new Map([...A1].map((t,e)=>[t,e]));function _1(t){let e=[],n=0,r=0;for(let o of t){let s=E1.get(o);if(s===void 0)return e;n+=(s&31)<<r,s&32?r+=5:(e.push(n&1?-(n>>>1):n>>>1),n=0,r=0)}return e}function I1(t){let e=[],n=0,r=0,o=0;for(let s of t.split(";")){let a=[],i=0;if(s)for(let c of s.split(",")){let l=_1(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])))}e.push(a)}return e}function R1(t,e){if(!t||t.length===0||t[0][0]>e)return null;let n=0,r=t.length-1;for(;n<r;){let o=n+r+1>>1;t[o][0]<=e?n=o:r=o-1}return t[n]}var Sv=new Map;async function $1(t){let e;try{e=await xv.stat(t)}catch{return null}let n=Sv.get(t);if(n&&n.mtimeMs===e.mtimeMs)return n;try{let r=JSON.parse(await xv.readFile(t,"utf8")),o={mtimeMs:e.mtimeMs,sources:r.sources||[],lines:I1(r.mappings||"")};return Sv.set(t,o),o}catch{return null}}var Mm=null;function O1(){return Mm||(Mm=process.env.BOSTRAT_RELEASE?Promise.resolve(process.env.BOSTRAT_RELEASE):v1("git",["rev-parse","--short","HEAD"],{cwd:xl.resolve(vv,"..","..")}).then(t=>t.stdout.trim()).catch(()=>null)),Mm}var C1=/(?:https?:\/\/[^\s()]*)?\/assets\/([^\s()/]+\.js):(\d+):(\d+)/g;async function M1(t,{distDir:e=T1}={}){let n=[],r=0,o=!1;for(let s of t.matchAll(C1)){let[a,i,c,l]=s,u=await $1(xl.join(e,"assets",`${i}.map`)),f=u?R1(u.lines[Number(c)-1],Number(l)-1):null;if(n.push(t.slice(r,s.index)),f&&u.sources[f[1]]){let d=u.sources[f[1]].replace(/^(\.\.\/)+/,"");n.push(`${d}:${f[2]+1}:${f[3]+1}`),o=!0}else n.push(a);r=s.index+a.length}return n.push(t.slice(r)),{stack:n.join(""),symbolicated:o}}async function Tv(t,e={}){try{if(!t?.error?.stack||!t.release||t.release==="unknown")return t;let n=e.release??await O1();if(!n||t.release!==n)return t;let{stack:r,symbolicated:o}=await M1(t.error.stack,e);o&&(t.error.stack=r,t.error.symbolicated=!0)}catch{}return t}var N1=()=>process.env.BOSTRAT_STATE_DIR||os.join(process.env.HOME||_v.tmpdir(),".bostrat"),or=()=>os.join(N1(),"telemetry"),Iv=()=>os.join(or(),".relay-offsets.json"),P1=50,D1=14,B1=3e4,Av=500,ie=(t,e)=>typeof t=="string"?t.slice(0,e):"";function j1(t,e){if(!t||typeof t!="object")return null;let n=ie(t.name,64);if(!n)return null;let r=Number.isFinite(t.ts)?t.ts:e,o={name:n,ts:Math.abs(r-e)<168*3600*1e3?r:e,receivedAt:e,anonId:ie(t.anonId,64),sessionId:ie(t.sessionId,64),userId:ie(t.userId,64),release:ie(t.release,64),appVersion:ie(t.appVersion,32),route:ie(t.route,128),deviceClass:t.deviceClass==="phone"||t.deviceClass==="desktop"?t.deviceClass:""};return t.props&&typeof t.props=="object"&&!Array.isArray(t.props)&&(JSON.stringify(t.props).length<=8192?o.props=t.props:o.props={clamped:!0}),t.error&&typeof t.error=="object"&&(o.error={kind:ie(t.error.kind,256),message:ie(t.error.message,8192),stack:ie(t.error.stack,32768),fingerprint:ie(t.error.fingerprint,64)}),Array.isArray(t.breadcrumbs)&&(o.breadcrumbs=t.breadcrumbs.slice(-50).map(s=>({t:Number.isFinite(s?.t)?s.t:0,n:ie(s?.n,64),r:ie(s?.r,128)}))),o}var Rv=t=>new Date(t).toISOString().slice(0,10),Ev=0;async function $v(t,e=Date.now()){let r=(Array.isArray(t?.events)?t.events.slice(0,P1):[]).map(s=>j1(s,e)).filter(Boolean);if(!r.length)return 0;for(let s of r)s.error?.stack&&await Tv(s);await hn.mkdir(or(),{recursive:!0});let o=os.join(or(),`${Rv(e)}.ndjson`);return await hn.appendFile(o,r.map(s=>JSON.stringify(s)+`
506
+ `).join(""),"utf8"),e-Ev>6*3600*1e3&&(Ev=e,L1(e).catch(()=>{})),r.length}async function L1(t=Date.now()){let e=Rv(t-D1*24*3600*1e3),n=[];try{n=await hn.readdir(or())}catch{return}let r=n.filter(s=>s.endsWith(".ndjson")&&s.slice(0,10)<e);if(!r.length)return;for(let s of r)await hn.rm(os.join(or(),s),{force:!0});let o=await Cv();for(let s of r)delete o[s];await Mv(o)}var Sl=new Map;function Ov(t,e=Date.now()){let n=t||"unknown",r=Sl.get(n);return r||(Sl.size>512&&Sl.clear(),r={tokens:40,at:e},Sl.set(n,r)),r.tokens=Math.min(40,r.tokens+(e-r.at)/6e4*20),r.at=e,r.tokens<1?!1:(r.tokens-=1,!0)}async function Cv(){try{return JSON.parse(await hn.readFile(Iv(),"utf8"))||{}}catch{return{}}}async function Mv(t){await hn.mkdir(or(),{recursive:!0}),await hn.writeFile(Iv(),JSON.stringify(t),"utf8")}function F1(t,{env:e,host:n}={}){let r=t.name==="app.error"&&t.error,o={};for(let[a,i]of[["event",t.name],["route",t.route],["session",t.sessionId],["anon",t.anonId],["user",t.userId],["release",t.release],["appVersion",t.appVersion],["device",t.deviceClass]])i&&(o[a]=i);let s={timestamp:new Date(t.ts).toISOString(),service:"bostrat-client",source:"treetop-js",env:e||process.env.BOSTRAT_ENV||"pi",host:n||_v.hostname(),level:r?"error":"info",message:r?`${t.error.kind||"Error"}: ${t.error.message||"(no message)"}`.slice(0,8192):t.name,tags:o,attributes:{...t.props?{props:t.props}:{},receivedAt:t.receivedAt}};return r&&(s.error={kind:t.error.kind,message:t.error.message,stack:t.error.stack},t.error.fingerprint&&(s.fingerprint=t.error.fingerprint),t.error.symbolicated&&(s.attributes.symbolicated=!0),t.breadcrumbs&&(s.attributes.breadcrumbs=t.breadcrumbs)),s}async function U1({fetchImpl:t=fetch}={}){let e=await $x();if(!e)return{sent:0,disabled:!0};let n;try{n=(await hn.readdir(or())).filter(s=>s.endsWith(".ndjson")).sort()}catch{return{sent:0,disabled:!1}}let r=await Cv(),o=0;for(let s of n){let a=os.join(or(),s),i=r[s]||0,c;try{let d=await hn.open(a,"r");try{let p=(await d.stat()).size;if(p<=i)continue;c=Buffer.alloc(p-i),await d.read(c,0,c.length,i)}finally{await d.close()}}catch{continue}let l=c.lastIndexOf(10);if(l<0)continue;let u=c.toString("utf8",0,l+1).split(`
507
+ `).filter(Boolean),f=[];for(let d of u)try{f.push(JSON.parse(d))}catch{}for(let d=0;d<f.length;d+=Av){let p=f.slice(d,d+Av).map(w=>F1(w)),h=await t(`${e.url.replace(/\/$/,"")}/v1/logs`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${e.ingestKey}`},body:JSON.stringify({events:p})}).catch(()=>null);if(!h||!h.ok)return{sent:o,disabled:!1};o+=p.length}r[s]=i+l+1,await Mv(r)}return{sent:o,disabled:!1}}var Nm=null,Pm=!1;function Nv(){Nm||(Nm=setInterval(async()=>{if(!Pm){Pm=!0;try{await U1()}catch(t){console.error("[telemetry] relay failed:",t?.message||t)}finally{Pm=!1}}},B1),Nm.unref?.())}import Tl from"node:fs/promises";import Lv from"node:path";import H1 from"node:os";var Fv=()=>process.env.BOSTRAT_STATE_DIR||Lv.join(process.env.HOME||H1.tmpdir(),".bostrat"),Uv=()=>Lv.join(Fv(),"dictation-glossary.json"),W1=100,q1=500,K1=["bostrat","globopi","codex","tmux","worktree","Deepgram","Linear","Firecracker","Tigris","WireGuard","misous","postyx","cedar","gerbil","Anthropic","Opus","Haiku","Sonnet","keyterm","monorepo","dogfood"],Al=null,Dm=null,Bm=Promise.resolve();function Pv(){let t={},e=Date.now();for(let n of K1)t[n.toLowerCase()]={term:n,count:1,lastUsed:e,source:"seed"};return t}async function Hv(){return Al||(Dm??=Tl.readFile(Uv(),"utf8").then(t=>JSON.parse(t)?.terms??Pv()).catch(()=>Pv()).then(t=>Al=t).finally(()=>Dm=null),Dm)}async function Dv(){let t=JSON.stringify({terms:Al},null,2),e=Uv(),n=`${e}.${process.pid}.tmp`;await Tl.mkdir(Fv(),{recursive:!0}),await Tl.writeFile(n,t),await Tl.rename(n,e)}function G1(){return Bm=Bm.then(Dv,Dv),Bm.catch(()=>{})}async function jm(){return Object.values(await Hv()).sort((e,n)=>n.count-e.count||n.lastUsed-e.lastUsed)}var V1=t=>Math.max(1,Math.ceil(t.length/4));async function z1(){let t=[],e=0;for(let{term:n}of await jm()){let r=V1(n);if(!(e+r>q1)&&(t.push(n),e+=r,t.length>=W1))break}return t}async function J1(t,e){let n=await Hv(),r=t.toLowerCase(),o=n[r];n[r]={term:t,count:(o?.count??0)+1,lastUsed:Date.now(),source:o?.source??e}}var Bv=t=>(t||"").split(/\s+/).map(e=>e.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"")).filter(Boolean),vl=t=>t.toLowerCase();function jv(t){return!new RegExp("\\p{L}","u").test(t)||t.length<3?!1:/^[a-z]+$/.test(t)?t.length>=4:!0}async function Wv(t,e){let n=Bv(t),r=Bv(e);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 f=s-1;f>=0;f--)a[u][f]=vl(n[u])===vl(r[f])?a[u+1][f+1]+1:Math.max(a[u+1][f],a[u][f+1]);let i=new Set,c=0,l=0;for(;c<o&&l<s;)vl(n[c])===vl(r[l])?(c++,l++):a[c+1][l]>=a[c][l+1]?c++:(jv(r[l])&&i.add(r[l]),l++);for(;l<s;l++)jv(r[l])&&i.add(r[l]);if(!i.size)return[];for(let u of i)await J1(u,"learned");return await G1(),[...i]}var Ka=null;function Y1(t,e){let n=null;try{n=JSON.parse(e)}catch{}let r=n?.err_code||n?.error_code||n?.category||"";return t===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."}:t===401||t===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 ${t}: ${e.slice(0,300)}`}}async function qv(){if(!Ka)return null;let t=await _a();if(!t||t.apiKey.slice(-6)!==Ka.keyTail)return null;let{keyTail:e,...n}=Ka;return n}async function Kv(t,e){let n=await _a();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 z1())r.searchParams.append("keyterm",i);let o=await fetch(r,{method:"POST",headers:{Authorization:`Token ${n.apiKey}`,"Content-Type":e||"application/octet-stream"},body:t});if(!o.ok){let i=await o.text().catch(()=>""),c=Y1(o.status,i);c.persistent&&(Ka={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 Ka=null,{transcript:(await o.json())?.results?.channels?.[0]?.alternatives?.[0]?.transcript??""}}at();var Lm={"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 X1(t){if(!t)return null;let e=String(t).trim();if(Lm[e])return e;let n=null;for(let r of Object.keys(Lm))e.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function Z1(t,e={}){let n=Lm[X1(t)];if(!n)return 0;let r=0;for(let o of Object.keys(n))r+=(Number(e[o])||0)*n[o];return r/1e6}function Q1(t,e){let n=null;try{n=JSON.parse(e)}catch{}let r=n?.error?.code||n?.error?.type||"";return t===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."}:t===401||t===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 (${t}): ${e.slice(0,300)}`}}var Ga=null;async function tj(){if(!Ga)return null;let t=await Qc();if(!t||t.apiKey.slice(-6)!==Ga.keyTail)return null;let{keyTail:e,...n}=Ga;return n}async function ej(t){let e=await fetch("https://api.openai.com/v1/realtime/client_secrets",{method:"POST",headers:{Authorization:`Bearer ${t.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify({session:{type:"realtime",model:t.model,audio:{output:{voice:t.voice}}}})});if(!e.ok){let o=await e.text().catch(()=>""),s=Q1(e.status,o);s.persistent&&(Ga={code:s.code,message:s.message,at:Date.now(),keyTail:t.apiKey.slice(-6)});let a=new Error(s.message);throw a.status=s.status,a.code=s.code,a}Ga=null;let n=await e.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 nj={openai:ej};async function Gv(){let t=await Qc();return t?{configured:!0,provider:t.provider,model:t.model,voice:t.voice,problem:await tj()}:{configured:!1}}async function Vv(){let t=await Qc();if(!t){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 e=await nj[t.provider](t);return{provider:t.provider,model:t.model,voice:t.voice,...e}}async function zv(t,{model:e,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=Z1(e,s),i=await I(t,{type:"cost.recorded",actor:"user",provider:"openai-realtime",payload:{model:e||"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}}var tT=ut.dirname(oj(import.meta.url)),Jv=Number(process.env.PORT)||3362,El=mm(process.env),eT=Number(process.env.BOSTRAT_AUTO_TRIGGER_PCT)||80,ss=FS(process.env.BOSTRAT_ALLOW_IPS),qm=US(process.env.BOSTRAT_VIEW_FRONT_CIDRS,yl),nT=WS(),rT=process.env.BOSTRAT_ALLOW_LAN_TOKENLESS!=="1",S=he();S.disable("x-powered-by");S.use((t,e,n)=>{e.setHeader("x-content-type-options","nosniff"),gl(t.headers.host)||(e.setHeader("x-frame-options","DENY"),e.setHeader("referrer-policy","strict-origin-when-cross-origin")),n()});S.use((t,e,n)=>{if(La(t)||ss.allowed(ss.clientIp(t))||qm.allows(t))return n();e.status(403).type("text/plain").send("bostrat: access restricted to the allowlist")});S.use(zS);S.use(GS({token:nT,enforce:rT}));S.use("/api/mocks",he.json({limit:"1mb"}));S.use("/api/mocks",he.raw({type:"image/png",limit:"24mb"}));S.use("/api/mocks",he.raw({type:["video/mp4","video/webm"],limit:"105mb"}));S.use("/api/runbooks",he.json({limit:"1mb"}));S.use("/api/tracks/adopt",he.json({limit:"1mb"}));S.use("/api/telemetry",he.json({limit:"256kb"}));S.use("/api/hook",he.json({limit:"2mb"}));S.use("/api/dictation",he.raw({type:["audio/*","video/mp4","application/octet-stream"],limit:"32mb"}));S.use("/api/tracks/:id/upload",he.raw({type:()=>!0,limit:"25mb"}));S.use(he.json({limit:"64kb"}));S.get("/api/health",async(t,e)=>{e.json({ok:!0,tmuxSocket:ne,hostTmuxAlive:await Tn(),autoTriggerPct:eT})});S.get("/api/sessions",async(t,e)=>{e.json({sessions:await ge()})});S.post("/api/sessions",async(t,e)=>{let{displayName:n,cwd:r}=t.body||{};if(typeof n!="string")return e.status(400).json({error:"displayName (string) required"});try{let o=await An(n,r||void 0);e.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;e.status(a).json({error:s})}});S.delete("/api/sessions/:name",async(t,e)=>{let n=decodeURIComponent(t.params.name);if(!At(n))return e.status(400).json({error:"invalid session name"});if(!await et(n))return e.status(404).json({error:"session not found"});try{await Re(n),e.json({ok:!0})}catch(r){e.status(500).json({error:`failed to kill: ${r?.message||r}`})}});S.get("/api/context/:name",async(t,e)=>{let n=decodeURIComponent(t.params.name);if(!At(n))return e.status(400).json({error:"invalid session name"});let r=await et(n);if(!r)return e.status(404).json({error:"session not found"});let o=await Ss(r.cwd,r.sessionId);if(!o)return e.json({available:!1,cwd:r.cwd,sessionId:r.sessionId||null});e.json({available:!0,...o})});S.post("/api/handoff/:name",async(t,e)=>{let n=decodeURIComponent(t.params.name);if(!At(n))return e.status(400).json({error:"invalid session name"});try{let r=await Eg(n);e.json({ok:!0,step:r.step,file:r.file,startedAt:r.startedAt})}catch(r){e.status(409).json({error:r?.message||String(r)})}});S.get("/api/handoff/:name",(t,e)=>{let n=decodeURIComponent(t.params.name),r=ji(n);if(!r)return e.json({running:!1});e.json({running:!r.finishedAt,step:r.step,error:r.error,file:r.file,startedAt:r.startedAt,finishedAt:r.finishedAt})});var Yv=10;S.get("/api/idle-guard",async(t,e)=>{try{e.json(vx({tracks:await nt(),views:await pf(),queuedOf:n=>Ho(n)}))}catch{e.status(500).json({busy:!0,reasons:["error"]})}});S.get("/api/tracks",async(t,e)=>{let n=(await nt()).filter(s=>!s.transferredTo),r=n.filter(s=>s.archivedAt&&!s.archiving),o=n;if(t.query.archived!=="all"&&r.length>Yv){let s=new Set([...r].sort((a,i)=>(i.archivedAt||0)-(a.archivedAt||0)).slice(0,Yv).map(a=>a.id));o=n.filter(a=>!a.archivedAt||a.archiving||s.has(a.id))}e.json({tracks:o,archivedTotal:r.length,agents:ka,agentAvailability:await Pc(),tickets:await qx()})});S.get("/api/cost",async(t,e)=>{try{let n=await nt();t.query.track&&(n=n.filter(o=>o.id===t.query.track));let r=await xS(n);if(r.cursorUsage=Qd(),t.query.format==="text")return e.type("text/plain").send(SS(r));e.json(r)}catch(n){e.status(500).json({error:n?.message||String(n)})}});S.get("/api/usage/roundup",async(t,e)=>{try{e.json(await AS(await nt(),{window:t.query.window,from:t.query.from,to:t.query.to}))}catch(n){e.status(500).json({error:n?.message||String(n)})}});S.get("/api/usage/spend",async(t,e)=>{try{let n=await $S(await nt(),{window:t.query.window,from:t.query.from,to:t.query.to});n.cursorUsage=Qd(),n.subscriptionMonthlyUsd=Number(process.env.BOSTRAT_SUBSCRIPTION_MONTHLY_USD)||null,n.caps=Ls(),e.json(n)}catch(n){e.status(500).json({error:n?.message||String(n)})}});S.get("/api/usage/caps",(t,e)=>{e.json(Ls())});S.post("/api/usage/caps",async(t,e)=>{try{e.json(await zi(t.body?.caps??{},{source:"local"}))}catch(n){e.status(400).json({error:n?.message||String(n)})}});S.get("/api/usage/limits",async(t,e)=>{try{let n=t.query.fresh==="1"||t.query.fresh==="true";e.json(await PS(await nt(),{fresh:n}))}catch(n){e.status(500).json({error:n?.message||String(n)})}});S.post("/api/hook",async(t,e)=>{try{let{mode:n,target:r}=await zm(t.get(Xa),{byToken:cp,legacy:()=>zs(t.body?.session_id,t.body?.cwd)});if(n==="refused")return is("refused",{reason:"unknown-token",hook:t.body?.hook_event_name}),e.json({ok:!1,error:"unknown hook token"});if(n==="legacy-denied")return is("legacy-denied",{reason:"tokenless-denied",hook:t.body?.hook_event_name}),e.status(401).json({ok:!1,error:"tokenless hook ingest is disabled (BOSTRAT_HOOK_LEGACY_DENY)"});n==="token"&&t.body?.session_id&&r.box?.sessionId&&t.body.session_id!==r.box.sessionId&&is("mismatch",{track:r.track.id,box:r.box.name}),is(n,{track:r?.track?.id,hook:t.body?.hook_event_name,...n==="legacy"?{reason:"tokenless-body-resolved",deny_with:"BOSTRAT_HOOK_LEGACY_DENY=1"}:{}});let o=await fS(t.body||{},()=>r);e.json({ok:!0,events:o.length})}catch(n){e.json({ok:!1,error:n?.message||String(n)})}});S.post("/api/telemetry",async(t,e)=>{try{if(!Ov(ss.clientIp(t)))return e.json({ok:!0,dropped:!0});let n=await $v(t.body||{});e.json({ok:!0,events:n})}catch(n){e.json({ok:!1,error:n?.message||String(n)})}});S.get("/api/repos",async(t,e)=>{try{let n=await We(),r=new Set((await Promise.all(n.map(a=>lt(a.path)))).filter(Boolean).map(a=>a.toLowerCase())),s=((await fs()).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}));e.json({repos:[...n,...s]})}catch(n){e.status(500).json({error:n?.message||String(n)})}});S.get("/api/github/token",async(t,e)=>{try{e.json(await ri(String(t.query.repo||"")))}catch(n){e.status(n?.status||502).json({error:n?.message||String(n)})}});S.get("/api/github/status",(t,e)=>{e.json({configured:ni(),calls:yb(),latency:xk()})});S.post("/api/github/refresh",(t,e)=>{oh(),e.json({ok:!0})});S.get("/api/gmail/search",async(t,e)=>{try{let n=await BS(String(t.query.q||""),{max:Number(t.query.max)||10});e.json({messages:n})}catch(n){e.status(n?.status||502).json({error:n?.message||String(n)})}});S.get("/api/gmail/messages/:id",async(t,e)=>{try{e.json({message:await jS(String(t.params.id))})}catch(n){e.status(n?.status||502).json({error:n?.message||String(n)})}});function Km(t,e,n){let r=t.workspace;return r?.kind==="multi"?(r.repos??[]).some(o=>e&&o?.base===e||n&&o?.repo===n):!r?.base||!e||r.base===e||n&&r.repo===n}async function _l({repo:t=null,number:e=null,branch:n=null}){let r=t?await lt(t):null;if(r&&e!=null){let s=await Kt(r,e),a=s&&await Y(s.trackId);if(a)return a}return n?(await nt()).find(s=>s.workspace?.branch===n&&Km(s,t,r))??null:null}async function oT({repo:t=null,number:e=null,branch:n=null}){let r=await _l({repo:t,number:e,branch:n}).catch(()=>null);if(r&&!r.archivedAt&&!r.transferredTo)return r;if(!n)return null;let o=t?await lt(t).catch(()=>null):null;return(await nt()).find(a=>!a.archivedAt&&!a.transferredTo&&a.workspace?.branch===n&&Km(a,t,o))??null}async function Ae(t,{number:e,url:n=null,title:r=null,branch:o=null,repo:s=null,track:a=null,extra:i={}}){let c=a||await _l({repo:s,number:e,branch:o}).catch(()=>null);if(!c)return;let l=i.repo??(s?await lt(s).catch(()=>null):null);await I({id:c.id,cwd:c.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",payload:{ts:Date.now(),change:t,number:e,url:n,title:r,branch:o??c.workspace?.branch??null,...l?{repo:l}:{},...i}}).catch(()=>{})}async function cj(t){let e=(await nt()).filter(n=>!n.archivedAt&&!n.transferredTo);for(let n of t??[]){if(!n.prs?.length)continue;let r=await lt(n.path);if(r)for(let o of n.prs){if(await Kt(r,o.number))continue;let s=e.find(a=>a.workspace?.branch===o.headRefName&&Km(a,n.path,r));s&&await oe({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(t,e)=>{try{let n=await Ik();await cj(n.repos).catch(()=>{}),e.json(n)}catch(n){e.status(500).json({error:n?.message||String(n)})}});S.post("/api/git/prs/merge",async(t,e)=>{let{repo:n,number:r,method:o,auto:s,update:a,archive:i,notify:c,headRefName:l,title:u,url:f}=t.body||{};try{if(s){let w=o||"merge";if(!ea.has(w))throw new Error(`invalid merge method: ${w}`);let y=Number(r);if(!Number.isInteger(y)||y<=0)throw new Error("invalid PR number");let k=await lt((await nn(n)).path);if(!k)throw new Error("repo has no GitHub remote");let x=await _l({repo:n,number:y,branch:l}).catch(()=>null);if(!x)throw new Error("auto-merge needs a Track to watch this PR \u2014 none owns it");if(a&&await na(n,y),await oe({repo:k,number:y,trackId:x.id,url:f,headRef:l,title:u,source:"matched"}).catch(()=>{}),!await Ws(k,y,{merge:{method:w}}))throw new Error("couldn't record the auto-merge arm");return await _r(k,y,i===!0),await qs(k,y,c===!0&&i!==!0),Pe(),await Ae("auto-armed",{number:y,url:f,title:u,branch:l,repo:n,track:x,...a?{extra:{updated:!0}}:{}}),e.json({ok:!0,number:y,auto:!0})}let d=await Co(n,r,{method:o||"squash"});await Ae("merged",{number:d.number,url:f,title:u,branch:l,repo:n});let p=await lt(n).catch(()=>null),h=!1;if(p&&(i===!0&&await _r(p,d.number,!0).catch(()=>{}),c===!0&&i!==!0&&await qs(p,d.number,!0).catch(()=>{}),await Ze(p,d.number).catch(()=>{}),h=await Xe(p,d.number).catch(()=>!1),await Ln(p,d.number,"merged").catch(()=>{})),i===!0&&!h){let w=await _l({repo:n,number:d.number,branch:l}).catch(()=>null);w&&!w.archivedAt&&await Br(w.id).catch(()=>{})}e.json(d)}catch(d){let p=d?.message||String(d),h=/invalid|unknown repo|required|needs a Track|no GitHub remote/i.test(p)?400:502;e.status(h).json({error:p})}});S.post("/api/git/prs/disarm-auto",async(t,e)=>{let{repo:n,number:r,headRefName:o,title:s,url:a}=t.body||{};try{let i=Number(r);if(!Number.isInteger(i)||i<=0)throw new Error("invalid PR number");let c=await lt((await nn(n)).path).catch(()=>null),l=c?await Ks(c,i).catch(()=>null):null;try{await Sf(n,i)}catch(u){if(!l)throw u}Pe(),await Ae("auto-canceled",{number:i,url:a,title:s,branch:o,repo:n}),e.json({ok:!0,number:i})}catch(i){let c=i?.message||String(i),l=/invalid|unknown repo|required/i.test(c)?400:502;e.status(l).json({error:c})}});S.post("/api/git/prs/merge-all",async(t,e)=>{let{repo:n,method:r}=t.body||{};try{let o=await lt(n).catch(()=>null),s=await Ck(n,{method:r||"merge",onMerged:a=>{Ae("merged",{number:a.number,url:a.url,title:a.title,branch:a.headRefName,repo:n}),o&&Ze(o,a.number).catch(()=>{}).then(()=>Xe(o,a.number)).catch(()=>{}).then(()=>Ln(o,a.number,"merged")).catch(()=>{})}});e.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;e.status(a).json({error:s})}});S.get("/api/git/prs/merge-all",(t,e)=>{e.json({jobs:Ok()})});S.post("/api/git/prs/merge-track",async(t,e)=>{let{trackId:n,update:r,archive:o,notify:s,method:a}=t.body||{};try{let i=a||"merge";if(!ea.has(i))throw new Error(`invalid merge method: ${i}`);if(!n)return e.status(400).json({error:"trackId required"});let c=await Y(n);if(!c)return e.status(404).json({error:`Track ${n} isn't on this node`});let l=(await Ir()).filter(d=>d.trackId===c.id&&d.state!=="merged"&&d.state!=="closed");if(!l.length)return e.status(409).json({error:"no open PRs on this Track"});for(let d of l)await _r(d.repo,d.number,o===!0).catch(()=>{}),await qs(d.repo,d.number,s===!0&&o!==!0).catch(()=>{});let u=[],f=[];for(let d of l){let p={repo:d.repo,number:d.number,ok:!0,action:"armed"};u.push(p);try{let h=await Or(d.repo);if(!h)throw new Error(`no local checkout for ${d.repo}`);let w=await Oo(h,d.number);f.push({r:p,l:d,repoPath:h,pr:w,plan:Rk(w,{update:r!==!1})})}catch(h){p.ok=!1,p.action="failed",p.reason=h?.message||String(h)}}for(let{r:d,l:p,repoPath:h,pr:w,plan:y}of $k(f))try{if(y.action==="skip")d.action="skipped",d.reason=y.reason;else if(y.action==="merge")await Co(h,p.number,{method:i}),await Ae("merged",{number:p.number,url:w.url,title:w.title,branch:w.headRefName,repo:h,track:c}),await Ze(p.repo,p.number).catch(()=>{}),await Xe(p.repo,p.number).catch(()=>{}),await Ln(p.repo,p.number,"merged").catch(()=>{}),d.action="merged";else{if(y.action==="update-arm"&&(await na(h,p.number).catch(()=>{}),d.action="updated-armed"),!await Ws(p.repo,p.number,{merge:{method:i}}))throw new Error("couldn't record the auto-merge arm");await Ae("auto-armed",{number:p.number,url:w.url,title:w.title,branch:w.headRefName,repo:h,track:c,...d.action==="updated-armed"?{extra:{updated:!0}}:{}})}}catch(k){d.ok=!1,d.action="failed",d.reason=k?.message||String(k)}if(Pe(),!u.some(d=>d.ok)){if(o===!0)for(let d of l)await _r(d.repo,d.number,!1).catch(()=>{});if(s===!0&&o!==!0)for(let d of l)await qs(d.repo,d.number,!1).catch(()=>{});return e.status(502).json({error:u.map(d=>`${d.repo}#${d.number}: ${d.reason}`).join("; "),results:u})}e.json({ok:!0,trackId:c.id,results:u})}catch(i){let c=i?.message||String(i),l=/invalid|required/i.test(c)?400:502;e.status(l).json({error:c})}});S.post("/api/git/prs/disarm-track",async(t,e)=>{let{trackId:n}=t.body||{};try{if(!n)return e.status(400).json({error:"trackId required"});let r=await Y(n);if(!r)return e.status(404).json({error:`Track ${n} isn't on this node`});let o=(await Ir()).filter(a=>a.trackId===r.id&&a.state!=="merged"&&a.state!=="closed"),s=[];for(let a of o){let i=await Ks(a.repo,a.number).catch(()=>null),c=await Or(a.repo).catch(()=>null);c&&await Sf(c,a.number).catch(()=>{}),i&&(await Ae("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}))}Pe(),e.json({ok:!0,trackId:r.id,canceled:s})}catch(r){let o=r?.message||String(r),s=/invalid|required/i.test(o)?400:502;e.status(s).json({error:o})}});S.post("/api/git/prs/open",async(t,e)=>{let{trackId:n,title:r,body:o,base:s,repos:a}=t.body||{};try{if(!n)return e.status(400).json({error:"trackId required"});let i=await Y(n);if(!i)return e.status(404).json({error:`Track ${n} isn't on this node`});if(i.workspace?.kind==="multi"){let u=ae(i.workspace),f,d=Array.isArray(a)?a.filter(Boolean):[];if(d.length)f=d.map(w=>{let y=u.find(k=>k.name===w||k.repo===w||k.base===w||k.dir===w);if(!y)throw new Error(`invalid repo "${w}" \u2014 not tagged on this Track`);return y});else if(f=await _o(i),!f.length)return e.status(409).json({error:"no tagged repo has work to ship"});let p=[];for(let w of f)try{let y=await Tf(w.dir,{title:r,body:o,base:s}),k=w.repo||await lt(w.dir).catch(()=>null);k&&y.number&&await oe({repo:k,number:y.number,trackId:i.id,url:y.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await Ae("opened",{number:y.number,url:y.url,title:r,track:i,branch:i.workspace?.branch,extra:{repo:k??w.name}}),p.push({repo:w.name,slug:k??null,ok:!0,url:y.url,number:y.number})}catch(y){p.push({repo:w.name,slug:w.repo??null,ok:!1,error:y?.message||String(y)})}let h=p.filter(w=>w.ok);return h.length?e.json({ok:!0,multi:!0,results:p,url:h[0].url,number:h[0].number}):e.status(502).json({error:p.map(w=>`${w.repo}: ${w.error}`).join("; "),results:p})}let c=await Tf(i.cwd,{title:r,body:o,base:s}),l=await lt(i.cwd).catch(()=>null);l&&c.number&&await oe({repo:l,number:c.number,trackId:i.id,url:c.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await Ae("opened",{number:c.number,url:c.url,title:r,track:i,branch:i.workspace?.branch,extra:{...l?{repo:l}:{}}}),e.json(c)}catch(i){let c=i?.message||String(i),l=/required|invalid/i.test(c)?400:502;e.status(l).json({error:c})}});S.get("/api/tracks/:id/repos",async(t,e)=>{try{let n=await Y(t.params.id);if(!n)return e.status(404).json({error:"track not found"});let r=await _o(n),o=new Map(r.map(a=>[a.base,a])),s=ae(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}});e.json({repos:s,branch:n.workspace?.branch??null,kind:n.workspace?.kind??null})}catch(n){e.status(500).json({error:n?.message||String(n)})}});S.post("/api/tracks/:id/repos",async(t,e)=>{let{repo:n}=t.body||{};try{if(!n||typeof n!="string")return e.status(400).json({error:"repo (path or owner/name) required"});let r=await yp(t.params.id,n);e.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;e.status(s).json({error:o})}});S.delete("/api/tracks/:id/repos/:name",async(t,e)=>{try{let n=await bp(t.params.id,t.params.name);e.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;e.status(o).json({error:r})}});S.post("/api/git/prs/fix",async(t,e)=>{let{repo:n,number:r}=t.body||{};try{let o=await Oo(n,r),s=await lt(n).catch(()=>null),a=await oT({repo:n,number:r,branch:o.headRefName});if(!a)return e.status(404).json({error:`no active Track owns PR #${o.number} (branch "${o.headRefName}")`});let i=ae(a.workspace).find(k=>k.base===n||s&&k.repo===s)??null,c=a.workspace?.kind==="multi",l=await Mk(n,o.number);if(!l.length)return e.status(409).json({error:"no failing checks on this PR"});let u=c&&i?ut.join("ci",i.name):"ci",f=ut.join(a.cwd,".bostrat",u),d=ut.join(".bostrat",u,`pr-${o.number}-fail.log`);await Ut.promises.mkdir(f,{recursive:!0}),await Ut.promises.writeFile(ut.join(a.cwd,d),l.map(k=>`\u2550\u2550\u2550\u2550 ${k.name}${k.link?` \xB7 ${k.link}`:""} \u2550\u2550\u2550\u2550
481
508
  ${k.log??"(no fetchable log \u2014 see link)"}
482
509
  `).join(`
483
- `));let p=l.map(k=>k.name).join(", "),m=c&&i?` in the ${i.name}/ checkout`:"",w=await fe(a.id,`CI is red on PR #${o.number} "${o.title}" (${o.url}) \u2014 branch ${o.headRefName}${m}. Failing check${l.length===1?"":"s"}: ${p}. The failure log is at ${f} 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"}),y=s;y&&(await ne({repo:y,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await nb(y,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await Se("fix-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{checks:l.map(k=>k.name)}}),e.json({ok:!0,leadBox:w.leadBox,queued:!!w.queued,checks:l.map(k=>k.name),log:f})}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;e.status(a).json({error:s})}});x.post("/api/git/prs/reconcile",async(t,e)=>{let{repo:n,number:r}=t.body||{};try{let o=await xo(n,r);if(o.mergeable!=="CONFLICTING")return e.status(409).json({error:"this PR does not conflict with its base branch"});let s=await st(n).catch(()=>null),a=await Rv({repo:n,number:r,branch:o.headRefName});if(!a)return e.status(404).json({error:`no active Track owns PR #${o.number} (branch "${o.headRefName}")`});let i=pe(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 fe(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 ne({repo:u,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await rb(u,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await Se("reconcile-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{base:o.baseRefName}}),e.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;e.status(a).json({error:s})}});x.post("/api/tracks/:id/pr-offer",async(t,e)=>{let{offerId:n,action:r}=t.body||{};try{let o=null;if(Array.isArray(t.body?.actions)){if(o=Fi.filter(d=>t.body.actions.includes(d)),!o.length)return e.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 e.status(400).json({error:'offerId and actions ["commit"|"rebase"|"push"|"pr"] (or action "dismiss") required'});if(!n)return e.status(400).json({error:"offerId required"});let s=o!=null&&t.body?.notify===!0,a=await z(t.params.id);if(!a)return e.status(404).json({error:"track not found"});let i=await L(a),c=i.find(d=>d.type==="pr.offered"&&d.payload?.offerId===n);if(!c)return e.status(404).json({error:"unknown offer"});if(i.some(d=>d.type==="pr.offer.answered"&&d.payload?.offerId===n))return e.status(409).json({error:"offer already answered"});if(o?.includes("pr")){let d=await am(a,c,{actions:o,notify:s});if(d)return e.json({ok:!0,offerId:n,action:"pr-exists",actions:o,notify:s,existingPr:d.pr})}let l=null;o&&(l=await fe(a.id,mo(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 I({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&&zf(a.id,{actions:o}),e.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:/not found|not running|archived/i.test(s)?409:502;e.status(a).json({error:s})}});x.post("/api/tracks/:id/pr-exists",async(t,e)=>{let{offerId:n,choice:r}=t.body||{};try{let o=await z(t.params.id);if(!o)return e.status(404).json({error:"track not found"});let{say:s}=await im(o,{offerId:n,choice:r});e.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;e.status(a).json({error:s})}});var Da=t=>e=>({...e,url:_S(e,t.headers)});x.get("/api/views",async(t,e)=>{try{let n=await Qd({trackId:t.query.track||void 0});e.json({views:n.map(Da(t)),maxLive:Ln})}catch(n){e.status(500).json({error:n?.message||String(n)})}});x.get("/api/views/:id",async(t,e)=>{let n=await Gb(t.params.id);if(!n)return e.status(404).json({error:"view not found"});e.json({view:Da(t)(n),session:yo(n.slug)})});x.post("/api/views",async(t,e)=>{let{trackId:n,name:r,cmd:o,cwd:s,port:a}=t.body||{};try{let i=n?await z(n):null;if(!i&&s&&(i=(await et()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+ut.sep)))||null),!i)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let c=await ef({trackId:i.id,name:r,cmd:o,cwd:i.cwd,serveCwd:s,port:a,box:i.leadBox,branch:i.workspace?.branch??null});e.json({ok:!0,view:Da(t)(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);e.status(l).json({error:c})}});x.post("/api/views/:id/stop",async(t,e)=>{try{e.json({ok:!0,view:Da(t)(await Vb(t.params.id))})}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:500).json({error:r})}});x.post("/api/views/:id/restart",async(t,e)=>{try{e.json({ok:!0,view:Da(t)(await zb(t.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;e.status(o).json({error:r})}});x.delete("/api/views/:id",async(t,e)=>{try{e.json(await Jb(t.params.id))}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:500).json({error:r})}});var E1=[["linear",Or,kp],["jira",jc,yp]],hm=new Map;x.get("/api/integrations/ticketing",async(t,e)=>{try{let n=await gp(),r={};for(let[o,s,a]of E1){let i=await s();if(!i){hm.delete(o),r[o]={configured:!1};continue}let c=hm.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},hm.set(o,c)}r[o]={...c.body,flow:n},o==="jira"&&i.tokenExpiresAt&&(r[o].tokenExpiresAt=i.tokenExpiresAt)}e.json(r)}catch(n){e.status(500).json({error:n?.message||String(n)})}});x.get("/api/tickets/flow",async(t,e)=>{try{e.json({flow:await gp()})}catch(n){e.status(500).json({error:n?.message||String(n)})}});x.post("/api/tickets/flow",async(t,e)=>{let{trackId:n,cwd:r,set:o,actor:s}=t.body||{};try{let a=await nx(o),i=n?await z(n):null;!i&&r&&(i=(await et()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+ut.sep)))||null),i&&await I({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(()=>{}),e.json({ok:!0,flow:a})}catch(a){let i=a?.message||String(a);e.status(/unknown|nothing to set/i.test(i)?400:500).json({error:i})}});var Ba=async(t,e)=>{let n=t?await z(t):null;return!n&&e&&(n=(await et()).find(o=>o.cwd&&(e===o.cwd||e.startsWith(o.cwd+ut.sep)))||null),n};x.get("/api/circuits",async(t,e)=>{try{e.json({circuits:await pp()})}catch(n){e.status(502).json({error:n?.message||String(n)})}});x.post("/api/circuits/link",async(t,e)=>{let{trackId:n,cwd:r,ref:o}=t.body||{};try{let s=await Ba(n,r);if(!s)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});if(!o)return e.status(400).json({error:"ref (circuit name or id) required"});let a=await Bo(o);await Pc(s,a,{source:"chat"}),e.json({ok:!0,trackId:s.id,circuit:a})}catch(s){let a=s?.message||String(s);e.status(/required|no circuit|names \d|no plane/i.test(a)?400:502).json({error:a})}});x.post("/api/circuits/unlink",async(t,e)=>{let{trackId:n,cwd:r}=t.body||{};try{let o=await Ba(n,r);if(!o)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});await Pc(o,null,{source:"chat"}),e.json({ok:!0,trackId:o.id})}catch(o){e.status(502).json({error:o?.message||String(o)})}});var $v=async(t,e,n)=>{if(t)return{ref:t,track:await Ba(e,n)};let r=await Ba(e,n),o=r?await hp(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}};x.post("/api/blueprints/publish",async(t,e)=>{let{trackId:n,cwd:r,circuit:o,newCircuit:s,name:a,markdown:i}=t.body||{};try{if(!i||!String(i).trim())return e.status(400).json({error:"markdown required"});let{ref:c}=s?{ref:null}:await $v(o,n,r),l=await X0({circuitRef:c,newCircuitName:s,name:a,markdown:i});e.json({ok:!0,...l})}catch(c){let l=c?.message||String(c);e.status(/required|no circuit|names \d|no plane|isn't in a circuit|run from inside/i.test(l)?400:502).json({error:l})}});x.get("/api/blueprints/show",async(t,e)=>{try{let{ref:n}=await $v(t.query.circuit,t.query.track,t.query.cwd);e.json(await mp(n))}catch(n){let r=n?.message||String(n);e.status(/no blueprint|no circuit|isn't in a circuit|run from inside|names \d/i.test(r)?404:502).json({error:r})}});x.post("/api/blueprints/tag",async(t,e)=>{let{trackId:n,cwd:r,itemIds:o}=t.body||{};try{let s=Array.isArray(o)?o.map(String):[];if(!s.length)return e.status(400).json({error:"itemIds required (BP-\u2026 ids)"});let a=await Ba(n,r);if(!a)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=await hp(a.id);if(!i)return e.status(400).json({error:"this Track isn't in a circuit \u2014 link one first (bostrat-circuit link \u2026)"});let c=await Z0(a,i,s);e.json({ok:!0,trackId:a.id,...c})}catch(s){let a=s?.message||String(s);e.status(/unknown\/unbindable|required|no blueprint|isn't in a circuit/i.test(a)?400:502).json({error:a})}});x.post("/api/tickets/link",async(t,e)=>{let{trackId:n,cwd:r,ref:o}=t.body||{};try{let s=n?await z(n):null;if(!s&&r&&(s=(await et()).find(c=>c.cwd&&(r===c.cwd||r.startsWith(c.cwd+ut.sep)))||null),!s)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});if(!o)return e.status(400).json({error:"ref (issue URL or key) required"});let a=await Lo(s,o,{source:n?"api":"cli"});e.json({ok:!0,trackId:s.id,ticket:a})}catch(s){let a=s?.message||String(s);e.status(/not a Linear|not found|no ticketing|required/i.test(a)?400:502).json({error:a})}});x.get("/api/tickets/status",async(t,e)=>{let{cwd:n,track:r}=t.query;try{let o=r?await z(r):null;if(!o&&n&&(o=(await et()).find(a=>a.cwd&&(n===a.cwd||String(n).startsWith(a.cwd+ut.sep)))||null),!o)return e.status(400).json({error:"track (or a cwd inside a Track workspace) required"});e.json({trackId:o.id,configured:await yx(),ticket:await Fe(o.id)})}catch(o){e.status(500).json({error:o?.message||String(o)})}});x.get("/api/tracks/:id/ticket",async(t,e)=>{e.json({ticket:await Fe(t.params.id)})});x.post("/api/tracks/:id/ticket",async(t,e)=>{try{let n=await z(t.params.id);if(!n)return e.status(404).json({error:"track not found"});let r=await Lo(n,(t.body||{}).ref,{source:"api"});e.json({ok:!0,ticket:r})}catch(n){let r=n?.message||String(n);e.status(/not a Linear|not found|no ticketing|required/i.test(r)?400:502).json({error:r})}});x.delete("/api/tracks/:id/ticket",async(t,e)=>{e.json({ok:!0,removed:await Cp(t.params.id)})});var wl=t=>/no ticket linked|unknown offer|unknown state/i.test(t)?404:/already answered/i.test(t)?409:/required|no ticketing/i.test(t)?400:502;x.get("/api/tracks/:id/ticket/states",async(t,e)=>{try{e.json(await Sx(t.params.id))}catch(n){let r=n?.message||String(n);e.status(wl(r)).json({error:r})}});x.post("/api/tracks/:id/ticket/state",async(t,e)=>{try{e.json({ok:!0,...await Mp(t.params.id,(t.body||{}).stateId)})}catch(n){let r=n?.message||String(n);e.status(wl(r)).json({error:r})}});x.post("/api/tracks/:id/ticket/comment",async(t,e)=>{try{e.json({ok:!0,...await vx(t.params.id,(t.body||{}).body)})}catch(n){let r=n?.message||String(n);e.status(wl(r)).json({error:r})}});x.post("/api/tracks/:id/ticket-offer",async(t,e)=>{let{offerId:n,accept:r}=t.body||{};try{let o=await z(t.params.id);if(!o)return e.status(404).json({error:"track not found"});e.json({ok:!0,...await Tx(o,n,r===!0)})}catch(o){let s=o?.message||String(o);e.status(wl(s)).json({error:s})}});x.post("/api/tracks/:id/fullscreen-offer",async(t,e)=>{let{offerId:n,accept:r}=t.body||{};try{e.json(await sp(t.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;e.status(a).json({error:s})}});x.post("/api/tickets/propose",async(t,e)=>{let{trackId:n,cwd:r,plan:o}=t.body||{};try{let s=n?await z(n):null;if(!s&&r&&(s=(await et()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+ut.sep)))||null),!s)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});e.json({ok:!0,trackId:s.id,proposal:await Ex(s,o)})}catch(s){let a=s?.message||String(s);e.status(/no ticketing|are off|needs an epic|too many|required/i.test(a)?400:502).json({error:a})}});x.get("/api/tickets/teams",async(t,e)=>{try{e.json({teams:await Ax()})}catch(n){let r=n?.message||String(n);e.status(/no ticketing/i.test(r)?400:502).json({error:r})}});x.post("/api/tracks/:id/ticket-create-offer",async(t,e)=>{let{proposalId:n,accept:r,teamId:o}=t.body||{};try{let s=await z(t.params.id);if(!s)return e.status(404).json({error:"track not found"});e.json({ok:!0,...await _x(s,n,r===!0,{teamId:o||null})})}catch(s){let a=s?.message||String(s);e.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})}});x.get("/api/mocks",async(t,e)=>{try{e.json({mocks:await Xs({trackId:t.query.track||void 0,group:t.query.group||void 0})})}catch(n){e.status(500).json({error:n?.message||String(n)})}});x.get("/api/mocks/:id",async(t,e)=>{let n=await en(t.params.id);if(!n)return e.status(404).json({error:"mock not found"});e.json({mock:n})});x.get("/api/mocks/:id/png",async(t,e)=>{let n=await en(t.params.id);if(!n)return e.status(404).json({error:"mock not found"});let r=ke(n,t.query.v??null);if(!r)return e.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=Js(n,r,"png");if(!o)return e.status(404).json({error:"no image for this version (poster extraction failed)"});e.set("cache-control","private, max-age=31536000, immutable"),e.sendFile(o,s=>{s&&!e.headersSent&&e.status(404).json({error:"rendered artifact missing"})})});x.get("/api/mocks/:id/media",async(t,e)=>{let n=await en(t.params.id);if(!n)return e.status(404).json({error:"mock not found"});let r=ke(n,t.query.v??null);if(!r)return e.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=Js(n,r,"video");if(!o)return e.status(404).json({error:"this version has no video (image or html sourced)"});e.set("cache-control","private, max-age=31536000, immutable"),e.sendFile(o,s=>{s&&!e.headersSent&&e.status(404).json({error:"video artifact missing"})})});x.get("/api/mocks/:id/html",async(t,e)=>{let n=await en(t.params.id);if(!n)return e.status(404).json({error:"mock not found"});let r=ke(n,t.query.v??null);if(!r?.htmlRel)return e.status(404).json({error:"this version has no HTML source (image-sourced)"});e.set("content-security-policy","sandbox"),e.sendFile(le(n,r.v).html,o=>{o&&!e.headersSent&&e.status(404).json({error:"source artifact missing"})})});x.post("/api/mocks",async(t,e)=>{let n=Buffer.isBuffer(t.body)?t.body:null,r=n&&pc(n)?n:null,o=n&&!r?n:null,s=n?t.query:t.body||{},{trackId:a,name:i,cwd:c,width:l,group:u}=s;try{let d=a?await z(a):null;if(!d&&c&&(d=(await et()).find(w=>w.cwd&&(c===w.cwd||c.startsWith(w.cwd+ut.sep)))||null),!d)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let f=(d.boxes||[]).find(m=>m.name===d.leadBox),p=await Ek({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:f?.agent||null});e.json({ok:!0,mock:p})}catch(d){let f=d?.message||String(d);e.status(/required|invalid|must be/i.test(f)?400:500).json({error:f})}});x.post("/api/mocks/:id/update",async(t,e)=>{let n=Buffer.isBuffer(t.body)?t.body:null,r=n&&pc(n)?n:null;try{let o=await _k(t.params.id,{html:n?null:(t.body||{}).html,image:r,video:n&&!r?n:null,width:n?t.query.width:(t.body||{}).width});e.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;e.status(a).json({error:s})}});x.post("/api/mocks/:id/pick",async(t,e)=>{try{let{mock:n,siblings:r}=await $k(t.params.id),o=r.length?` over ${r.map(s=>`"${s.name}"`).join(", ")}`:"";await fe(n.trackId,`Design decision: go with "${n.name}" (mock:${n.id})${o} \u2014 proceed with this design.`,{kind:"mock-picked"}).catch(()=>{}),e.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;e.status(o).json({error:r})}});x.delete("/api/mocks/:id",async(t,e)=>{try{let n=(await zk(t.params.id)).map(r=>({id:r.id,name:r.name}));e.json({...await Ok(t.params.id),...n.length?{danglingFlows:n}:{}})}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:500).json({error:r})}});x.get("/api/flows",async(t,e)=>{try{e.json({flows:await Wk({trackId:t.query.track||void 0})})}catch(n){e.status(500).json({error:n?.message||String(n)})}});x.get("/api/flows/:id",async(t,e)=>{let n=await qk(t.params.id);if(!n)return e.status(404).json({error:"flow not found"});e.json({flow:n})});x.post("/api/flows",async(t,e)=>{let{trackId:n,name:r,steps:o,cwd:s}=t.body||{};try{let a=n?await z(n):null;if(!a&&s&&(a=(await et()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+ut.sep)))||null),!a)return e.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 Kk({trackId:a.id,name:r,steps:o,cwd:a.cwd,box:a.leadBox,agent:i?.agent||null});e.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;e.status(c).json({error:i})}});x.post("/api/flows/:id/update",async(t,e)=>{try{let{steps:n,note:r}=t.body||{};e.json({ok:!0,flow:await Gk(t.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;e.status(o).json({error:r})}});x.delete("/api/flows/:id",async(t,e)=>{try{e.json(await Vk(t.params.id))}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:500).json({error:r})}});x.get("/api/runbooks",async(t,e)=>{try{let n=t.query.track||void 0;if(!n&&t.query.cwd){let s=await et(),a=String(t.query.cwd);if(n=s.find(i=>i.cwd&&(a===i.cwd||a.startsWith(i.cwd+ut.sep)))?.id,!n)return e.json({runbooks:[]})}let{runbooks:r,fleetDegraded:o}=await n0({trackId:n,status:t.query.status||void 0});e.json({runbooks:r,...o?{fleetDegraded:!0}:{}})}catch(n){e.status(500).json({error:n?.message||String(n)})}});x.get("/api/runbooks/:id",async(t,e)=>{let n=await Af(t.params.id);if(!n)return e.status(404).json({error:"runbook not found"});e.json({runbook:n})});x.get("/api/runbooks/:id/md",async(t,e)=>{let n=await Af(t.params.id);if(!n)return e.status(404).json({error:"runbook not found"});let r=t0(n,t.query.v??null);if(!r)return e.status(404).json({error:"no such version"});if(e.set("content-security-policy","sandbox"),e.set("cache-control","private, max-age=31536000, immutable"),e.type("text/markdown; charset=utf-8"),n.remote){let o=await r0(n,r.v);return typeof o!="string"?e.status(404).json({error:"runbook artifact missing"}):e.send(o)}e.sendFile(sn(n,r.v),o=>{o&&!e.headersSent&&e.status(404).json({error:"runbook artifact missing"})})});x.get("/api/loops",async(t,e)=>{e.json(await Qp())});x.post("/api/loops/report",async(t,e)=>{let{outcome:n,note:r,cwd:o}=t.body||{};if(!["ok","acted","attention"].includes(n))return e.status(400).json({error:"outcome must be one of ok | acted | attention"});if(!o)return e.status(400).json({error:"cwd required"});let a=(await et()).find(u=>u.cwd&&(o===u.cwd||o.startsWith(u.cwd+ut.sep)))||null;if(!a)return e.status(400).json({error:"cwd is not inside a Track workspace"});let i=await Qp();if(i.source!=="plane")return e.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 e.status(404).json({error:`Track "${a.name}" is not a loop's run Track \u2014 nothing to report on`});let l=await OS({loopId:c.id,outcome:n,note:r});if(!l.ok)return e.status(l.status||503).json({error:l.error||"report failed"});e.json({ok:!0,loop:{id:c.id,name:c.name},run:l.run})});x.post("/api/runbooks",async(t,e)=>{let{trackId:n,name:r,md:o,cwd:s}=t.body||{};try{let a=n?await z(n):null;if(!a&&s&&(a=(await et()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+ut.sep)))||null),!a)return e.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 o0({trackId:a.id,trackName:a.name,name:r,md:o,cwd:a.cwd,box:a.leadBox,agent:i?.agent||null});e.json({ok:!0,runbook:c})}catch(a){let i=a?.message||String(a);e.status(/required|invalid|over the|secret VALUE/i.test(i)?400:500).json({error:i})}});x.post("/api/runbooks/:id/update",async(t,e)=>{try{let{md:n,note:r}=t.body||{};e.json({ok:!0,runbook:await s0(t.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;e.status(o).json({error:r})}});x.post("/api/runbooks/:id/status",async(t,e)=>{try{e.json({ok:!0,runbook:await a0(t.params.id,(t.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;e.status(o).json({error:r})}});x.delete("/api/runbooks/:id",async(t,e)=>{try{e.json(await i0(t.params.id))}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:500).json({error:r})}});x.get("/api/changelog/draft",async(t,e)=>{try{let n=PS(t.query.since||null);e.json({since:n,repos:tm(),prs:await NS(n)})}catch(n){let r=n?.message||String(n);e.status(/unparseable/i.test(r)?400:500).json({error:r})}});x.post("/api/changelog/publish",async(t,e)=>{let{md:n,day:r,trackId:o,cwd:s}=t.body||{};try{let a=o?await z(o):null;if(!a&&s&&(a=(await et()).find(c=>c.cwd&&(s===c.cwd||String(s).startsWith(c.cwd+ut.sep)))||null),!a)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});e.json({ok:!0,entry:await BS(a,{md:n,day:r})})}catch(a){let i=a?.message||String(a);e.status(/required|invalid|no `- `|over the|secret VALUE/i.test(i)?400:500).json({error:i})}});var _1=120,wm=400,hl=null;x.post("/api/notify",async(t,e)=>{let{title:n,body:r,urgency:o,cwd:s,trackId:a}=t.body||{};try{let i=typeof r=="string"?r.trim():"";if(!i)return e.status(400).json({error:"body (the message) required"});if(i.length>wm)return e.status(400).json({error:`message is ${i.length} chars \u2014 over the ${wm} cap; a notification is a nudge, put the detail in chat`});let c=Zs(`${n||""}
484
- ${i}`);if(c.length)return e.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 z(a):null;if(!l&&s&&(l=(await et()).find(m=>m.cwd&&(s===m.cwd||s.startsWith(m.cwd+ut.sep)))||null),!l)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let u=(l.boxes||[]).find(p=>p.name===l.leadBox),d=(p,m)=>String(p).replace(/\s+/g," ").trim().slice(0,m),f={title:n?d(n,_1):l.name,body:d(i,wm),urgency:o==="high"?"high":"normal",trackName:l.name,ts:Date.now()};await I(l,{type:"notify.raised",actor:"agent",boxId:l.leadBox??null,provider:u?.agent||null,payload:f}),e.json({ok:!0,notification:f,delivered:hl?hl.status().connected:null})}catch(i){e.status(500).json({error:i?.message||String(i)})}});x.post("/api/dictation",async(t,e)=>{if(!Buffer.isBuffer(t.body)||t.body.length===0)return e.status(400).json({error:"expected a raw audio body"});try{e.json(await wv(t.body,t.headers["content-type"]))}catch(n){e.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});x.get("/api/dictation/glossary",async(t,e)=>{e.json({configured:!!await wa(),terms:await pm(),problem:await hv()})});x.post("/api/dictation/learn",async(t,e)=>{let{transcript:n,finalText:r}=t.body||{};if(typeof n!="string"||typeof r!="string")return e.status(400).json({error:"transcript and finalText are required"});e.json({learned:await mv(n,r)})});x.get("/api/tracks/:id/voice-chat",async(t,e)=>{if(!await z(t.params.id))return e.status(404).json({error:"track not found"});e.json(await gv())});x.post("/api/tracks/:id/voice-chat/session",async(t,e)=>{try{let n=await z(t.params.id);if(!n)return e.status(404).json({error:"track not found"});if(n.archivedAt)return e.status(409).json({error:"track is archived"});e.json(await yv())}catch(n){e.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});x.post("/api/tracks/:id/voice-chat/usage",async(t,e)=>{try{let n=await z(t.params.id);if(!n)return e.status(404).json({error:"track not found"});let{model:r,usage:o,seconds:s}=t.body||{};e.json({ok:!0,...await bv(n,{model:r,usage:o,seconds:s})})}catch(n){e.status(n?.status||500).json({error:n?.message||String(n)})}});x.post("/api/tracks",async(t,e)=>{let{name:n,cwd:r,repo:o,repos:s,agent:a,skipPermissions:i,ticket:c,circuit:l}=t.body||{};try{let u=await _c({name:n,cwd:r,repo:o,repos:s,agent:a,skipPermissions:i!==!1}),d=null;if(c)try{await Lo(u,c,{source:"create"})}catch(p){d=p?.message||String(p)}let f=null;if(l)try{await Pc(u,await Bo(l),{source:"picker"})}catch(p){f=p?.message||String(p)}e.json({ok:!0,track:u,...d?{ticketWarning:d}:{},...f?{circuitWarning:f}:{}})}catch(u){let d=u?.message||String(u);e.status(/required|unknown agent|invalid|must be/i.test(d)?400:500).json({error:d})}});x.get("/api/tracks/:id",async(t,e)=>{let n=await z(t.params.id);if(!n)return e.status(404).json({error:"track not found"});e.json({track:n,handoff:Ov(No(t.params.id)),subtasks:$r(t.params.id).map(ja)})});x.delete("/api/tracks/:id",async(t,e)=>{try{let n=await np(t.params.id,{cascadeMocks:t.query.mocks!=="0",cascadeRunbooks:t.query.runbooks==="1"});await Cp(t.params.id).catch(()=>{}),e.json(n)}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:500).json({error:r})}});x.post("/api/tracks/:id/archive",async(t,e)=>{try{e.json({ok:!0,track:await Rr(t.params.id)})}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:/already archived/i.test(r)?409:500).json({error:r})}});x.post("/api/tracks/:id/unarchive",async(t,e)=>{try{e.json({ok:!0,track:await rp(t.params.id)})}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:/not archived/i.test(r)?409:500).json({error:r})}});x.get("/api/tracks/:id/messages",async(t,e)=>{let n=await vc(t.params.id);if(!n)return e.status(404).json({error:"track not found"});e.json(n)});x.get("/api/tracks/:id/events",async(t,e)=>{let n=await z(t.params.id);if(!n)return e.status(404).json({error:"track not found"});e.set({"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive","x-accel-buffering":"no"}),e.flushHeaders();let r=i=>e.write(`id: ${i.seq}
510
+ `));let p=l.map(k=>k.name).join(", "),h=c&&i?` in the ${i.name}/ checkout`:"",w=await me(a.id,`CI is red on PR #${o.number} "${o.title}" (${o.url}) \u2014 branch ${o.headRefName}${h}. Failing check${l.length===1?"":"s"}: ${p}. The failure log is at ${d} 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"}),y=s;y&&(await oe({repo:y,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await Sb(y,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await Ae("fix-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{checks:l.map(k=>k.name)}}),e.json({ok:!0,leadBox:w.leadBox,queued:!!w.queued,checks:l.map(k=>k.name),log:d})}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;e.status(a).json({error:s})}});S.post("/api/git/prs/reconcile",async(t,e)=>{let{repo:n,number:r}=t.body||{};try{let o=await Oo(n,r);if(o.mergeable!=="CONFLICTING")return e.status(409).json({error:"this PR does not conflict with its base branch"});let s=await lt(n).catch(()=>null),a=await oT({repo:n,number:r,branch:o.headRefName});if(!a)return e.status(404).json({error:`no active Track owns PR #${o.number} (branch "${o.headRefName}")`});let i=ae(a.workspace).find(f=>f.base===n||s&&f.repo===s)??null,c=a.workspace?.kind==="multi"&&i?` In the ${i.name}/ checkout:`:"",l=await me(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 oe({repo:u,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await vb(u,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await Ae("reconcile-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{base:o.baseRefName}}),e.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;e.status(a).json({error:s})}});S.post("/api/tracks/:id/pr-offer",async(t,e)=>{let{offerId:n,action:r}=t.body||{};try{let o=null;if(Array.isArray(t.body?.actions)){if(o=Qi.filter(f=>t.body.actions.includes(f)),!o.length)return e.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 e.status(400).json({error:'offerId and actions ["commit"|"rebase"|"push"|"pr"] (or action "dismiss") required'});if(!n)return e.status(400).json({error:"offerId required"});let s=o!=null&&t.body?.notify===!0,a=await Y(t.params.id);if(!a)return e.status(404).json({error:"track not found"});let i=await F(a),c=i.find(f=>f.type==="pr.offered"&&f.payload?.offerId===n);if(!c)return e.status(404).json({error:"unknown offer"});if(i.some(f=>f.type==="pr.offer.answered"&&f.payload?.offerId===n))return e.status(409).json({error:"offer already answered"});if(o?.includes("pr")){let f=await Om(a,c,{actions:o,notify:s});if(f)return e.json({ok:!0,offerId:n,action:"pr-exists",actions:o,notify:s,existingPr:f.pr})}let l=null;o&&(l=await me(a.id,To(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 I({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&&pp(a.id,{actions:o}),e.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:/not found|not running|archived/i.test(s)?409:502;e.status(a).json({error:s})}});S.post("/api/tracks/:id/pr-exists",async(t,e)=>{let{offerId:n,choice:r}=t.body||{};try{let o=await Y(t.params.id);if(!o)return e.status(404).json({error:"track not found"});let{say:s}=await Cm(o,{offerId:n,choice:r});e.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;e.status(a).json({error:s})}});var za=t=>e=>({...e,url:YS(e,t.headers)});S.get("/api/views",async(t,e)=>{try{let n=await pf({trackId:t.query.track||void 0});e.json({views:n.map(za(t)),maxLive:Wn})}catch(n){e.status(500).json({error:n?.message||String(n)})}});S.get("/api/views/:id",async(t,e)=>{let n=await fk(t.params.id);if(!n)return e.status(404).json({error:"view not found"});e.json({view:za(t)(n),session:Io(n.slug)})});S.post("/api/views",async(t,e)=>{let{trackId:n,name:r,cmd:o,cwd:s,port:a}=t.body||{};try{let i=n?await Y(n):null;if(!i&&s&&(i=(await nt()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+ut.sep)))||null),!i)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let c=await hf({trackId:i.id,name:r,cmd:o,cwd:i.cwd,serveCwd:s,port:a,box:i.leadBox,branch:i.workspace?.branch??null});e.json({ok:!0,view:za(t)(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);e.status(l).json({error:c})}});S.post("/api/views/:id/stop",async(t,e)=>{try{e.json({ok:!0,view:za(t)(await pk(t.params.id))})}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:500).json({error:r})}});S.post("/api/views/:id/restart",async(t,e)=>{try{e.json({ok:!0,view:za(t)(await mk(t.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;e.status(o).json({error:r})}});S.delete("/api/views/:id",async(t,e)=>{try{e.json(await hk(t.params.id))}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:500).json({error:r})}});var lj=[["linear",Lr,Kp],["jira",Zc,Wp]],Fm=new Map;S.get("/api/integrations/ticketing",async(t,e)=>{try{let n=await Hp(),r={};for(let[o,s,a]of lj){let i=await s();if(!i){Fm.delete(o),r[o]={configured:!1};continue}let c=Fm.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},Fm.set(o,c)}r[o]={...c.body,flow:n},o==="jira"&&i.tokenExpiresAt&&(r[o].tokenExpiresAt=i.tokenExpiresAt)}e.json(r)}catch(n){e.status(500).json({error:n?.message||String(n)})}});S.get("/api/tickets/flow",async(t,e)=>{try{e.json({flow:await Hp()})}catch(n){e.status(500).json({error:n?.message||String(n)})}});S.post("/api/tickets/flow",async(t,e)=>{let{trackId:n,cwd:r,set:o,actor:s}=t.body||{};try{let a=await Rx(o),i=n?await Y(n):null;!i&&r&&(i=(await nt()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+ut.sep)))||null),i&&await I({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(()=>{}),e.json({ok:!0,flow:a})}catch(a){let i=a?.message||String(a);e.status(/unknown|nothing to set/i.test(i)?400:500).json({error:i})}});var Va=async(t,e)=>{let n=t?await Y(t):null;return!n&&e&&(n=(await nt()).find(o=>o.cwd&&(e===o.cwd||e.startsWith(o.cwd+ut.sep)))||null),n};S.get("/api/circuits",async(t,e)=>{try{e.json({circuits:await jp()})}catch(n){e.status(502).json({error:n?.message||String(n)})}});S.post("/api/circuits/link",async(t,e)=>{let{trackId:n,cwd:r,ref:o}=t.body||{};try{let s=await Va(n,r);if(!s)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});if(!o)return e.status(400).json({error:"ref (circuit name or id) required"});let a=await Vo(o);await zc(s,a,{source:"chat"}),e.json({ok:!0,trackId:s.id,circuit:a})}catch(s){let a=s?.message||String(s);e.status(/required|no circuit|names \d|no plane/i.test(a)?400:502).json({error:a})}});S.post("/api/circuits/unlink",async(t,e)=>{let{trackId:n,cwd:r}=t.body||{};try{let o=await Va(n,r);if(!o)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});await zc(o,null,{source:"chat"}),e.json({ok:!0,trackId:o.id})}catch(o){e.status(502).json({error:o?.message||String(o)})}});var sT=async(t,e,n)=>{if(t)return{ref:t,track:await Va(e,n)};let r=await Va(e,n),o=r?await Fp(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(t,e)=>{let{trackId:n,cwd:r,circuit:o,newCircuit:s,name:a,markdown:i}=t.body||{};try{if(!i||!String(i).trim())return e.status(400).json({error:"markdown required"});let{ref:c}=s?{ref:null}:await sT(o,n,r),l=await Tx({circuitRef:c,newCircuitName:s,name:a,markdown:i});e.json({ok:!0,...l})}catch(c){let l=c?.message||String(c);e.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(t,e)=>{try{let{ref:n}=await sT(t.query.circuit,t.query.track,t.query.cwd);e.json(await Lp(n))}catch(n){let r=n?.message||String(n);e.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/blueprints/tag",async(t,e)=>{let{trackId:n,cwd:r,itemIds:o}=t.body||{};try{let s=Array.isArray(o)?o.map(String):[];if(!s.length)return e.status(400).json({error:"itemIds required (BP-\u2026 ids)"});let a=await Va(n,r);if(!a)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=await Fp(a.id);if(!i)return e.status(400).json({error:"this Track isn't in a circuit \u2014 link one first (bostrat-circuit link \u2026)"});let c=await Ax(a,i,s);e.json({ok:!0,trackId:a.id,...c})}catch(s){let a=s?.message||String(s);e.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(t,e)=>{let{trackId:n,cwd:r,ref:o}=t.body||{};try{let s=n?await Y(n):null;if(!s&&r&&(s=(await nt()).find(c=>c.cwd&&(r===c.cwd||r.startsWith(c.cwd+ut.sep)))||null),!s)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});if(!o)return e.status(400).json({error:"ref (issue URL or key) required"});let a=await Yo(s,o,{source:n?"api":"cli"});e.json({ok:!0,trackId:s.id,ticket:a})}catch(s){let a=s?.message||String(s);e.status(/not a Linear|not found|no ticketing|required/i.test(a)?400:502).json({error:a})}});S.get("/api/tickets/status",async(t,e)=>{let{cwd:n,track:r}=t.query;try{let o=r?await Y(r):null;if(!o&&n&&(o=(await nt()).find(a=>a.cwd&&(n===a.cwd||String(n).startsWith(a.cwd+ut.sep)))||null),!o)return e.status(400).json({error:"track (or a cwd inside a Track workspace) required"});e.json({trackId:o.id,configured:await Kx(),ticket:await He(o.id)})}catch(o){e.status(500).json({error:o?.message||String(o)})}});S.get("/api/tracks/:id/ticket",async(t,e)=>{e.json({ticket:await He(t.params.id)})});S.post("/api/tracks/:id/ticket",async(t,e)=>{try{let n=await Y(t.params.id);if(!n)return e.status(404).json({error:"track not found"});let r=await Yo(n,(t.body||{}).ref,{source:"api"});e.json({ok:!0,ticket:r})}catch(n){let r=n?.message||String(n);e.status(/not a Linear|not found|no ticketing|required/i.test(r)?400:502).json({error:r})}});S.delete("/api/tracks/:id/ticket",async(t,e)=>{e.json({ok:!0,removed:await rm(t.params.id)})});var Rl=t=>/no ticket linked|unknown offer|unknown state/i.test(t)?404:/already answered/i.test(t)?409:/required|no ticketing/i.test(t)?400:502;S.get("/api/tracks/:id/ticket/states",async(t,e)=>{try{e.json(await Jx(t.params.id))}catch(n){let r=n?.message||String(n);e.status(Rl(r)).json({error:r})}});S.post("/api/tracks/:id/ticket/state",async(t,e)=>{try{e.json({ok:!0,...await om(t.params.id,(t.body||{}).stateId)})}catch(n){let r=n?.message||String(n);e.status(Rl(r)).json({error:r})}});S.post("/api/tracks/:id/ticket/comment",async(t,e)=>{try{e.json({ok:!0,...await Yx(t.params.id,(t.body||{}).body)})}catch(n){let r=n?.message||String(n);e.status(Rl(r)).json({error:r})}});S.post("/api/tracks/:id/ticket-offer",async(t,e)=>{let{offerId:n,accept:r}=t.body||{};try{let o=await Y(t.params.id);if(!o)return e.status(404).json({error:"track not found"});e.json({ok:!0,...await Xx(o,n,r===!0)})}catch(o){let s=o?.message||String(o);e.status(Rl(s)).json({error:s})}});S.post("/api/tracks/:id/fullscreen-offer",async(t,e)=>{let{offerId:n,accept:r}=t.body||{};try{e.json(await Ep(t.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;e.status(a).json({error:s})}});S.post("/api/tickets/propose",async(t,e)=>{let{trackId:n,cwd:r,plan:o}=t.body||{};try{let s=n?await Y(n):null;if(!s&&r&&(s=(await nt()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+ut.sep)))||null),!s)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});e.json({ok:!0,trackId:s.id,proposal:await Qx(s,o)})}catch(s){let a=s?.message||String(s);e.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(t,e)=>{try{e.json({teams:await Zx()})}catch(n){let r=n?.message||String(n);e.status(/no ticketing/i.test(r)?400:502).json({error:r})}});S.post("/api/tracks/:id/ticket-create-offer",async(t,e)=>{let{proposalId:n,accept:r,teamId:o}=t.body||{};try{let s=await Y(t.params.id);if(!s)return e.status(404).json({error:"track not found"});e.json({ok:!0,...await tS(s,n,r===!0,{teamId:o||null})})}catch(s){let a=s?.message||String(s);e.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(t,e)=>{try{e.json({mocks:await aa({trackId:t.query.track||void 0,group:t.query.group||void 0})})}catch(n){e.status(500).json({error:n?.message||String(n)})}});S.get("/api/mocks/:id",async(t,e)=>{let n=await rn(t.params.id);if(!n)return e.status(404).json({error:"mock not found"});e.json({mock:n})});S.get("/api/mocks/:id/png",async(t,e)=>{let n=await rn(t.params.id);if(!n)return e.status(404).json({error:"mock not found"});let r=ve(n,t.query.v??null);if(!r)return e.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=oa(n,r,"png");if(!o)return e.status(404).json({error:"no image for this version (poster extraction failed)"});e.set("cache-control","private, max-age=31536000, immutable"),e.sendFile(o,s=>{s&&!e.headersSent&&e.status(404).json({error:"rendered artifact missing"})})});S.get("/api/mocks/:id/media",async(t,e)=>{let n=await rn(t.params.id);if(!n)return e.status(404).json({error:"mock not found"});let r=ve(n,t.query.v??null);if(!r)return e.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=oa(n,r,"video");if(!o)return e.status(404).json({error:"this version has no video (image or html sourced)"});e.set("cache-control","private, max-age=31536000, immutable"),e.sendFile(o,s=>{s&&!e.headersSent&&e.status(404).json({error:"video artifact missing"})})});S.get("/api/mocks/:id/html",async(t,e)=>{let n=await rn(t.params.id);if(!n)return e.status(404).json({error:"mock not found"});let r=ve(n,t.query.v??null);if(!r?.htmlRel)return e.status(404).json({error:"this version has no HTML source (image-sourced)"});e.set("content-security-policy","sandbox"),e.sendFile(fe(n,r.v).html,o=>{o&&!e.headersSent&&e.status(404).json({error:"source artifact missing"})})});S.post("/api/mocks",async(t,e)=>{let n=Buffer.isBuffer(t.body)?t.body:null,r=n&&Ec(n)?n:null,o=n&&!r?n:null,s=n?t.query:t.body||{},{trackId:a,name:i,cwd:c,width:l,group:u}=s;try{let f=a?await Y(a):null;if(!f&&c&&(f=(await nt()).find(w=>w.cwd&&(c===w.cwd||c.startsWith(w.cwd+ut.sep)))||null),!f)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let d=(f.boxes||[]).find(h=>h.name===f.leadBox),p=await Gk({trackId:f.id,name:i,html:n?null:s.html,image:r,video:o,cwd:f.cwd,width:l,group:u,box:f.leadBox,agent:d?.agent||null});e.json({ok:!0,mock:p})}catch(f){let d=f?.message||String(f);e.status(/required|invalid|must be/i.test(d)?400:500).json({error:d})}});S.post("/api/mocks/:id/update",async(t,e)=>{let n=Buffer.isBuffer(t.body)?t.body:null,r=n&&Ec(n)?n:null;try{let o=await Vk(t.params.id,{html:n?null:(t.body||{}).html,image:r,video:n&&!r?n:null,width:n?t.query.width:(t.body||{}).width});e.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;e.status(a).json({error:s})}});S.post("/api/mocks/:id/pick",async(t,e)=>{try{let{mock:n,siblings:r}=await Yk(t.params.id),o=r.length?` over ${r.map(s=>`"${s.name}"`).join(", ")}`:"";await me(n.trackId,`Design decision: go with "${n.name}" (mock:${n.id})${o} \u2014 proceed with this design.`,{kind:"mock-picked"}).catch(()=>{}),e.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;e.status(o).json({error:r})}});S.delete("/api/mocks/:id",async(t,e)=>{try{let n=(await m0(t.params.id)).map(r=>({id:r.id,name:r.name}));e.json({...await Xk(t.params.id),...n.length?{danglingFlows:n}:{}})}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:500).json({error:r})}});S.get("/api/flows",async(t,e)=>{try{e.json({flows:await l0({trackId:t.query.track||void 0})})}catch(n){e.status(500).json({error:n?.message||String(n)})}});S.get("/api/flows/:id",async(t,e)=>{let n=await u0(t.params.id);if(!n)return e.status(404).json({error:"flow not found"});e.json({flow:n})});S.post("/api/flows",async(t,e)=>{let{trackId:n,name:r,steps:o,cwd:s}=t.body||{};try{let a=n?await Y(n):null;if(!a&&s&&(a=(await nt()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+ut.sep)))||null),!a)return e.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 d0({trackId:a.id,name:r,steps:o,cwd:a.cwd,box:a.leadBox,agent:i?.agent||null});e.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;e.status(c).json({error:i})}});S.post("/api/flows/:id/update",async(t,e)=>{try{let{steps:n,note:r}=t.body||{};e.json({ok:!0,flow:await f0(t.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;e.status(o).json({error:r})}});S.delete("/api/flows/:id",async(t,e)=>{try{e.json(await p0(t.params.id))}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:500).json({error:r})}});S.get("/api/runbooks",async(t,e)=>{try{let n=t.query.track||void 0;if(!n&&t.query.cwd){let s=await nt(),a=String(t.query.cwd);if(n=s.find(i=>i.cwd&&(a===i.cwd||a.startsWith(i.cwd+ut.sep)))?.id,!n)return e.json({runbooks:[]})}let{runbooks:r,fleetDegraded:o}=await S0({trackId:n,status:t.query.status||void 0});e.json({runbooks:r,...o?{fleetDegraded:!0}:{}})}catch(n){e.status(500).json({error:n?.message||String(n)})}});S.get("/api/runbooks/:id",async(t,e)=>{let n=await jf(t.params.id);if(!n)return e.status(404).json({error:"runbook not found"});e.json({runbook:n})});S.get("/api/runbooks/:id/md",async(t,e)=>{let n=await jf(t.params.id);if(!n)return e.status(404).json({error:"runbook not found"});let r=k0(n,t.query.v??null);if(!r)return e.status(404).json({error:"no such version"});if(e.set("content-security-policy","sandbox"),e.set("cache-control","private, max-age=31536000, immutable"),e.type("text/markdown; charset=utf-8"),n.remote){let o=await v0(n,r.v);return typeof o!="string"?e.status(404).json({error:"runbook artifact missing"}):e.send(o)}e.sendFile(cn(n,r.v),o=>{o&&!e.headersSent&&e.status(404).json({error:"runbook artifact missing"})})});S.get("/api/loops",async(t,e)=>{e.json(await Tm())});S.post("/api/loops/report",async(t,e)=>{let{outcome:n,note:r,cwd:o}=t.body||{};if(!["ok","acted","attention"].includes(n))return e.status(400).json({error:"outcome must be one of ok | acted | attention"});if(!o)return e.status(400).json({error:"cwd required"});let a=(await nt()).find(u=>u.cwd&&(o===u.cwd||o.startsWith(u.cwd+ut.sep)))||null;if(!a)return e.status(400).json({error:"cwd is not inside a Track workspace"});let i=await Tm();if(i.source!=="plane")return e.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 e.status(404).json({error:`Track "${a.name}" is not a loop's run Track \u2014 nothing to report on`});let l=await tv({loopId:c.id,outcome:n,note:r});if(!l.ok)return e.status(l.status||503).json({error:l.error||"report failed"});e.json({ok:!0,loop:{id:c.id,name:c.name},run:l.run})});S.post("/api/loops/propose",async(t,e)=>{let{trackId:n,cwd:r,plan:o}=t.body||{};try{let s=n?await Y(n):null;if(!s&&r&&(s=(await nt()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+ut.sep)))||null),!s)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});e.json({ok:!0,trackId:s.id,proposal:await sv(s,o)})}catch(s){e.status(400).json({error:s?.message||String(s)})}});S.post("/api/tracks/:id/loop-create-offer",async(t,e)=>{let{proposalId:n,accept:r,loopId:o,nextFireAt:s}=t.body||{};try{let a=await Y(t.params.id);if(!a)return e.status(404).json({error:"track not found"});e.json({ok:!0,...await av(a,n,r===!0,{loopId:o||null,nextFireAt:s??null})})}catch(a){let i=a?.message||String(a);e.status(/unknown proposal/i.test(i)?404:/already answered/i.test(i)?409:400).json({error:i})}});S.post("/api/runbooks",async(t,e)=>{let{trackId:n,name:r,md:o,cwd:s}=t.body||{};try{let a=n?await Y(n):null;if(!a&&s&&(a=(await nt()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+ut.sep)))||null),!a)return e.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 T0({trackId:a.id,trackName:a.name,name:r,md:o,cwd:a.cwd,box:a.leadBox,agent:i?.agent||null});e.json({ok:!0,runbook:c})}catch(a){let i=a?.message||String(a);e.status(/required|invalid|over the|secret VALUE/i.test(i)?400:500).json({error:i})}});S.post("/api/runbooks/:id/update",async(t,e)=>{try{let{md:n,note:r}=t.body||{};e.json({ok:!0,runbook:await A0(t.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;e.status(o).json({error:r})}});S.post("/api/runbooks/:id/status",async(t,e)=>{try{e.json({ok:!0,runbook:await E0(t.params.id,(t.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;e.status(o).json({error:r})}});S.delete("/api/runbooks/:id",async(t,e)=>{try{e.json(await _0(t.params.id))}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:500).json({error:r})}});S.get("/api/changelog/draft",async(t,e)=>{try{let n=lv(t.query.since||null);e.json({since:n,repos:Am(),prs:await uv(n)})}catch(n){let r=n?.message||String(n);e.status(/unparseable/i.test(r)?400:500).json({error:r})}});S.post("/api/changelog/publish",async(t,e)=>{let{md:n,day:r,trackId:o,cwd:s}=t.body||{};try{let a=o?await Y(o):null;if(!a&&s&&(a=(await nt()).find(c=>c.cwd&&(s===c.cwd||String(s).startsWith(c.cwd+ut.sep)))||null),!a)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});e.json({ok:!0,entry:await dv(a,{md:n,day:r})})}catch(a){let i=a?.message||String(a);e.status(/required|invalid|no `- `|over the|secret VALUE/i.test(i)?400:500).json({error:i})}});var uj=120,Um=400,Il=null;S.post("/api/notify",async(t,e)=>{let{title:n,body:r,urgency:o,cwd:s,trackId:a}=t.body||{};try{let i=typeof r=="string"?r.trim():"";if(!i)return e.status(400).json({error:"body (the message) required"});if(i.length>Um)return e.status(400).json({error:`message is ${i.length} chars \u2014 over the ${Um} cap; a notification is a nudge, put the detail in chat`});let c=ia(`${n||""}
511
+ ${i}`);if(c.length)return e.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 Y(a):null;if(!l&&s&&(l=(await nt()).find(h=>h.cwd&&(s===h.cwd||s.startsWith(h.cwd+ut.sep)))||null),!l)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let u=(l.boxes||[]).find(p=>p.name===l.leadBox),f=(p,h)=>String(p).replace(/\s+/g," ").trim().slice(0,h),d={title:n?f(n,uj):l.name,body:f(i,Um),urgency:o==="high"?"high":"normal",trackName:l.name,ts:Date.now()};await I(l,{type:"notify.raised",actor:"agent",boxId:l.leadBox??null,provider:u?.agent||null,payload:d}),e.json({ok:!0,notification:d,delivered:Il?Il.status().connected:null})}catch(i){e.status(500).json({error:i?.message||String(i)})}});S.post("/api/dictation",async(t,e)=>{if(!Buffer.isBuffer(t.body)||t.body.length===0)return e.status(400).json({error:"expected a raw audio body"});try{e.json(await Kv(t.body,t.headers["content-type"]))}catch(n){e.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});S.get("/api/dictation/glossary",async(t,e)=>{e.json({configured:!!await _a(),terms:await jm(),problem:await qv()})});S.post("/api/dictation/learn",async(t,e)=>{let{transcript:n,finalText:r}=t.body||{};if(typeof n!="string"||typeof r!="string")return e.status(400).json({error:"transcript and finalText are required"});e.json({learned:await Wv(n,r)})});S.get("/api/tracks/:id/voice-chat",async(t,e)=>{if(!await Y(t.params.id))return e.status(404).json({error:"track not found"});e.json(await Gv())});S.post("/api/tracks/:id/voice-chat/session",async(t,e)=>{try{let n=await Y(t.params.id);if(!n)return e.status(404).json({error:"track not found"});if(n.archivedAt)return e.status(409).json({error:"track is archived"});e.json(await Vv())}catch(n){e.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});S.post("/api/tracks/:id/voice-chat/usage",async(t,e)=>{try{let n=await Y(t.params.id);if(!n)return e.status(404).json({error:"track not found"});let{model:r,usage:o,seconds:s}=t.body||{};e.json({ok:!0,...await zv(n,{model:r,usage:o,seconds:s})})}catch(n){e.status(n?.status||500).json({error:n?.message||String(n)})}});S.post("/api/tracks",async(t,e)=>{let{name:n,cwd:r,repo:o,repos:s,agent:a,skipPermissions:i,ticket:c,circuit:l}=t.body||{};try{let u=await Lc({name:n,cwd:r,repo:o,repos:s,agent:a,skipPermissions:i!==!1}),f=null;if(c)try{await Yo(u,c,{source:"create"})}catch(p){f=p?.message||String(p)}let d=null;if(l)try{await zc(u,await Vo(l),{source:"picker"})}catch(p){d=p?.message||String(p)}e.json({ok:!0,track:u,...f?{ticketWarning:f}:{},...d?{circuitWarning:d}:{}})}catch(u){let f=u?.message||String(u);e.status(/required|unknown agent|invalid|must be/i.test(f)?400:500).json({error:f})}});S.get("/api/tracks/:id",async(t,e)=>{let n=await Y(t.params.id);if(!n)return e.status(404).json({error:"track not found"});e.json({track:n,handoff:aT(Go(t.params.id)),subtasks:jr(t.params.id).map(Ja)})});S.delete("/api/tracks/:id",async(t,e)=>{try{let n=await vp(t.params.id,{cascadeMocks:t.query.mocks!=="0",cascadeRunbooks:t.query.runbooks==="1"});await rm(t.params.id).catch(()=>{}),e.json(n)}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:500).json({error:r})}});S.post("/api/tracks/:id/archive",async(t,e)=>{try{e.json({ok:!0,track:await Br(t.params.id)})}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:/already archived/i.test(r)?409:500).json({error:r})}});S.post("/api/tracks/:id/unarchive",async(t,e)=>{try{e.json({ok:!0,track:await Tp(t.params.id)})}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:/not archived/i.test(r)?409:500).json({error:r})}});S.get("/api/tracks/:id/messages",async(t,e)=>{let n=await Dc(t.params.id);if(!n)return e.status(404).json({error:"track not found"});e.json(n)});S.get("/api/tracks/:id/events",async(t,e)=>{let n=await Y(t.params.id);if(!n)return e.status(404).json({error:"track not found"});e.set({"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive","x-accel-buffering":"no"}),e.flushHeaders();let r=i=>e.write(`id: ${i.seq}
485
512
  data: ${JSON.stringify(i)}
486
513
 
487
- `),o=Number(t.query.since??t.headers["last-event-id"])||0;for(let i of await L(n))i.seq>o&&r(i);let s=ew(n.id,r),a=setInterval(()=>e.write(`: hb
514
+ `),o=Number(t.query.since??t.headers["last-event-id"])||0;for(let i of await F(n))i.seq>o&&r(i);let s=Aw(n.id,r),a=setInterval(()=>e.write(`: hb
488
515
 
489
- `),25e3);t.on("close",()=>{clearInterval(a),s()})});x.get("/api/tracks/:id/search",async(t,e)=>{let n=await z(t.params.id);if(!n)return e.status(404).json({error:"track not found"});let r=String(t.query.q||"").trim();if(!r)return e.status(400).json({error:"q (query) is required"});let o=Math.min(Math.max(Number(t.query.k)||8,1),50),s=bs(await L(n)),a=wi(s,r,{k:o,role:t.query.role||null,tag:t.query.tag||null});e.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}))})});x.get("/api/memory",async(t,e)=>{e.json({stores:await zm()})});x.delete("/api/memory/:key/:file",async(t,e)=>{let n=String(t.params.key||"");if(!/^[a-z0-9][a-z0-9._-]*$/.test(n))return e.status(400).json({error:"bad store key"});try{e.json({ok:!0,...await Jm(n,String(t.params.file||""))})}catch(r){let o=r?.message||String(r);e.status(/not found/i.test(o)?404:/bad fact/i.test(o)?400:500).json({error:o})}});var I1=["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(`
490
- `);x.post("/api/tracks/:id/memory/consolidate",async(t,e)=>{try{e.json({ok:!0,...await fe(t.params.id,I1)})}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:/archived/i.test(r)?409:/not running/i.test(r)?400:500).json({error:r})}});x.post("/api/tracks/:id/lead/restart",async(t,e)=>{try{e.json({ok:!0,track:await $c(t.params.id)})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/mid-turn|terminal|archived/i.test(r)?409:500;e.status(o).json({error:r})}});x.post("/api/tracks/:id/say",async(t,e)=>{let{text:n,attachments:r}=t.body||{};try{e.json(await fe(t.params.id,n,{attachments:r}))}catch(o){let s=o?.message||String(o);if(o?.usageCap)return e.status(429).json({error:"usage_cap",message:s,cap:o.usageCap});e.status(/not found/i.test(s)?404:/archived/i.test(s)?409:/required|not running/i.test(s)?400:500).json({error:s})}});x.post("/api/tracks/:id/upload",async(t,e)=>{try{let n=await z(t.params.id);if(!n)return e.status(404).json({error:`track "${t.params.id}" not found`});if(n.archivedAt)return e.status(409).json({error:"track is archived"});if(!n.cwd)return e.status(409).json({error:"track has no workspace yet"});let r=Buffer.isBuffer(t.body)?t.body:null,o=await p0(n.cwd,{filename:t.query.filename,buffer:r});e.json({ok:!0,attachment:o})}catch(n){let r=n?.message||String(n);e.status(/too large|unsupported|empty|required/i.test(r)?400:500).json({error:r})}});x.get("/api/tracks/:id/uploads/:file",async(t,e)=>{try{let n=await z(t.params.id);if(!n)return e.status(404).json({error:`track "${t.params.id}" not found`});if(!n.cwd)return e.status(404).json({error:"track has no workspace"});let r=ut.basename(String(t.params.file||""));if(!r||!If(ut.extname(r).slice(1)))return e.status(400).json({error:"not an upload path"});e.set("cache-control","private, max-age=31536000, immutable"),e.set("content-security-policy","sandbox");let o=_f(n.cwd),s,a;try{s=await Ft.promises.realpath(o),a=await Ft.promises.realpath(ut.join(o,r))}catch{return e.status(404).json({error:"upload not found"})}if(!a.startsWith(s+ut.sep))return e.status(404).json({error:"upload not found"});e.sendFile(r,{root:o},i=>{i&&!e.headersSent&&e.status(404).json({error:"upload not found"})})}catch(n){e.status(500).json({error:n?.message||String(n)})}});var R1=/^[0-9a-fA-F-]{8,64}$/;x.get("/api/tracks/:id/chat-images/:box/:uuid/:idx",async(t,e)=>{try{let n=await z(t.params.id);if(!n)return e.status(404).json({error:`track "${t.params.id}" not found`});let{box:r,uuid:o}=t.params,s=Number(t.params.idx);if(!R1.test(o)||!Number.isInteger(s)||s<0)return e.status(400).json({error:"bad image ref"});let a=(n.boxes||[]).find(f=>f.name===r);if(!a||a.agent!=="claude"||!a.cwd||!a.sessionId)return e.status(404).json({error:"image source not available"});let i=qe(a.cwd,a.sessionId);if(!i)return e.status(404).json({error:"transcript not found"});let c=`"${o}"`,l=null,u=k1.createInterface({input:Ft.createReadStream(i,{encoding:"utf8"}),crlfDelay:1/0});for await(let f of u){if(!f.includes(c))continue;let p;try{p=JSON.parse(f)}catch{continue}if(p.uuid===o){l=p,u.close();break}}let d=l?Xl(l)[s]:null;if(!d||!/^image\//.test(d.mediaType))return e.status(404).json({error:"image not found"});e.set("content-type",d.mediaType),e.set("cache-control","private, max-age=31536000, immutable"),e.set("content-security-policy","sandbox"),e.send(Buffer.from(d.data,"base64"))}catch(n){e.status(500).json({error:n?.message||String(n)})}});x.post("/api/tracks/:id/interrupt",async(t,e)=>{try{e.json(await Ac(t.params.id))}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:/archived/i.test(r)?409:500).json({error:r})}});x.delete("/api/tracks/:id/queue",async(t,e)=>{try{let{removed:n,restored:r,draftRev:o}=await Vf(t.params.id);e.json({ok:!0,removed:n.filter(s=>s.kind!=="ship-notify"),restored:r,draftRev:o})}catch(n){e.status(500).json({error:n?.message||String(n)})}});x.post("/api/tracks/:id/answer-prompt",async(t,e)=>{let{promptId:n,answers:r,text:o}=t.body||{};try{e.json(await Tc(t.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;e.status(i).json({error:a})}});x.post("/api/setup/:provider/start",async(t,e)=>{try{let n=await ep({provider:t.params.provider,fresh:t.body?.fresh===!0});e.json({ok:!0,track:n})}catch(n){let r=n?.message||String(n);e.status(/unknown setup provider|isn't available/i.test(r)?400:500).json({error:r})}});x.post("/api/tracks/:id/navigate-prompt",async(t,e)=>{let{promptId:n,questionIndex:r}=t.body||{};try{e.json(await Kf(t.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;e.status(a).json({error:s})}});x.put("/api/tracks/:id/draft",async(t,e)=>{let{text:n,rev:r}=t.body||{};try{e.json(await Yf(t.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;e.status(a).json({error:s})}});x.get("/api/tracks/:id/usage",async(t,e)=>{let n=await z(t.params.id);if(!n)return e.status(404).json({error:"track not found"});let r=n.boxes?.find(s=>s.name===n.leadBox)||null,o=t.query.fresh==="1"||t.query.fresh==="true";e.json(await el(r,{fresh:o}))});x.post("/api/tracks/:id/model",async(t,e)=>{let{model:n}=t.body||{};try{e.json(await Xf(t.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;e.status(s).json({error:o})}});x.post("/api/tracks/:id/subtask",async(t,e)=>{let{agent:n,task:r,skipPermissions:o,reason:s}=t.body||{};try{let a=await up(t.params.id,{agent:n,task:r,skipPermissions:o!==!1,reason:s});e.json({ok:!0,subtask:ja(a)})}catch(a){let i=a?.message||String(a);if(a?.usageCap)return e.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;e.status(c).json({error:i})}});x.get("/api/tracks/:id/subtasks",(t,e)=>{e.json({subtasks:$r(t.params.id).map(ja)})});x.get("/api/tracks/:id/subtask/:sid/messages",async(t,e)=>{let n=await qf(t.params.id,t.params.sid);if(!n)return e.status(404).json({error:"subtask not found"});e.json(n)});x.post("/api/tracks/:id/subtask/:sid/cancel",(t,e)=>{try{e.json({ok:!0,subtask:ja(Mc(t.params.sid))})}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:409).json({error:r})}});x.post("/api/tracks/:id/subtask/:sid/merge-now",(t,e)=>{try{e.json({ok:!0,subtask:ja(dp(t.params.sid))})}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:409).json({error:r})}});function ja(t){return t?{id:t.id,agent:t.agent,task:t.task,skipPermissions:t.skipPermissions,step:t.step,running:!t.finishedAt,box:t.box,branch:t.branch,stat:t.stat,files:t.files||null,conflicts:t.conflicts||[],applied:t.applied,error:t.error,canceled:t.canceled,startedAt:t.startedAt,finishedAt:t.finishedAt}:null}x.post("/api/tracks/:id/handoff-lead",async(t,e)=>{let{toAgent:n,skipPermissions:r,reason:o}=t.body||{};try{let s=await Oc(t.params.id,n,r!==!1,o);e.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 e.status(429).json({error:"usage_cap",message:a,cap:s.usageCap});e.status(/already running/i.test(a)?409:/not found/i.test(a)?404:400).json({error:a})}});x.post("/api/tracks/:id/spin-up-view",async(t,e)=>{try{e.json(await Jf(t.params.id,t.body||{}))}catch(n){let r=n?.message||String(n);e.status(/already being spun up/i.test(r)?409:/not found/i.test(r)?404:400).json({error:r})}});x.get("/api/tracks/:id/handoff-lead",(t,e)=>{e.json(Ov(No(t.params.id))??{running:!1})});function Ov(t){return t?{running:!t.finishedAt,step:t.step,error:t.error,fromBox:t.fromBox,toBox:t.toBox,toAgent:t.toAgent,skipPermissions:t.skipPermissions,startedAt:t.startedAt,finishedAt:t.finishedAt}:null}x.get("/api/debug/handoff",async(t,e)=>{let n=Math.min(Number(t.query.limit)||80,500);e.json({verbose:ti(),paths:fh,trace:await dh({limit:n})})});var gm=ut.resolve(Av,"..","..","client","dist");Ft.existsSync(gm)&&(x.use(ve.static(gm)),x.get(/^(?!\/api\/).*/,(t,e)=>e.sendFile(ut.join(gm,"index.html"))));var Cv=S1.createServer(x),$1=new T1({noServer:!0}),Mv=(t,e,n)=>{if(!(Ia(t)||zo.allowed(zo.clientIp(t))||bm.allows(t))){e.write(`HTTP/1.1 403 Forbidden\r
516
+ `),25e3);t.on("close",()=>{clearInterval(a),s()})});S.get("/api/tracks/:id/search",async(t,e)=>{let n=await Y(t.params.id);if(!n)return e.status(404).json({error:"track not found"});let r=String(t.query.q||"").trim();if(!r)return e.status(400).json({error:"q (query) is required"});let o=Math.min(Math.max(Number(t.query.k)||8,1),50),s=Rs(await F(n)),a=$i(s,r,{k:o,role:t.query.role||null,tag:t.query.tag||null});e.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(t,e)=>{e.json({stores:await bh()})});S.delete("/api/memory/:key/:file",async(t,e)=>{let n=String(t.params.key||"");if(!/^[a-z0-9][a-z0-9._-]*$/.test(n))return e.status(400).json({error:"bad store key"});try{e.json({ok:!0,...await kh(n,String(t.params.file||""))})}catch(r){let o=r?.message||String(r);e.status(/not found/i.test(o)?404:/bad fact/i.test(o)?400:500).json({error:o})}});var dj=["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(`
517
+ `);S.post("/api/tracks/:id/memory/consolidate",async(t,e)=>{try{e.json({ok:!0,...await me(t.params.id,dj)})}catch(n){let r=n?.message||String(n);e.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(t,e)=>{try{e.json({ok:!0,track:await Hc(t.params.id)})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/mid-turn|terminal|archived/i.test(r)?409:500;e.status(o).json({error:r})}});S.post("/api/tracks/:id/say",async(t,e)=>{let{text:n,attachments:r}=t.body||{};try{e.json(await me(t.params.id,n,{attachments:r}))}catch(o){let s=o?.message||String(o);if(o?.usageCap)return e.status(429).json({error:"usage_cap",message:s,cap:o.usageCap});e.status(/not found/i.test(s)?404:/archived/i.test(s)?409:/required|not running/i.test(s)?400:500).json({error:s})}});S.post("/api/tracks/:id/upload",async(t,e)=>{try{let n=await Y(t.params.id);if(!n)return e.status(404).json({error:`track "${t.params.id}" not found`});if(n.archivedAt)return e.status(409).json({error:"track is archived"});if(!n.cwd)return e.status(409).json({error:"track has no workspace yet"});let r=Buffer.isBuffer(t.body)?t.body:null,o=await M0(n.cwd,{filename:t.query.filename,buffer:r});e.json({ok:!0,attachment:o})}catch(n){let r=n?.message||String(n);e.status(/too large|unsupported|empty|required/i.test(r)?400:500).json({error:r})}});S.get("/api/tracks/:id/uploads/:file",async(t,e)=>{try{let n=await Y(t.params.id);if(!n)return e.status(404).json({error:`track "${t.params.id}" not found`});if(!n.cwd)return e.status(404).json({error:"track has no workspace"});let r=ut.basename(String(t.params.file||""));if(!r||!Uf(ut.extname(r).slice(1)))return e.status(400).json({error:"not an upload path"});e.set("cache-control","private, max-age=31536000, immutable"),e.set("content-security-policy","sandbox");let o=Ff(n.cwd),s,a;try{s=await Ut.promises.realpath(o),a=await Ut.promises.realpath(ut.join(o,r))}catch{return e.status(404).json({error:"upload not found"})}if(!a.startsWith(s+ut.sep))return e.status(404).json({error:"upload not found"});e.sendFile(r,{root:o},i=>{i&&!e.headersSent&&e.status(404).json({error:"upload not found"})})}catch(n){e.status(500).json({error:n?.message||String(n)})}});var fj=/^[0-9a-fA-F-]{8,64}$/;S.get("/api/tracks/:id/chat-images/:box/:uuid/:idx",async(t,e)=>{try{let n=await Y(t.params.id);if(!n)return e.status(404).json({error:`track "${t.params.id}" not found`});let{box:r,uuid:o}=t.params,s=Number(t.params.idx);if(!fj.test(o)||!Number.isInteger(s)||s<0)return e.status(400).json({error:"bad image ref"});let a=(n.boxes||[]).find(d=>d.name===r);if(!a||a.agent!=="claude"||!a.cwd||!a.sessionId)return e.status(404).json({error:"image source not available"});let i=Ge(a.cwd,a.sessionId);if(!i)return e.status(404).json({error:"transcript not found"});let c=`"${o}"`,l=null,u=rj.createInterface({input:Ut.createReadStream(i,{encoding:"utf8"}),crlfDelay:1/0});for await(let d of u){if(!d.includes(c))continue;let p;try{p=JSON.parse(d)}catch{continue}if(p.uuid===o){l=p,u.close();break}}let f=l?iu(l)[s]:null;if(!f||!/^image\//.test(f.mediaType))return e.status(404).json({error:"image not found"});e.set("content-type",f.mediaType),e.set("cache-control","private, max-age=31536000, immutable"),e.set("content-security-policy","sandbox"),e.send(Buffer.from(f.data,"base64"))}catch(n){e.status(500).json({error:n?.message||String(n)})}});S.post("/api/tracks/:id/interrupt",async(t,e)=>{try{e.json(await jc(t.params.id))}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:/archived/i.test(r)?409:500).json({error:r})}});S.delete("/api/tracks/:id/queue",async(t,e)=>{try{let{removed:n,restored:r,draftRev:o}=await fp(t.params.id);e.json({ok:!0,removed:n.filter(s=>s.kind!=="ship-notify"),restored:r,draftRev:o})}catch(n){e.status(500).json({error:n?.message||String(n)})}});S.post("/api/tracks/:id/answer-prompt",async(t,e)=>{let{promptId:n,answers:r,text:o}=t.body||{};try{e.json(await Bc(t.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;e.status(i).json({error:a})}});S.post("/api/setup/:provider/start",async(t,e)=>{try{let n=await xp({provider:t.params.provider,fresh:t.body?.fresh===!0});e.json({ok:!0,track:n})}catch(n){let r=n?.message||String(n);e.status(/unknown setup provider|isn't available/i.test(r)?400:500).json({error:r})}});S.post("/api/tracks/:id/navigate-prompt",async(t,e)=>{let{promptId:n,questionIndex:r}=t.body||{};try{e.json(await up(t.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;e.status(a).json({error:s})}});S.put("/api/tracks/:id/draft",async(t,e)=>{let{text:n,rev:r}=t.body||{};try{e.json(await wp(t.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;e.status(a).json({error:s})}});S.get("/api/tracks/:id/usage",async(t,e)=>{let n=await Y(t.params.id);if(!n)return e.status(404).json({error:"track not found"});let r=n.boxes?.find(s=>s.name===n.leadBox)||null,o=t.query.fresh==="1"||t.query.fresh==="true";e.json(await ml(r,{fresh:o}))});S.post("/api/tracks/:id/model",async(t,e)=>{let{model:n}=t.body||{};try{e.json(await gp(t.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;e.status(s).json({error:o})}});S.post("/api/tracks/:id/subtask",async(t,e)=>{let{agent:n,task:r,skipPermissions:o,reason:s}=t.body||{};try{let a=await Pp(t.params.id,{agent:n,task:r,skipPermissions:o!==!1,reason:s});e.json({ok:!0,subtask:Ja(a)})}catch(a){let i=a?.message||String(a);if(a?.usageCap)return e.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;e.status(c).json({error:i})}});S.get("/api/tracks/:id/subtasks",(t,e)=>{e.json({subtasks:jr(t.params.id).map(Ja)})});S.get("/api/tracks/:id/subtask/:sid/messages",async(t,e)=>{let n=await lp(t.params.id,t.params.sid);if(!n)return e.status(404).json({error:"subtask not found"});e.json(n)});S.post("/api/tracks/:id/subtask/:sid/cancel",(t,e)=>{try{e.json({ok:!0,subtask:Ja(Vc(t.params.sid))})}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:409).json({error:r})}});S.post("/api/tracks/:id/subtask/:sid/merge-now",(t,e)=>{try{e.json({ok:!0,subtask:Ja(Dp(t.params.sid))})}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:409).json({error:r})}});function Ja(t){return t?{id:t.id,agent:t.agent,task:t.task,skipPermissions:t.skipPermissions,step:t.step,running:!t.finishedAt,box:t.box,branch:t.branch,stat:t.stat,files:t.files||null,conflicts:t.conflicts||[],applied:t.applied,error:t.error,canceled:t.canceled,startedAt:t.startedAt,finishedAt:t.finishedAt}:null}S.post("/api/tracks/:id/handoff-lead",async(t,e)=>{let{toAgent:n,skipPermissions:r,reason:o}=t.body||{};try{let s=await qc(t.params.id,n,r!==!1,o);e.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 e.status(429).json({error:"usage_cap",message:a,cap:s.usageCap});e.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(t,e)=>{try{e.json(await mp(t.params.id,t.body||{}))}catch(n){let r=n?.message||String(n);e.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",(t,e)=>{e.json(aT(Go(t.params.id))??{running:!1})});S.post("/api/tracks/:id/transfer-out",async(t,e)=>{try{let n=await $p(t.params.id);e.json({ok:!0,step:n.step,startedAt:n.startedAt})}catch(n){let r=n?.message||String(n);e.status(/already running/i.test(r)?409:/not found/i.test(r)?404:400).json({error:r})}});S.get("/api/tracks/:id/transfer-out",(t,e)=>{let n=Rp(t.params.id);if(!n)return e.json({running:!1});e.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(t,e)=>{try{e.json(await Kc(t.params.id,t.body||{}))}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:400).json({error:r})}});S.post("/api/tracks/adopt",async(t,e)=>{let{trackId:n}=t.body||{};try{e.json(await Cp({...t.body||{},trackId:n}))}catch(r){let o=r?.message||String(r);e.status(/already running|already hosted/i.test(o)?409:/not found/i.test(o)?404:400).json({error:o})}});function aT(t){return t?{running:!t.finishedAt,step:t.step,error:t.error,fromBox:t.fromBox,toBox:t.toBox,toAgent:t.toAgent,skipPermissions:t.skipPermissions,startedAt:t.startedAt,finishedAt:t.finishedAt}:null}S.get("/api/debug/handoff",async(t,e)=>{let n=Math.min(Number(t.query.limit)||80,500);e.json({verbose:mi(),paths:Dh,trace:await Ph({limit:n})})});var Hm=ut.resolve(tT,"..","..","client","dist");Ut.existsSync(Hm)&&(S.use(he.static(Hm)),S.get(/^(?!\/api\/).*/,(t,e)=>e.sendFile(ut.join(Hm,"index.html"))));var iT=sj.createServer(S),pj=new ij({noServer:!0}),cT=(t,e,n)=>{if(!(La(t)||ss.allowed(ss.clientIp(t))||qm.allows(t))){e.write(`HTTP/1.1 403 Forbidden\r
491
518
  \r
492
- `),e.destroy();return}if(ES(t,e,n))return;if(!TS(t,_v,{enforce:Iv})){e.write(`HTTP/1.1 401 Unauthorized\r
519
+ `),e.destroy();return}if(JS(t,e,n))return;if(!VS(t,nT,{enforce:rT})){e.write(`HTTP/1.1 401 Unauthorized\r
493
520
  \r
494
- `),e.destroy();return}let r=Ah(t.url);if(!r.ok){e.write(`HTTP/1.1 ${r.status} ${r.status===400?"Bad Request":"Not Found"}\r
521
+ `),e.destroy();return}let r=Jh(t.url);if(!r.ok){e.write(`HTTP/1.1 ${r.status} ${r.status===400?"Bad Request":"Not Found"}\r
495
522
  \r
496
- `),e.destroy();return}let o=r.sessionName;if(!bt(o)){e.write(`HTTP/1.1 400 Bad Request\r
523
+ `),e.destroy();return}let o=r.sessionName;if(!At(o)){e.write(`HTTP/1.1 400 Bad Request\r
497
524
  \r
498
- `),e.destroy();return}let{cols:s,rows:a}=r;$1.handleUpgrade(t,e,n,i=>Sh(i,o,{cols:s,rows:a}))};Cv.on("upgrade",Mv);var Pv=process.env.BOSTRAT_CERT_DIR||ut.join(process.env.HOME||ym.tmpdir(),".bostrat","certs"),Sv=Number(process.env.BOSTRAT_TLS_PORT)||3443,vv=ut.join(Pv,"bostrat.globopi.key"),Tv=ut.join(Pv,"bostrat.globopi.crt");if(Ft.existsSync(vv)&&Ft.existsSync(Tv)){let t=v1.createServer({key:Ft.readFileSync(vv),cert:Ft.readFileSync(Tv)},x);t.on("upgrade",Mv),t.on("error",e=>{console.error(`[bostrat-agent] https listener failed (${e?.code||e?.message}) \u2014 continuing HTTP-only`)}),t.listen(Sv,pl,()=>{console.log(`[bostrat-agent] https listening on ${pl||"0.0.0.0"}:${Sv}`)})}Cv.listen(kv,pl,()=>{console.log(`[bostrat-agent] listening on ${pl||"0.0.0.0"}:${kv}`);let t=Fx(process.env);t&&console.warn(`[bostrat-agent] \u26A0 SECURITY: plane-linked node bound to ${t.host?t.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: ${te}`),console.log(`[bostrat-agent] auto-trigger default: ${Ev}%`),console.log(`[bostrat-agent] ip allowlist: ${zo.open?"OPEN":process.env.BOSTRAT_ALLOW_IPS||"CLOSED (BOSTRAT_ALLOW_IPS unset)"}`+(bm.active?` \xB7 view front-door: ${process.env.BOSTRAT_VIEW_FRONT_CIDRS} (registered views only)`:"")),ip().then(e=>e&&console.log("[bostrat-agent] reconciled interrupted handoff(s)")).catch(e=>console.error("[bostrat-agent] handoff reconcile failed:",e?.message||e)),cp().then(e=>e&&console.log("[bostrat-agent] reconciled interrupted subtask(s)")).catch(e=>console.error("[bostrat-agent] subtask reconcile failed:",e?.message||e)),op().then(e=>e&&console.log(`[bostrat-agent] reaped ${e} orphaned box(es) on archived track(s)`)).catch(e=>console.error("[bostrat-agent] archived-orphan sweep failed:",e?.message||e)),tp().then(e=>console.log(`[bostrat-agent] standing instructions refreshed (${e.refreshed} updated, ${e.removed} legacy CLAUDE.md removed${e.codexGlobal?`, codex global ${e.codexGlobal}`:""})`)).catch(e=>console.error("[bostrat-agent] standing-instructions refresh failed:",e?.message||e)),P1(),M1(),wy({listTracks:et,getTrack:z}).then(e=>console.log(`[bostrat-agent] spend caps ${e.configured?"armed":"unconfigured (fail-open)"} \u2014 seeded ${Object.keys(e.spent).length} provider counter(s)`)).catch(e=>console.error("[bostrat-agent] spend-caps seed failed (staying fail-open):",e?.message||e)),cS()&&lS({listTracks:et}),HS(),KS(),Ix({resolveTrack:z}),jx({listTracks:et,createTrack:_c,archiveTrack:Rr,listRepos:Ue,resolveTrack:z,sayToLead:fe,answerPrompt:Tc,startLeadHandoff:Oc,interruptLead:Ac,listSubtaskJobs:$r,cancelSubtask:Mc,readEvents:L,appendEvent:I,divertShip:am,answerPrExists:im,knownAgents:ua}),O1(),ds().then(e=>{e||console.warn(`[boot] no host tmux server on ${te} and auto-start failed \u2014 boxes cannot spawn until one runs`)}),sv(),process.env.BOSTRAT_PLANE_URL&&process.env.BOSTRAT_PLANE_TOKEN&&(hl=Wx({url:process.env.BOSTRAT_PLANE_URL,token:process.env.BOSTRAT_PLANE_TOKEN,nodeId:process.env.BOSTRAT_NODE_ID||ym.hostname(),name:process.env.BOSTRAT_NODE_NAME||ym.hostname(),listTracks:et,detectAgents:xc,sampleMetrics:Kx}),console.log(`[bostrat-agent] plane link \u2192 ${process.env.BOSTRAT_PLANE_URL}`),Fr().catch(()=>{}),u0().then(e=>e.pushed&&console.log(`[content-plane] seeded ${e.pushed} runbooks to the plane`),()=>{}),Rx().then(e=>e.pushed&&console.log(`[content-plane] seeded ${e.pushed} ticket links to the plane`),()=>{}),Pk().then(e=>e.pushed&&console.log(`[content-plane] seeded ${e.pushed} mocks to the plane`),()=>{}),Xk().then(e=>e.pushed&&console.log(`[content-plane] seeded ${e.pushed} flows to the plane`),()=>{}),lb().then(e=>e.pushed&&console.log(`[content-plane] seeded ${e.pushed} PR links to the plane`),()=>{}))});process.on("SIGTERM",()=>{try{hl?.stop()}catch{}setTimeout(()=>process.exit(0),150)});function O1(){C1(),oc().catch(()=>{}),setInterval(()=>oc().catch(()=>{}),1e4)}function C1(){for(let t of["bostrat-view","bostrat-mock","bostrat-flow","bostrat-ticket","bostrat-circuit","bostrat-blueprint","bostrat-runbook","bostrat-loop","bostrat-notify","bostrat-gmail","bostrat-changelog","gh"])try{let e=ut.resolve(Av,"..","bin",t),n=ut.join(process.env.HOME||"",".local","bin");if(!process.env.HOME||!Ft.existsSync(e))continue;Ft.mkdirSync(n,{recursive:!0});let r=ut.join(n,t);(Ft.existsSync(r)?Ft.readlinkSync(r):null)!==e&&(Ft.rmSync(r,{force:!0}),Ft.symlinkSync(e,r)),console.log(`[bostrat-agent] ${t} CLI linked at ${r}`)}catch(e){console.error(`[bostrat-agent] ${t} CLI link failed:`,e?.message||e)}}function M1(){let t=!1,e=async()=>{if(!t){t=!0;try{let n=await et(),r=await sS({tracks:n});r.committed&&console.log(`[state-sync] committed (${r.staged} file(s) staged${r.pushed?", pushed":""})`)}catch{}finally{t=!1}}};setInterval(e,6e4),e()}function P1(){let t=!1;setInterval(async()=>{if(!t){t=!0;try{let e=await et();for(let n of e)n.archivedAt||!n.boxes?.some(r=>r.state==="live")||(await vc(n.id).catch(()=>{}),await mk(n).catch(()=>{}))}catch{}finally{t=!1}}},4e3)}
525
+ `),e.destroy();return}let{cols:s,rows:a}=r;pj.handleUpgrade(t,e,n,i=>Gh(i,o,{cols:s,rows:a}))};iT.on("upgrade",cT);var lT=process.env.BOSTRAT_CERT_DIR||ut.join(process.env.HOME||Wm.tmpdir(),".bostrat","certs"),Xv=Number(process.env.BOSTRAT_TLS_PORT)||3443,Zv=ut.join(lT,"bostrat.globopi.key"),Qv=ut.join(lT,"bostrat.globopi.crt");if(Ut.existsSync(Zv)&&Ut.existsSync(Qv)){let t=aj.createServer({key:Ut.readFileSync(Zv),cert:Ut.readFileSync(Qv)},S);t.on("upgrade",cT),t.on("error",e=>{console.error(`[bostrat-agent] https listener failed (${e?.code||e?.message}) \u2014 continuing HTTP-only`)}),t.listen(Xv,El,()=>{console.log(`[bostrat-agent] https listening on ${El||"0.0.0.0"}:${Xv}`)})}iT.listen(Jv,El,()=>{console.log(`[bostrat-agent] listening on ${El||"0.0.0.0"}:${Jv}`);let t=pS(process.env);t&&console.warn(`[bostrat-agent] \u26A0 SECURITY: plane-linked node bound to ${t.host?t.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: ${ne}`),console.log(`[bostrat-agent] auto-trigger default: ${eT}%`),console.log(`[bostrat-agent] ip allowlist: ${ss.open?"OPEN":process.env.BOSTRAT_ALLOW_IPS||"CLOSED (BOSTRAT_ALLOW_IPS unset)"}`+(qm.active?` \xB7 view front-door: ${process.env.BOSTRAT_VIEW_FRONT_CIDRS} (registered views only)`:"")),Ip().then(e=>e&&console.log("[bostrat-agent] reconciled interrupted handoff(s)")).catch(e=>console.error("[bostrat-agent] handoff reconcile failed:",e?.message||e)),Mp().then(e=>e&&console.log("[bostrat-agent] reconciled interrupted subtask(s)")).catch(e=>console.error("[bostrat-agent] subtask reconcile failed:",e?.message||e)),Ap().then(e=>e&&console.log(`[bostrat-agent] reaped ${e} orphaned box(es) on archived track(s)`)).catch(e=>console.error("[bostrat-agent] archived-orphan sweep failed:",e?.message||e)),kp().then(e=>console.log(`[bostrat-agent] standing instructions refreshed (${e.refreshed} updated, ${e.removed} legacy CLAUDE.md removed${e.codexGlobal?`, codex global ${e.codexGlobal}`:""})`)).catch(e=>console.error("[bostrat-agent] standing-instructions refresh failed:",e?.message||e)),gj(),wj(),Dy({listTracks:nt,getTrack:Y}).then(e=>console.log(`[bostrat-agent] spend caps ${e.configured?"armed":"unconfigured (fail-open)"} \u2014 seeded ${Object.keys(e.spent).length} provider counter(s)`)).catch(e=>console.error("[bostrat-agent] spend-caps seed failed (staying fail-open):",e?.message||e)),j0()&&L0({listTracks:nt}),gv(),kv(),eS({resolveTrack:Y}),dS({listTracks:nt,createTrack:Lc,archiveTrack:Br,listRepos:We,resolveTrack:Y,sayToLead:me,answerPrompt:Bc,startLeadHandoff:qc,interruptLead:jc,listSubtaskJobs:jr,cancelSubtask:Vc,readEvents:F,appendEvent:I,divertShip:Om,answerPrExists:Cm,knownAgents:ka}),mj(),ks().then(e=>{e||console.warn(`[boot] no host tmux server on ${ne} and auto-start failed \u2014 boxes cannot spawn until one runs`)}),Nv(),process.env.BOSTRAT_PLANE_URL&&process.env.BOSTRAT_PLANE_TOKEN&&(Il=wS({url:process.env.BOSTRAT_PLANE_URL,token:process.env.BOSTRAT_PLANE_TOKEN,nodeId:process.env.BOSTRAT_NODE_ID||Wm.hostname(),name:process.env.BOSTRAT_NODE_NAME||Wm.hostname(),listTracks:nt,detectAgents:Pc,sampleMetrics:yS,onTracksTransferred:Op}),console.log(`[bostrat-agent] plane link \u2192 ${process.env.BOSTRAT_PLANE_URL}`),Jr().catch(()=>{}),$0().then(e=>e.pushed&&console.log(`[content-plane] seeded ${e.pushed} runbooks to the plane`),()=>{}),nS().then(e=>e.pushed&&console.log(`[content-plane] seeded ${e.pushed} ticket links to the plane`),()=>{}),t0().then(e=>e.pushed&&console.log(`[content-plane] seeded ${e.pushed} mocks to the plane`),()=>{}),g0().then(e=>e.pushed&&console.log(`[content-plane] seeded ${e.pushed} flows to the plane`),()=>{}),Rb().then(e=>e.pushed&&console.log(`[content-plane] seeded ${e.pushed} PR links to the plane`),()=>{}))});process.on("SIGTERM",()=>{try{Il?.stop()}catch{}setTimeout(()=>process.exit(0),150)});function mj(){hj(),gc().catch(()=>{}),setInterval(()=>gc().catch(()=>{}),1e4)}function hj(){for(let t of["bostrat-view","bostrat-mock","bostrat-flow","bostrat-ticket","bostrat-circuit","bostrat-blueprint","bostrat-runbook","bostrat-loop","bostrat-notify","bostrat-gmail","bostrat-changelog","gh"])try{let e=ut.resolve(tT,"..","bin",t),n=ut.join(process.env.HOME||"",".local","bin");if(!process.env.HOME||!Ut.existsSync(e))continue;Ut.mkdirSync(n,{recursive:!0});let r=ut.join(n,t);(Ut.existsSync(r)?Ut.readlinkSync(r):null)!==e&&(Ut.rmSync(r,{force:!0}),Ut.symlinkSync(e,r)),console.log(`[bostrat-agent] ${t} CLI linked at ${r}`)}catch(e){console.error(`[bostrat-agent] ${t} CLI link failed:`,e?.message||e)}}function wj(){let t=!1,e=async()=>{if(!t){t=!0;try{let n=await nt(),r=await CS({tracks:n});r.committed&&console.log(`[state-sync] committed (${r.staged} file(s) staged${r.pushed?", pushed":""})`)}catch{}finally{t=!1}}};setInterval(e,6e4),e()}function gj(){let t=!1;setInterval(async()=>{if(!t){t=!0;try{let e=await nt();for(let n of e)n.archivedAt||n.transferredTo||!n.boxes?.some(r=>r.state==="live")||(await Dc(n.id).catch(()=>{}),await Nk(n).catch(()=>{}))}catch{}finally{t=!1}}},4e3)}