bostrat-node 1.7.2 → 1.7.3

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 hT=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 Ol=(t,e)=>{for(var n in e)hT(t,n,{get:e[n],enumerable:!0})};import{createHash as wT,randomBytes as gT,timingSafeEqual as yT}from"node:crypto";function Vm(){return gT(32).toString("hex")}function is(t){let e=typeof t=="string"?t.trim():"";return e?wT("sha256").update(e).digest("hex"):null}function zm(t,e){return typeof t!="string"||typeof e!="string"||t.length!==e.length||!t?!1:yT(Buffer.from(t),Buffer.from(e))}function cs(t,e={},{now:n=Date.now(),log:r=console.warn}={}){if(Cl.set(t,(Cl.get(t)||0)+1),Ml.has(t)&&n-Ml.get(t)<bT)return!1;Ml.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=${Cl.get(t)}${o?` ${o}`:""}`),!0}async function Jm(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 Xa,Za,Cl,Ml,bT,ls=M(()=>{Xa="BOSTRAT_HOOK_TOKEN",Za="x-bostrat-hook";Cl=new Map,Ml=new Map,bT=6e4});import ee from"node:fs/promises";import Ym from"node:os";import Jt from"node:path";import{execFile as kT}from"node:child_process";import{promisify as xT}from"node:util";function Qa(){return/^(1|true|yes|on)$/i.test(process.env.BOSTRAT_CLAUDE_USE_API_KEY||"")&&process.env.ANTHROPIC_API_KEY?.trim()||null}function ST(){return process.env.CLAUDE_CONFIG_DIR?Jt.join(process.env.CLAUDE_CONFIG_DIR,".claude.json"):Jt.join(Ym.homedir(),".claude.json")}function vT(){return process.env.CLAUDE_CONFIG_DIR?Jt.join(process.env.CLAUDE_CONFIG_DIR,"settings.json"):Jt.join(Ym.homedir(),".claude","settings.json")}async function gn(t){if(!t||typeof t!="string")return;let e=Jt.resolve(t),n=ST(),r=vT(),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(Jt.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 "${Za}: $${Xa}" --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 ee.mkdir(Jt.dirname(r),{recursive:!0}),await ee.writeFile(r,JSON.stringify(i,null,2)),await TT(e)}async function TT(t){try{let e=Jt.resolve(t),n=Jt.join(e,".bostrat","memory","claude"),r=Jt.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(Jt.join(".bostrat","memory"));if(s&&!a||s===n)return;o.autoMemoryDirectory=n,await ee.mkdir(n,{recursive:!0}),await ee.mkdir(Jt.dirname(r),{recursive:!0}),await ee.writeFile(r,JSON.stringify(o,null,2)),await AT(e,["/.claude/settings.local.json"])}catch{}}async function AT(t,e){try{let{stdout:n}=await xT(kT)("git",["-C",t,"rev-parse","--git-path","info/exclude"]),r=Jt.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(Jt.dirname(r),{recursive:!0}),await ee.appendFile(r,(o&&!o.endsWith(`
1
+ var BT=Object.defineProperty;var C=(t,e,n)=>()=>{if(n)throw n[0];try{return t&&(e=t(t=0)),e}catch(r){throw n=[r],r}};var Ul=(t,e)=>{for(var n in e)BT(t,n,{get:e[n],enumerable:!0})};import{createHash as DT,randomBytes as jT,timingSafeEqual as LT}from"node:crypto";function sh(){return jT(32).toString("hex")}function ws(t){let e=typeof t=="string"?t.trim():"";return e?DT("sha256").update(e).digest("hex"):null}function ah(t,e){return typeof t!="string"||typeof e!="string"||t.length!==e.length||!t?!1:LT(Buffer.from(t),Buffer.from(e))}function gs(t,e={},{now:n=Date.now(),log:r=console.warn}={}){if(Hl.set(t,(Hl.get(t)||0)+1),Wl.has(t)&&n-Wl.get(t)<FT)return!1;Wl.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=${Hl.get(t)}${o?` ${o}`:""}`),!0}async function ih(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 oi,si,Hl,Wl,FT,ys=C(()=>{oi="BOSTRAT_HOOK_TOKEN",si="x-bostrat-hook";Hl=new Map,Wl=new Map,FT=6e4});import ne from"node:fs/promises";import ch from"node:os";import Yt from"node:path";import{execFile as UT}from"node:child_process";import{promisify as HT}from"node:util";function ai(){return/^(1|true|yes|on)$/i.test(process.env.BOSTRAT_CLAUDE_USE_API_KEY||"")&&process.env.ANTHROPIC_API_KEY?.trim()||null}function WT(){return process.env.CLAUDE_CONFIG_DIR?Yt.join(process.env.CLAUDE_CONFIG_DIR,".claude.json"):Yt.join(ch.homedir(),".claude.json")}function qT(){return process.env.CLAUDE_CONFIG_DIR?Yt.join(process.env.CLAUDE_CONFIG_DIR,"settings.json"):Yt.join(ch.homedir(),".claude","settings.json")}async function kn(t){if(!t||typeof t!="string")return;let e=Yt.resolve(t),n=WT(),r=qT(),o={};try{o=JSON.parse(await ne.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 ne.mkdir(Yt.dirname(n),{recursive:!0}),await ne.writeFile(n,JSON.stringify(o,null,2));let i={};try{i=JSON.parse(await ne.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 "${si}: $${oi}" --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 ne.mkdir(Yt.dirname(r),{recursive:!0}),await ne.writeFile(r,JSON.stringify(i,null,2)),await KT(e)}async function KT(t){try{let e=Yt.resolve(t),n=Yt.join(e,".bostrat","memory","claude"),r=Yt.join(e,".claude","settings.local.json"),o={};try{o=JSON.parse(await ne.readFile(r,"utf8"))}catch{}let s=o.autoMemoryDirectory,a=typeof s=="string"&&s.includes(Yt.join(".bostrat","memory"));if(s&&!a||s===n)return;o.autoMemoryDirectory=n,await ne.mkdir(n,{recursive:!0}),await ne.mkdir(Yt.dirname(r),{recursive:!0}),await ne.writeFile(r,JSON.stringify(o,null,2)),await GT(e,["/.claude/settings.local.json"])}catch{}}async function GT(t,e){try{let{stdout:n}=await HT(UT)("git",["-C",t,"rev-parse","--git-path","info/exclude"]),r=Yt.resolve(t,n.trim()),o=await ne.readFile(r,"utf8").catch(()=>""),s=e.filter(a=>!o.split(`
2
+ `).includes(a));if(!s.length)return;await ne.mkdir(Yt.dirname(r),{recursive:!0}),await ne.appendFile(r,(o&&!o.endsWith(`
3
3
  `)?`
4
4
  `:"")+s.join(`
5
5
  `)+`
6
- `)}catch{}}var us=M(()=>{ls()});import Nl from"node:fs/promises";import ET from"node:os";import ti from"node:path";function _T(){let t=process.env.CODEX_HOME||ti.join(ET.homedir(),".codex");return ti.join(t,"config.toml")}function Xm(t){return`[projects."${t}"]`}function IT(t,e){let n=Xm(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 Kr(t){if(!t||typeof t!="string")return;let e=ti.resolve(t),n=_T(),r="";try{r=await Nl.readFile(n,"utf8")}catch{}if(IT(r,e))return;let o=Xm(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 bs=C(()=>{ys()});import ql from"node:fs/promises";import VT from"node:os";import ii from"node:path";function zT(){let t=process.env.CODEX_HOME||ii.join(VT.homedir(),".codex");return ii.join(t,"config.toml")}function lh(t){return`[projects."${t}"]`}function JT(t,e){let n=lh(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 Yr(t){if(!t||typeof t!="string")return;let e=ii.resolve(t),n=zT(),r="";try{r=await ql.readFile(n,"utf8")}catch{}if(JT(r,e))return;let o=lh(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*$/,"")}
7
7
  trust_level = "trusted"
8
8
  `;r=r.slice(0,a)+d+r.slice(l)}else{let s=`
9
9
  ${o}
10
10
  trust_level = "trusted"
11
11
  `;r=r.trimEnd()+s+(r.length&&!r.endsWith(`
12
12
  `)?`
13
- `:"")}try{await Nl.mkdir(ti.dirname(n),{recursive:!0}),await Nl.writeFile(n,r)}catch(s){console.warn(`[codex-config] could not seed folder trust for ${e}: ${s?.message||s}`)}}var ei=M(()=>{});import Zm from"node:fs/promises";import RT from"node:os";import ds from"node:path";function $T(t){let n=ds.resolve(t).slice(1).replace(/\//g,"-").replace(/\./g,""),r=process.env.CURSOR_CONFIG_DIR||ds.join(RT.homedir(),".cursor");return ds.join(r,"projects",n)}async function Gr(t){if(!t||typeof t!="string")return;let e=ds.resolve(t),n=$T(e),r=ds.join(n,".workspace-trusted");await Zm.mkdir(n,{recursive:!0}),await Zm.writeFile(r,`${JSON.stringify({trustedAt:new Date().toISOString(),workspacePath:e},null,2)}
14
- `,"utf8")}var ni=M(()=>{});import Bl from"node:fs/promises";import yn from"node:path";import{execFile as OT}from"node:child_process";import{promisify as CT}from"node:util";async function jT(t){try{return(await Bl.stat(yn.join(t,".git"))).isDirectory()?"repo":"worktree"}catch{return null}}async function LT(t){let e=i=>Bl.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 jT(o);if(a==="worktree")return;if(a==="repo"){t.set(o,{path:o,name:yn.basename(o),branch:await LT(o)});return}if(s>=BT)return;let i;try{i=await Bl.readdir(o,{withFileTypes:!0})}catch{return}for(let c of i)!c.isDirectory()||c.name.startsWith(".")||DT.has(c.name)||await e(yn.join(o,c.name),s+1)}for(let o of PT)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 FT(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(Pl.has(t))return Pl.get(t);let e=null;try{let{stdout:n}=await MT("git",["-C",t,"config","--get","remote.origin.url"],{timeout:5e3});e=FT(n)}catch{e=null}return Pl.set(t,e),e}async function Vr(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 MT,Qm,NT,PT,BT,DT,Pl,ar=M(()=>{MT=CT(OT),Qm=process.env.HOME||"/home/globo",NT=yn.join(process.env.BOSTRAT_STATE_DIR||yn.join(Qm,".bostrat"),"repos"),PT=[...(process.env.BOSTRAT_REPOS_ROOT||yn.join(Qm,"Documents")).split(","),NT].map(t=>t.trim()).filter(Boolean),BT=Number(process.env.BOSTRAT_REPOS_DEPTH)||3,DT=new Set(["node_modules",".git",".cache","dist","build",".next","vendor","__pycache__","venv",".venv","target"]);Pl=new Map});import UT from"node:fs";import th from"node:fs/promises";import fs from"node:path";import HT from"node:os";import{fileURLToPath as WT}from"node:url";import{execFile as qT}from"node:child_process";import{promisify as KT}from"node:util";function gt(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 ri(t=process.env){return!!(gt(t)&&t.BOSTRAT_PLANE_TOKEN)}async function oi(t,{env:e=process.env}={}){let n=String(t||"").toLowerCase();if(!nh.test(n))throw zr("repo must be owner/name",400);let r=Dl.get(n);if(r&&r.expiresAt-Date.now()>zT)return r;if(!ri(e))throw zr("node is not plane-linked \u2014 GitHub auth unavailable",503);let o;try{o=await rh(`${gt(e)}/v1/github/token?repo=${encodeURIComponent(t)}`,{headers:oh(e)})}catch(i){if(r&&r.expiresAt>Date.now())return r;throw zr(`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 zr(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 ps({env:t=process.env,force:e=!1}={}){if(!ri(t))return{configured:!1,repos:[],username:null};if(!e&&ir&&Date.now()-ir.at<JT)return ir.data;try{let n=await rh(`${gt(t)}/v1/github/repos`,{headers:oh(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 sh(){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 oi(r,{env:n});return o?{GH_TOKEN:o}:{}}catch{return{}}}async function jl({env:t=process.env}={}){return(await ps({env:t})).username??null}function QT(t){let[e,n]=String(t).split("/");return fs.join(VT,e,n)}async function Ll(t,{env:e=process.env}={}){let n=(...r)=>eh("git",["-C",t,...r],{timeout:1e4});await n("config","--replace-all","credential.helper",""),await n("config","--add","credential.helper",`!"${XT()}" ${ZT(e)}`),await n("config","credential.useHttpPath","true")}async function si(t,{env:e=process.env,baseUrl:n="https://github.com"}={}){if(!nh.test(String(t||"")))throw zr(`bad repo slug "${t}"`,400);let r=QT(t);if(UT.existsSync(fs.join(r,".git")))return r;let{token:o}=await oi(t,{env:e});await th.mkdir(fs.dirname(r),{recursive:!0});let s="!f() { echo username=x-access-token; echo password=$BOSTRAT_GIT_TOKEN; }; f";try{await eh("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 th.rm(r,{recursive:!0,force:!0}).catch(()=>{}),zr(`clone of ${t} failed: ${a?.stderr?.trim?.()||a?.message||a}`,502)}return await Ll(r,{env:e}),r}var eh,GT,VT,nh,zT,JT,YT,rh,Dl,ir,oh,zr,XT,ZT,Wt=M(()=>{ar();eh=KT(qT),GT=process.env.BOSTRAT_STATE_DIR||fs.join(process.env.HOME||HT.tmpdir(),".bostrat"),VT=fs.join(GT,"repos"),nh=/^[^/\s]+\/[^/\s]+$/,zT=5*6e4,JT=6e4,YT=10*6e4,rh=fetch,Dl=new Map,ir=null;oh=t=>({authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`}),zr=(t,e)=>Object.assign(new Error(t),{status:e});XT=()=>WT(new URL("../bin/bostrat-git-credential",import.meta.url)),ZT=(t=process.env)=>`http://127.0.0.1:${Number(t.PORT)||3362}`});function ah(t=process.env){return!!(gt(t)&&t.BOSTRAT_PLANE_TOKEN)}async function ch(t,e,n){let r=gt(n),o=new AbortController,s=setTimeout(()=>o.abort(),eA);try{return await nA(`${r}${t}`,{...e,signal:o.signal})}finally{clearTimeout(s)}}async function lh(t,{env:e=process.env,force:n=!1}={}){if(!ah(e))return{facts:[],source:"unconfigured"};let r=Fl.get(t);if(!n&&r&&Date.now()-r.at<tA)return{facts:r.facts,source:"cache"};try{let o=await ch(`/v1/memory/${encodeURIComponent(t)}`,{headers:ih(e)},e);if(!o.ok)throw new Error(`plane ${o.status}`);let s=await o.json(),a=Array.isArray(s?.facts)?s.facts:[];return Fl.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 ai(t,e,{env:n=process.env}={}){if(!ah(n))return{pushed:0,source:"unconfigured"};if(!e?.length)return{pushed:0,source:"empty"};try{let r=await ch(`/v1/memory/${encodeURIComponent(t)}`,{method:"POST",headers:{...ih(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 Fl.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 tA,eA,Fl,nA,ih,uh=M(()=>{Wt();tA=6e4,eA=5e3,Fl=new Map,nA=(...t)=>fetch(...t);ih=t=>({authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`})});import q from"node:fs/promises";import rA from"node:os";import tt from"node:path";import{execFile as oA}from"node:child_process";import{promisify as sA}from"node:util";function ii(){return tt.join(Ul,"memory","repos")}function cr(t){return t===qe?tt.join(Ul,"memory",qe):tt.join(ii(),t)}async function ms(t){try{return JSON.parse(await q.readFile(tt.join(t,hh),"utf8"))}catch{return{}}}async function Hl(t,e){let n=await ms(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,hh),JSON.stringify(n))}function fh(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 ph(t){try{let{stdout:e}=await aA("git",["-C",t,"config","--get","remote.origin.url"]);return e.trim()||null}catch{return null}}async function Wl(t){if(!t)return[];let e=fh(await ph(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=fh(await ph(tt.join(t,o.name)));s&&!n.includes(s)&&n.push(s)}return n}function ci(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}=ci(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 wh(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 ql(t,e,n,r=new Map){let o=(t||"").split(`
13
+ `:"")}try{await ql.mkdir(ii.dirname(n),{recursive:!0}),await ql.writeFile(n,r)}catch(s){console.warn(`[codex-config] could not seed folder trust for ${e}: ${s?.message||s}`)}}var ci=C(()=>{});import uh from"node:fs/promises";import YT from"node:os";import ks from"node:path";function XT(t){let n=ks.resolve(t).slice(1).replace(/\//g,"-").replace(/\./g,""),r=process.env.CURSOR_CONFIG_DIR||ks.join(YT.homedir(),".cursor");return ks.join(r,"projects",n)}async function Xr(t){if(!t||typeof t!="string")return;let e=ks.resolve(t),n=XT(e),r=ks.join(n,".workspace-trusted");await uh.mkdir(n,{recursive:!0}),await uh.writeFile(r,`${JSON.stringify({trustedAt:new Date().toISOString(),workspacePath:e},null,2)}
14
+ `,"utf8")}var li=C(()=>{});import Gl from"node:fs/promises";import xn from"node:path";import{execFile as ZT}from"node:child_process";import{promisify as QT}from"node:util";async function sA(t){try{return(await Gl.stat(xn.join(t,".git"))).isDirectory()?"repo":"worktree"}catch{return null}}async function aA(t){let e=i=>Gl.readFile(xn.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 qe(){let t=new Map;async function e(o,s){if(t.has(o))return;let a=await sA(o);if(a==="worktree")return;if(a==="repo"){t.set(o,{path:o,name:xn.basename(o),branch:await aA(o)});return}if(s>=rA)return;let i;try{i=await Gl.readdir(o,{withFileTypes:!0})}catch{return}for(let c of i)!c.isDirectory()||c.name.startsWith(".")||oA.has(c.name)||await e(xn.join(o,c.name),s+1)}for(let o of nA)await e(xn.resolve(o),0);let n=new Set,r=[];for(let o of t.values()){let s=(await ut(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 iA(t){let e=String(t||"").trim().match(/github\.com[:/]+([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i);return e?`${e[1]}/${e[2]}`:null}async function ut(t){if(!t)return null;if(Kl.has(t))return Kl.get(t);let e=null;try{let{stdout:n}=await tA("git",["-C",t,"config","--get","remote.origin.url"],{timeout:5e3});e=iA(n)}catch{e=null}return Kl.set(t,e),e}async function Zr(t){let e=String(t||"").toLowerCase();if(!e)return null;for(let n of await qe())if((await ut(n.path))?.toLowerCase()===e)return n.path;return null}var tA,dh,eA,nA,rA,oA,Kl,cr=C(()=>{tA=QT(ZT),dh=process.env.HOME||"/home/globo",eA=xn.join(process.env.BOSTRAT_STATE_DIR||xn.join(dh,".bostrat"),"repos"),nA=[...(process.env.BOSTRAT_REPOS_ROOT||xn.join(dh,"Documents")).split(","),eA].map(t=>t.trim()).filter(Boolean),rA=Number(process.env.BOSTRAT_REPOS_DEPTH)||3,oA=new Set(["node_modules",".git",".cache","dist","build",".next","vendor","__pycache__","venv",".venv","target"]);Kl=new Map});import cA from"node:fs";import fh from"node:fs/promises";import xs from"node:path";import lA from"node:os";import{fileURLToPath as uA}from"node:url";import{execFile as dA}from"node:child_process";import{promisify as fA}from"node:util";function gt(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 ui(t=process.env){return!!(gt(t)&&t.BOSTRAT_PLANE_TOKEN)}async function di(t,{env:e=process.env}={}){let n=String(t||"").toLowerCase();if(!mh.test(n))throw Qr("repo must be owner/name",400);let r=Vl.get(n);if(r&&r.expiresAt-Date.now()>hA)return r;if(!ui(e))throw Qr("node is not plane-linked \u2014 GitHub auth unavailable",503);let o;try{o=await hh(`${gt(e)}/v1/github/token?repo=${encodeURIComponent(t)}`,{headers:wh(e)})}catch(i){if(r&&r.expiresAt>Date.now())return r;throw Qr(`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 Qr(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 vs({env:t=process.env,force:e=!1}={}){if(!ui(t))return{configured:!1,repos:[],username:null};if(!e&&lr&&Date.now()-lr.at<wA)return lr.data;try{let n=await hh(`${gt(t)}/v1/github/repos`,{headers:wh(t)});if(!n.ok)throw new Error(`plane replied ${n.status}`);let r=await n.json();return lr={at:Date.now(),data:r},r}catch(n){return lr?lr.data:{configured:!0,repos:[],username:null,error:n?.message||String(n)}}}function gh(){Vl.clear(),lr=null}async function Ie({cwd:t=null,slug:e=null,env:n=process.env}={}){try{let r=e||(t?await ut(t):null);if(!r)return{};let{token:o}=await di(r,{env:n});return o?{GH_TOKEN:o}:{}}catch{return{}}}async function zl({env:t=process.env}={}){return(await vs({env:t})).username??null}function kA(t){let[e,n]=String(t).split("/");return xs.join(mA,e,n)}async function Jl(t,{env:e=process.env}={}){let n=(...r)=>ph("git",["-C",t,...r],{timeout:1e4});await n("config","--replace-all","credential.helper",""),await n("config","--add","credential.helper",`!"${yA()}" ${bA(e)}`),await n("config","credential.useHttpPath","true")}async function fi(t,{env:e=process.env,baseUrl:n="https://github.com"}={}){if(!mh.test(String(t||"")))throw Qr(`bad repo slug "${t}"`,400);let r=kA(t);if(cA.existsSync(xs.join(r,".git")))return r;let{token:o}=await di(t,{env:e});await fh.mkdir(xs.dirname(r),{recursive:!0});let s="!f() { echo username=x-access-token; echo password=$BOSTRAT_GIT_TOKEN; }; f";try{await ph("git",["-c","credential.helper=","-c",`credential.helper=${s}`,"clone","--no-tags","-q",`${n}/${t}.git`,r],{timeout:gA,env:{...e,BOSTRAT_GIT_TOKEN:o,GIT_TERMINAL_PROMPT:"0"}})}catch(a){throw await fh.rm(r,{recursive:!0,force:!0}).catch(()=>{}),Qr(`clone of ${t} failed: ${a?.stderr?.trim?.()||a?.message||a}`,502)}return await Jl(r,{env:e}),r}var ph,pA,mA,mh,hA,wA,gA,hh,Vl,lr,wh,Qr,yA,bA,qt=C(()=>{cr();ph=fA(dA),pA=process.env.BOSTRAT_STATE_DIR||xs.join(process.env.HOME||lA.tmpdir(),".bostrat"),mA=xs.join(pA,"repos"),mh=/^[^/\s]+\/[^/\s]+$/,hA=5*6e4,wA=6e4,gA=10*6e4,hh=fetch,Vl=new Map,lr=null;wh=t=>({authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`}),Qr=(t,e)=>Object.assign(new Error(t),{status:e});yA=()=>uA(new URL("../bin/bostrat-git-credential",import.meta.url)),bA=(t=process.env)=>`http://127.0.0.1:${Number(t.PORT)||3362}`});function yh(t=process.env){return!!(gt(t)&&t.BOSTRAT_PLANE_TOKEN)}async function kh(t,e,n){let r=gt(n),o=new AbortController,s=setTimeout(()=>o.abort(),vA);try{return await SA(`${r}${t}`,{...e,signal:o.signal})}finally{clearTimeout(s)}}async function xh(t,{env:e=process.env,force:n=!1}={}){if(!yh(e))return{facts:[],source:"unconfigured"};let r=Yl.get(t);if(!n&&r&&Date.now()-r.at<xA)return{facts:r.facts,source:"cache"};try{let o=await kh(`/v1/memory/${encodeURIComponent(t)}`,{headers:bh(e)},e);if(!o.ok)throw new Error(`plane ${o.status}`);let s=await o.json(),a=Array.isArray(s?.facts)?s.facts:[];return Yl.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 pi(t,e,{env:n=process.env}={}){if(!yh(n))return{pushed:0,source:"unconfigured"};if(!e?.length)return{pushed:0,source:"empty"};try{let r=await kh(`/v1/memory/${encodeURIComponent(t)}`,{method:"POST",headers:{...bh(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 Yl.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 xA,vA,Yl,SA,bh,vh=C(()=>{qt();xA=6e4,vA=5e3,Yl=new Map,SA=(...t)=>fetch(...t);bh=t=>({authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`})});import K from"node:fs/promises";import TA from"node:os";import et from"node:path";import{execFile as AA}from"node:child_process";import{promisify as EA}from"node:util";function mi(){return et.join(Xl,"memory","repos")}function ur(t){return t===Ke?et.join(Xl,"memory",Ke):et.join(mi(),t)}async function Ss(t){try{return JSON.parse(await K.readFile(et.join(t,_h),"utf8"))}catch{return{}}}async function Zl(t,e){let n=await Ss(t);for(let[r,o]of e)n[r]=Math.max(Number(n[r])||0,o);await K.mkdir(t,{recursive:!0}),await K.writeFile(et.join(t,_h),JSON.stringify(n))}function Th(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 Ah(t){try{let{stdout:e}=await _A("git",["-C",t,"config","--get","remote.origin.url"]);return e.trim()||null}catch{return null}}async function Ql(t){if(!t)return[];let e=Th(await Ah(t));if(e)return[e];let n=[],r=[];try{r=await K.readdir(t,{withFileTypes:!0})}catch{return[]}for(let o of r){if(!o.isDirectory()||o.name.startsWith("."))continue;let s=Th(await Ah(et.join(t,o.name)));s&&!n.includes(s)&&n.push(s)}return n}function hi(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 vn(t,e){let n=new RegExp(`^\\s*${e}:\\s*(.+?)\\s*$`,"m").exec(t||"");return n?n[1].replace(/^"|"$/g,""):null}async function Re(t,e=null){let n=e??await K.readFile(t,"utf8").catch(()=>""),{fm:r}=hi(n),o=vn(r,"modified"),s=o?Date.parse(o):NaN;if(Number.isFinite(s))return s;try{return(await K.stat(t)).mtimeMs}catch{return 0}}function Ih(t,e){let n=vn(t,"scope"),r=/^repo:([a-z0-9][a-z0-9._-]*)$/i.exec(n||"");if(r)return r[1].toLowerCase();if((n||"").toLowerCase()===Ke){let o=vn(t,"trust");if(!o||/^operator/i.test(o))return Ke}return e}function tu(t,e,n,r=new Map){let o=(t||"").split(`
15
15
  `),s=new Map;for(let c of(e||"").split(`
16
- `)){let l=Jr(c);l&&c.trim().startsWith("-")&&s.set(l,c)}let a=new Set,i=o.map(c=>{let l=Jr(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=to(c);l&&c.trim().startsWith("-")&&s.set(l,c)}let a=new Set,i=o.map(c=>{let l=to(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 gh(t,e){let n=bn(e,"name")||t.replace(/\.md$/,""),r=bn(e,"description")||"";return`- [${n}](${t})${r?` \u2014 ${r}`:""}`}async function hs(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 yh(t,e){let n=tt.join(t,".bostrat","memory"),r=await hs(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),d;try{d=await q.readFile(u,"utf8")}catch{continue}let{fm:f}=ci(d),h=wh(f,e);if(!h)continue;let p=cr(h),w=tt.join(p,l),y=await Ie(u,d);if(i.has(p)||i.set(p,await ms(p)),(i.get(p)[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(p,{recursive:!0}),await q.writeFile(w,d),a++;let E=o.get(p);E||o.set(p,E={won:new Set,generated:new Map}),E.won.add(l),E.generated.set(l,gh(l,f)),s.has(h)||s.set(h,new Set),s.get(h).add(l)}let c=await q.readFile(tt.join(n,"MEMORY.md"),"utf8").catch(()=>"");for(let[l,u]of o){let d=tt.join(l,"MEMORY.md"),f=await q.readFile(d,"utf8").catch(()=>"");await q.writeFile(d,ql(f,c,u.won,u.generated))}return{harvested:a,changedByKey:s}}async function cA(){let t=tt.join(Ul,"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 Wl(s),c=await yh(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 dA(t,e){let n=cr(t),r=await ms(n),o=new Set,s=new Map,a=[],i=0;for(let c of e||[]){let l=String(c?.file||"");if(!lA.test(l)||l==="MEMORY.md")continue;let u=tt.join(n,l),d=await q.access(u).then(()=>!0).catch(()=>!1),f=d?await Ie(u):0,h=Number(c.modified)||0;if(c.deleted){h>f&&(d&&await q.rm(u,{force:!0}),await Hl(n,[[l,h]]),d&&(a.push(l),i++));continue}d&&f>=h||(r[l]||0)>=h||(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=ql(l,[...s.values()].join(`
19
+ `)}function Rh(t,e){let n=vn(e,"name")||t.replace(/\.md$/,""),r=vn(e,"description")||"";return`- [${n}](${t})${r?` \u2014 ${r}`:""}`}async function Ts(t){let e=[];try{e=await K.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 $h(t,e){let n=et.join(t,".bostrat","memory"),r=await Ts(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=et.join(n,l),d;try{d=await K.readFile(u,"utf8")}catch{continue}let{fm:f}=hi(d),p=Ih(f,e);if(!p)continue;let h=ur(p),w=et.join(h,l),y=await Re(u,d);if(i.has(h)||i.set(h,await Ss(h)),(i.get(h)[l]||0)>=y)continue;let k=await Re(w).catch(()=>0);if(await K.access(w).then(()=>!0).catch(()=>!1)&&k>=y)continue;await K.mkdir(h,{recursive:!0}),await K.writeFile(w,d),a++;let A=o.get(h);A||o.set(h,A={won:new Set,generated:new Map}),A.won.add(l),A.generated.set(l,Rh(l,f)),s.has(p)||s.set(p,new Set),s.get(p).add(l)}let c=await K.readFile(et.join(n,"MEMORY.md"),"utf8").catch(()=>"");for(let[l,u]of o){let d=et.join(l,"MEMORY.md"),f=await K.readFile(d,"utf8").catch(()=>"");await K.writeFile(d,tu(f,c,u.won,u.generated))}return{harvested:a,changedByKey:s}}async function RA(){let t=et.join(Xl,"workspaces"),e=[];try{e=await K.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=et.join(t,o.name);if(!await K.access(et.join(s,".bostrat","memory")).then(()=>!0).catch(()=>!1))continue;let[i]=await Ql(s),c=await $h(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 CA(t,e){let n=ur(t),r=await Ss(n),o=new Set,s=new Map,a=[],i=0;for(let c of e||[]){let l=String(c?.file||"");if(!$A.test(l)||l==="MEMORY.md")continue;let u=et.join(n,l),d=await K.access(u).then(()=>!0).catch(()=>!1),f=d?await Re(u):0,p=Number(c.modified)||0;if(c.deleted){p>f&&(d&&await K.rm(u,{force:!0}),await Zl(n,[[l,p]]),d&&(a.push(l),i++));continue}d&&f>=p||(r[l]||0)>=p||(await K.mkdir(n,{recursive:!0}),await K.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=et.join(n,"MEMORY.md"),l=await K.readFile(c,"utf8").catch(()=>""),u=tu(l,[...s.values()].join(`
20
20
  `),o);if(a.length){let d=new Set(a);u=u.split(`
21
- `).filter(f=>!d.has(Jr(f))).join(`
22
- `)}await q.mkdir(n,{recursive:!0}),await q.writeFile(c,u)}return{changed:i,tombstoned:a.length}}async function Kl(t,e=null){let n=cr(t),r=e?.length?e:await hs(n);if(!r.length)return{pushed:0,source:"empty"};let o=uA(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 ai(t,s)}async function fA(t){let{facts:e,source:n}=await lh(t);e.length?await dA(t,e):n==="plane"&&await Kl(t)}function pA(t){let e=t.split(`
23
- `);e.length>dh&&(e=e.slice(0,dh));let n=e.join(`
24
- `);for(;Buffer.byteLength(n,"utf8")>iA&&e.length;)e.pop(),n=e.join(`
25
- `);return n}async function hA(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 d=cr(u),f=await ms(d);for(let[y,k]of Object.entries(f)){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 h=await hs(d);if(!h.length)continue;await q.mkdir(n,{recursive:!0});for(let y of h){let k=tt.join(d,y),x=tt.join(n,y),E=await Ie(k),$=await Ie(x).catch(()=>0);await q.access(x).then(()=>!0).catch(()=>!1)&&$>=E||(await q.copyFile(k,x),r++)}let p=await q.readFile(tt.join(d,"MEMORY.md"),"utf8").catch(()=>""),w=u===qe?"## operator memory":`## repo: ${u}`;p.trim()&&s.push(e.length>1?`${w}
21
+ `).filter(f=>!d.has(to(f))).join(`
22
+ `)}await K.mkdir(n,{recursive:!0}),await K.writeFile(c,u)}return{changed:i,tombstoned:a.length}}async function eu(t,e=null){let n=ur(t),r=e?.length?e:await Ts(n);if(!r.length)return{pushed:0,source:"empty"};let o=OA(await K.readFile(et.join(n,"MEMORY.md"),"utf8").catch(()=>"")),s=[];for(let a of r){let i=et.join(n,a),c;try{c=await K.readFile(i,"utf8")}catch{continue}s.push({file:a,content:c,modified:await Re(i,c),indexLine:o.get(a)??null})}return pi(t,s)}async function MA(t){let{facts:e,source:n}=await xh(t);e.length?await CA(t,e):n==="plane"&&await eu(t)}function NA(t){let e=t.split(`
23
+ `);e.length>Sh&&(e=e.slice(0,Sh));let n=e.join(`
24
+ `);for(;Buffer.byteLength(n,"utf8")>IA&&e.length;)e.pop(),n=e.join(`
25
+ `);return n}async function BA(t,e){if(!t||!e?.length)return{materialized:!1,reason:"no-repo-key"};let n=et.join(t,".bostrat","memory"),r=0,o=0,s=[];for(let u of e){let d=ur(u),f=await Ss(d);for(let[y,k]of Object.entries(f)){let x=et.join(n,y);await K.access(x).then(()=>!0).catch(()=>!1)&&await Re(x)<=k&&(await K.rm(x,{force:!0}),o++)}let p=await Ts(d);if(!p.length)continue;await K.mkdir(n,{recursive:!0});for(let y of p){let k=et.join(d,y),x=et.join(n,y),A=await Re(k),R=await Re(x).catch(()=>0);await K.access(x).then(()=>!0).catch(()=>!1)&&R>=A||(await K.copyFile(k,x),r++)}let h=await K.readFile(et.join(d,"MEMORY.md"),"utf8").catch(()=>""),w=u===Ke?"## operator memory":`## repo: ${u}`;h.trim()&&s.push(e.length>1?`${w}
26
26
 
27
- ${p.trim()}`:p.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=pA(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"),mA,{flag:"wx"}).catch(()=>{}),{materialized:!0,facts:r,capped:c!==i}}async function bh(t){try{let e=await Wl(t);if(!e.length)return{materialized:!1,reason:"no-repo-key"};let n=[...e,qe];if(Date.now()-mh>wA){mh=Date.now(),await gA();let{changedByKey:r}=await cA();for(let[o,s]of r)await Kl(o,[...s])}for(let r of n)await fA(r);return await hA(t,n)}catch(e){return{materialized:!1,reason:"error",error:e?.message||String(e)}}}async function gA(){let t=0,e=[];try{e=await q.readdir(ii(),{withFileTypes:!0})}catch{return{moved:t}}for(let n of e){if(!n.isDirectory())continue;let r=tt.join(ii(),n.name),o=cr(qe),s=new Set,a=new Map;for(let h of await hs(r)){let p=tt.join(r,h),w;try{w=await q.readFile(p,"utf8")}catch{continue}let{fm:y}=ci(w);if(wh(y,n.name)!==qe)continue;let k=tt.join(o,h),x=await Ie(k).catch(()=>0),E=await Ie(p,w);await q.mkdir(o,{recursive:!0}),E>x&&await q.writeFile(k,w),await q.rm(p,{force:!0}),s.add(h),a.set(h,gh(h,y)),t++}if(!s.size)continue;let i=Date.now();await Hl(r,[...s].map(h=>[h,i])),await ai(n.name,[...s].map(h=>({file:h,deleted:!0,modified:i})));let c=tt.join(r,"MEMORY.md"),l=await q.readFile(c,"utf8").catch(()=>""),u=l.split(`
31
- `).filter(h=>!s.has(Jr(h))).join(`
32
- `);await q.writeFile(c,u).catch(()=>{});let d=tt.join(o,"MEMORY.md"),f=await q.readFile(d,"utf8").catch(()=>"");await q.writeFile(d,ql(f,l,s,a))}return{moved:t}}async function kh(){let t=[],e=[qe];try{for(let n of await q.readdir(ii(),{withFileTypes:!0}))n.isDirectory()&&e.push(n.name)}catch{}for(let n of e){let r=cr(n),o=await hs(r),s=await ms(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}=ci(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 xh(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 Hl(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=>Jr(l)!==e).join(`
34
- `)).catch(()=>{});let c=await ai(t,[{file:e,deleted:!0,modified:s}]);return{deleted:e,key:t,plane:c.source}}async function Sh(t){try{let e=await Wl(t),{harvested:n,changedByKey:r}=await yh(t,e[0]||null);for(let[o,s]of r)await Kl(o,[...s]);return{harvested:n}}catch(e){return{harvested:0,error:e?.message||String(e)}}}var aA,Ul,dh,iA,qe,hh,Jr,lA,uA,mA,mh,wA,li=M(()=>{uh();aA=sA(oA),Ul=process.env.BOSTRAT_STATE_DIR||tt.join(process.env.HOME||rA.tmpdir(),".bostrat"),dh=200,iA=25*1024;qe="operator";hh=".tombstones.json";Jr=t=>/\]\(([^)]+\.md)\)/.exec(t)?.[1]||null;lA=/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/,uA=t=>{let e=new Map;for(let n of(t||"").split(`
35
- `)){let r=Jr(n);r&&n.trim().startsWith("-")&&e.set(r,n)}return e};mA=`# Track memory
30
+ `,c=NA(i);await K.mkdir(n,{recursive:!0}),await K.writeFile(et.join(n,"MEMORY.md"),c);let l=et.join(n,"claude");return await K.mkdir(l,{recursive:!0}),await K.writeFile(et.join(l,"MEMORY.md"),PA,{flag:"wx"}).catch(()=>{}),{materialized:!0,facts:r,capped:c!==i}}async function Oh(t){try{let e=await Ql(t);if(!e.length)return{materialized:!1,reason:"no-repo-key"};let n=[...e,Ke];if(Date.now()-Eh>DA){Eh=Date.now(),await jA();let{changedByKey:r}=await RA();for(let[o,s]of r)await eu(o,[...s])}for(let r of n)await MA(r);return await BA(t,n)}catch(e){return{materialized:!1,reason:"error",error:e?.message||String(e)}}}async function jA(){let t=0,e=[];try{e=await K.readdir(mi(),{withFileTypes:!0})}catch{return{moved:t}}for(let n of e){if(!n.isDirectory())continue;let r=et.join(mi(),n.name),o=ur(Ke),s=new Set,a=new Map;for(let p of await Ts(r)){let h=et.join(r,p),w;try{w=await K.readFile(h,"utf8")}catch{continue}let{fm:y}=hi(w);if(Ih(y,n.name)!==Ke)continue;let k=et.join(o,p),x=await Re(k).catch(()=>0),A=await Re(h,w);await K.mkdir(o,{recursive:!0}),A>x&&await K.writeFile(k,w),await K.rm(h,{force:!0}),s.add(p),a.set(p,Rh(p,y)),t++}if(!s.size)continue;let i=Date.now();await Zl(r,[...s].map(p=>[p,i])),await pi(n.name,[...s].map(p=>({file:p,deleted:!0,modified:i})));let c=et.join(r,"MEMORY.md"),l=await K.readFile(c,"utf8").catch(()=>""),u=l.split(`
31
+ `).filter(p=>!s.has(to(p))).join(`
32
+ `);await K.writeFile(c,u).catch(()=>{});let d=et.join(o,"MEMORY.md"),f=await K.readFile(d,"utf8").catch(()=>"");await K.writeFile(d,tu(f,l,s,a))}return{moved:t}}async function Ch(){let t=[],e=[Ke];try{for(let n of await K.readdir(mi(),{withFileTypes:!0}))n.isDirectory()&&e.push(n.name)}catch{}for(let n of e){let r=ur(n),o=await Ts(r),s=await Ss(r);if(!o.length&&!Object.keys(s).length)continue;let a=[];for(let i of o){let c=await K.readFile(et.join(r,i),"utf8").catch(()=>""),{fm:l}=hi(c);a.push({file:i,name:vn(l,"name")||i.replace(/\.md$/,""),description:vn(l,"description")||"",scope:vn(l,"scope")||null,modified:await Re(et.join(r,i),c)})}t.push({key:n,facts:a,tombstones:Object.keys(s).length})}return t}async function Mh(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=ur(t),r=et.join(n,e);if(!await K.access(r).then(()=>!0).catch(()=>!1))throw new Error(`fact ${e} not found in ${t}`);let s=Date.now();await K.rm(r,{force:!0}),await Zl(n,[[e,s]]);let a=et.join(n,"MEMORY.md"),i=await K.readFile(a,"utf8").catch(()=>"");await K.writeFile(a,i.split(`
33
+ `).filter(l=>to(l)!==e).join(`
34
+ `)).catch(()=>{});let c=await pi(t,[{file:e,deleted:!0,modified:s}]);return{deleted:e,key:t,plane:c.source}}async function Nh(t){try{let e=await Ql(t),{harvested:n,changedByKey:r}=await $h(t,e[0]||null);for(let[o,s]of r)await eu(o,[...s]);return{harvested:n}}catch(e){return{harvested:0,error:e?.message||String(e)}}}var _A,Xl,Sh,IA,Ke,_h,to,$A,OA,PA,Eh,DA,wi=C(()=>{vh();_A=EA(AA),Xl=process.env.BOSTRAT_STATE_DIR||et.join(process.env.HOME||TA.tmpdir(),".bostrat"),Sh=200,IA=25*1024;Ke="operator";_h=".tombstones.json";to=t=>/\]\(([^)]+\.md)\)/.exec(t)?.[1]||null;$A=/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/,OA=t=>{let e=new Map;for(let n of(t||"").split(`
35
+ `)){let r=to(n);r&&n.trim().startsWith("-")&&e.set(r,n)}return e};PA=`# 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
- `;mh=0,wA=3e4});import Gl from"node:fs/promises";import yA from"node:path";async function Yt(t,e,{mode:n}={}){await Gl.mkdir(yA.dirname(t),{recursive:!0});let r=`${t}.${process.pid}.${++bA}.tmp`;await Gl.writeFile(r,JSON.stringify(e,null,2)+`
41
- `,n!=null?{mode:n}:void 0),await Gl.rename(r,t)}var bA,kn=M(()=>{bA=0});import _h from"node:fs/promises";import Ih from"node:os";import Rh from"node:path";function vt(t=process.env){return!!(gt(t)&&t.BOSTRAT_PLANE_TOKEN)}async function ys(t,e={},n=process.env){let r=new AbortController,o=setTimeout(()=>r.abort(),kA);try{return await EA(`${gt(n)}${t}`,{...e,signal:r.signal})}finally{clearTimeout(o)}}async function Oh(){return di||(Vl||=_h.readFile($h(),"utf8").then(t=>JSON.parse(t)).catch(()=>({ops:[]})).then(t=>di={ops:Array.isArray(t?.ops)?t.ops:[],parked:Array.isArray(t?.parked)?t.parked:[]}).finally(()=>Vl=null),Vl)}async function fi(){await Yt($h(),di).catch(()=>{})}function Ah(t){return t.op==="blob"?`blob ${t.family} ${t.id} ${t.v} ${t.kind}`:`${t.op} ${t.family} ${t.id}`}async function Jl(t){let e=await Oh(),n=Ah(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=>Ah(o)===n);r>=0?e.ops[r]=t:e.ops.push(t)}e.ops.length>vh&&(e.ops=e.ops.slice(-vh)),await fi()}function Eh(){ui||(ui=setTimeout(()=>{ui=null,Yr().catch(()=>{})},_A),ui.unref?.())}function zl(t){let e=new Error(`plane ${t}`);return e.refused=!0,e}async function RA(t,e=process.env){if(t.op==="record"){let n=await ys(`/v1/content/${encodeURIComponent(t.family)}`,{method:"POST",headers:{...gs(e),"content-type":"application/json"},body:JSON.stringify({records:[{id:t.id,trackId:t.trackId??null,data:t.data,updatedAt:t.updatedAt,originNode:AA()}]})},e);if(!n.ok)throw zl(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 _h.readFile(t.path).catch(()=>null);if(!n)return{delivered:!0,dropped:"source file gone"};let r=await ys(`/v1/content/${encodeURIComponent(t.family)}/${encodeURIComponent(t.id)}/blob?v=${t.v}&kind=${encodeURIComponent(t.kind)}`,{method:"POST",headers:{...gs(e),"content-type":"application/octet-stream"},body:n},e);if(!r.ok&&r.status!==400)throw zl(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 ys(`/v1/content/${encodeURIComponent(t.family)}/${encodeURIComponent(t.id)}?deletedAt=${t.deletedAt}`,{method:"DELETE",headers:gs(e)},e);if(!n.ok)throw zl(n.status);return{delivered:!0}}return{delivered:!0,dropped:"unknown op"}}async function Yr({env:t=process.env,log:e=console,now:n=Date.now()}={}){return vt(t)?ws||(ws=(async()=>{let r=await Oh();$A(r,n);let o=0,s=0;for(;r.ops.length;){let a=r.ops[0],i;try{i=await RA(a,t)}catch(c){if(!c?.refused)return Eh(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};if(a.refusals=(a.refusals||0)+1,a.refusals<SA)return Eh(),await fi(),{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>Th&&(r.parked=r.parked.slice(-Th)),s++,await fi();continue}i.rejected&&e.error?.(`[content-plane] ALARM plane rejected ${a.op} ${a.family}/${a.id}: ${i.rejected}`),r.ops.shift(),o++,await fi()}return{flushed:o,parked:s,pending:0}})().finally(()=>{ws=null}),ws):{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)>=IA);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 qt(t,e,{trackId:n=null,env:r=process.env}={}){return vt(r)?(await Jl({op:"record",family:t,id:e.id,trackId:n??e.trackId??null,data:e,updatedAt:Number(e.updatedAt)||Date.now()}),Yr({env:r})):{queued:!1,source:"unconfigured"}}async function xn(t,e,n,r,o,{env:s=process.env}={}){return vt(s)?(await Jl({op:"blob",family:t,id:e,v:Number(n),kind:r,path:o}),Yr({env:s})):{queued:!1,source:"unconfigured"}}async function we(t,e,{deletedAt:n=Date.now(),env:r=process.env}={}){return vt(r)?(await Jl({op:"delete",family:t,id:e,deletedAt:n}),Yr({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 ys(`/v1/content/${encodeURIComponent(t)}?tombstones=1`,{headers:gs(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 bs(t,e,n,r,{env:o=process.env}={}){if(!vt(o))return null;try{let s=await ys(`/v1/content/${encodeURIComponent(t)}/${encodeURIComponent(e)}/blob?v=${Number(n)}&kind=${encodeURIComponent(r)}`,{headers:gs(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 kA,xA,vh,SA,Th,vA,TA,$h,AA,EA,_A,IA,gs,di,Vl,ui,ws,Sn=M(()=>{Wt();kn();kA=1e4,xA=3e4,vh=2e3,SA=5,Th=100,vA=60*6e4,TA=()=>process.env.BOSTRAT_STATE_DIR||Rh.join(process.env.HOME||Ih.tmpdir(),".bostrat"),$h=()=>Rh.join(TA(),"content-outbox.json"),AA=()=>process.env.BOSTRAT_NODE_ID||Ih.hostname(),EA=(...t)=>fetch(...t),_A=xA,IA=vA;gs=(t=process.env)=>({authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`});di=null,Vl=null,ui=null,ws=null});import Yl from"node:fs/promises";import Ch from"node:path";async function Mh(t,e,{box:n=null,agent:r=null}={}){if(!t||!vt())return{pushed:!1};try{let o=Date.now();return await qt("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 pi(t){try{let e=MA(t);if(!e||!vt())return{restored:!1};let n=Ch.join(t,OA,CA);if(await Yl.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 bs("checkpoints",e,s.data.v,"md");return typeof a!="string"||!a?{restored:!1}:(await Yl.mkdir(Ch.dirname(n),{recursive:!0}),await Yl.writeFile(n,a),{restored:!0,v:s.data.v})}catch{return{restored:!1}}}var OA,CA,MA,mi=M(()=>{Sn();OA=".bostrat/handoff",CA="latest.md",MA=t=>/workspaces[/\\]([0-9a-f]{8})$/.exec(t||"")?.[1]??null});import ks from"node:fs/promises";import NA from"node:os";import Ph from"node:path";function lr(t){let e=String(t??"");for(let n of PA)e=e.replace(n,"\u2039redacted\u203A");return e}function hi(){let t=process.env.BOSTRAT_HANDOFF_DEBUG;return t==="1"||t==="true"}async function BA(t){try{await ks.mkdir(Xl,{recursive:!0}),await ks.appendFile(Xr,`${JSON.stringify(t)}
42
- `,"utf8");let n=(await ks.readFile(Xr,"utf8")).split(`
43
- `).filter(Boolean);n.length>Nh&&await ks.writeFile(Xr,`${n.slice(-Nh).join(`
40
+ `;Eh=0,DA=3e4});import nu from"node:fs/promises";import LA from"node:path";async function Xt(t,e,{mode:n}={}){await nu.mkdir(LA.dirname(t),{recursive:!0});let r=`${t}.${process.pid}.${++FA}.tmp`;await nu.writeFile(r,JSON.stringify(e,null,2)+`
41
+ `,n!=null?{mode:n}:void 0),await nu.rename(r,t)}var FA,Sn=C(()=>{FA=0});import Lh from"node:fs/promises";import Fh from"node:os";import Uh from"node:path";function kt(t=process.env){return!!(gt(t)&&t.BOSTRAT_PLANE_TOKEN)}async function _s(t,e={},n=process.env){let r=new AbortController,o=setTimeout(()=>r.abort(),UA);try{return await VA(`${gt(n)}${t}`,{...e,signal:r.signal})}finally{clearTimeout(o)}}async function Wh(){return yi||(ru||=Lh.readFile(Hh(),"utf8").then(t=>JSON.parse(t)).catch(()=>({ops:[]})).then(t=>yi={ops:Array.isArray(t?.ops)?t.ops:[],parked:Array.isArray(t?.parked)?t.parked:[]}).finally(()=>ru=null),ru)}async function bi(){await Xt(Hh(),yi).catch(()=>{})}function Dh(t){return t.op==="blob"?`blob ${t.family} ${t.id} ${t.v} ${t.kind}`:`${t.op} ${t.family} ${t.id}`}async function su(t){let e=await Wh(),n=Dh(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=>Dh(o)===n);r>=0?e.ops[r]=t:e.ops.push(t)}e.ops.length>Ph&&(e.ops=e.ops.slice(-Ph)),await bi()}function jh(){gi||(gi=setTimeout(()=>{gi=null,eo().catch(()=>{})},zA),gi.unref?.())}function ou(t){let e=new Error(`plane ${t}`);return e.refused=!0,e}async function YA(t,e=process.env){if(t.op==="record"){let n=await _s(`/v1/content/${encodeURIComponent(t.family)}`,{method:"POST",headers:{...Es(e),"content-type":"application/json"},body:JSON.stringify({records:[{id:t.id,trackId:t.trackId??null,data:t.data,updatedAt:t.updatedAt,originNode:GA()}]})},e);if(!n.ok)throw ou(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 Lh.readFile(t.path).catch(()=>null);if(!n)return{delivered:!0,dropped:"source file gone"};let r=await _s(`/v1/content/${encodeURIComponent(t.family)}/${encodeURIComponent(t.id)}/blob?v=${t.v}&kind=${encodeURIComponent(t.kind)}`,{method:"POST",headers:{...Es(e),"content-type":"application/octet-stream"},body:n},e);if(!r.ok&&r.status!==400)throw ou(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 _s(`/v1/content/${encodeURIComponent(t.family)}/${encodeURIComponent(t.id)}?deletedAt=${t.deletedAt}`,{method:"DELETE",headers:Es(e)},e);if(!n.ok)throw ou(n.status);return{delivered:!0}}return{delivered:!0,dropped:"unknown op"}}async function eo({env:t=process.env,log:e=console,now:n=Date.now()}={}){return kt(t)?As||(As=(async()=>{let r=await Wh();XA(r,n);let o=0,s=0;for(;r.ops.length;){let a=r.ops[0],i;try{i=await YA(a,t)}catch(c){if(!c?.refused)return jh(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};if(a.refusals=(a.refusals||0)+1,a.refusals<WA)return jh(),await bi(),{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>Bh&&(r.parked=r.parked.slice(-Bh)),s++,await bi();continue}i.rejected&&e.error?.(`[content-plane] ALARM plane rejected ${a.op} ${a.family}/${a.id}: ${i.rejected}`),r.ops.shift(),o++,await bi()}return{flushed:o,parked:s,pending:0}})().finally(()=>{As=null}),As):{flushed:0,source:"unconfigured"}}function XA(t,e){if(!t.parked.length||t.ops.length)return;let n=t.parked.filter(r=>e-(r.parkedAt||0)>=JA);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 Kt(t,e,{trackId:n=null,env:r=process.env}={}){return kt(r)?(await su({op:"record",family:t,id:e.id,trackId:n??e.trackId??null,data:e,updatedAt:Number(e.updatedAt)||Date.now()}),eo({env:r})):{queued:!1,source:"unconfigured"}}async function Tn(t,e,n,r,o,{env:s=process.env}={}){return kt(s)?(await su({op:"blob",family:t,id:e,v:Number(n),kind:r,path:o}),eo({env:s})):{queued:!1,source:"unconfigured"}}async function ye(t,e,{deletedAt:n=Date.now(),env:r=process.env}={}){return kt(r)?(await su({op:"delete",family:t,id:e,deletedAt:n}),eo({env:r})):{queued:!1,source:"unconfigured"}}async function Mt(t,{env:e=process.env}={}){if(!kt(e))return{records:[],source:"unconfigured"};try{let n=await _s(`/v1/content/${encodeURIComponent(t)}?tombstones=1`,{headers:Es(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 Is(t,e,n,r,{env:o=process.env}={}){if(!kt(o))return null;try{let s=await _s(`/v1/content/${encodeURIComponent(t)}/${encodeURIComponent(e)}/blob?v=${Number(n)}&kind=${encodeURIComponent(r)}`,{headers:Es(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 UA,HA,Ph,WA,Bh,qA,KA,Hh,GA,VA,zA,JA,Es,yi,ru,gi,As,An=C(()=>{qt();Sn();UA=1e4,HA=3e4,Ph=2e3,WA=5,Bh=100,qA=60*6e4,KA=()=>process.env.BOSTRAT_STATE_DIR||Uh.join(process.env.HOME||Fh.tmpdir(),".bostrat"),Hh=()=>Uh.join(KA(),"content-outbox.json"),GA=()=>process.env.BOSTRAT_NODE_ID||Fh.hostname(),VA=(...t)=>fetch(...t),zA=HA,JA=qA;Es=(t=process.env)=>({authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`});yi=null,ru=null,gi=null,As=null});import au from"node:fs/promises";import qh from"node:path";async function Kh(t,e,{box:n=null,agent:r=null}={}){if(!t||!kt())return{pushed:!1};try{let o=Date.now();return await Kt("checkpoints",{id:t,trackId:t,v:o,box:n,agent:r,updatedAt:o},{trackId:t}),await Tn("checkpoints",t,o,"md",e),{pushed:!0,v:o}}catch{return{pushed:!1}}}async function ki(t){try{let e=tE(t);if(!e||!kt())return{restored:!1};let n=qh.join(t,ZA,QA);if(await au.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 Is("checkpoints",e,s.data.v,"md");return typeof a!="string"||!a?{restored:!1}:(await au.mkdir(qh.dirname(n),{recursive:!0}),await au.writeFile(n,a),{restored:!0,v:s.data.v})}catch{return{restored:!1}}}var ZA,QA,tE,xi=C(()=>{An();ZA=".bostrat/handoff",QA="latest.md",tE=t=>/workspaces[/\\]([0-9a-f]{8})$/.exec(t||"")?.[1]??null});import Rs from"node:fs/promises";import eE from"node:os";import Vh from"node:path";function dr(t){let e=String(t??"");for(let n of nE)e=e.replace(n,"\u2039redacted\u203A");return e}function vi(){let t=process.env.BOSTRAT_HANDOFF_DEBUG;return t==="1"||t==="true"}async function rE(t){try{await Rs.mkdir(iu,{recursive:!0}),await Rs.appendFile(no,`${JSON.stringify(t)}
42
+ `,"utf8");let n=(await Rs.readFile(no,"utf8")).split(`
43
+ `).filter(Boolean);n.length>Gh&&await Rs.writeFile(no,`${n.slice(-Gh).join(`
44
44
  `)}
45
- `,"utf8")}catch(e){console.warn(`[handoff-debug] failed to write ${Xr}: ${e?.message||e}`)}}async function V(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&&hi())try{e.paneTail=lr((await Tt(e.sessionName,{lines:35})).slice(-4e3))}catch{e.paneTail=null}(hi()||e.error||/^(checkpoint|spawn|hydrate|commit|done|summarize|clear|resume|ready|send|failed|launch)/.test(String(e.phase||e.step||"")))&&await BA(e)}async function Bh({limit:t=80}={}){try{return(await ks.readFile(Xr,"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 PA,Xl,Xr,Nh,Dh,Ke=M(()=>{Kt();PA=[/[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];Xl=process.env.BOSTRAT_DEBUG_DIR||Ph.join(NA.homedir(),".bostrat","debug"),Xr=Ph.join(Xl,"handoff.jsonl"),Nh=Number(process.env.BOSTRAT_HANDOFF_DEBUG_MAX)||500;Dh={DEBUG_DIR:Xl,LOG_FILE:Xr}});import{execFile as DA}from"node:child_process";import{promisify as jA}from"node:util";import gi from"node:fs";import{randomUUID as LA}from"node:crypto";function to(t){return new Promise(e=>setTimeout(e,t))}function wi(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 Lh(t){return`/tmp/tmux-${t}/default`}function FA({explicit:t,legacyExists:e,runtimeDir:n,uid:r}){if(t)return t;let o=Lh(r);return e?o:n?`${n}/bostrat/tmux-default`:o}function tu(){return process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1"?[]:["-e",`${HA}=1`]}function nu(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 qA(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 Fh(t,{loginShell:e=!1,failOpen:n=!1}={}){let r=await Uh(t,{loginShell:e});return r===yi?!0:r===Zr?!1:n}async function Uh(t,{loginShell:e=!1,timeoutMs:n=Zl}={}){if(!t)return Zr;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}),yi}catch(s){return s?.killed||s?.signal?Qr:s?.code===1||s?.code===127?Zr:Qr}}async function bi(t,{retries:e=KA,sleep:n=GA,probe:r=Uh}={}){let o=String(t||"").trim().split(/\s+/)[0],s=await r(o,{timeoutMs:Zl});for(let a=0;s===Qr&&a<e.length;a++)await n(e[a]),s=await r(o,{timeoutMs:Zl*2});return s}function U(...t){return["-S",ne,...t]}async function Tn(){if(!gi.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 xs(){if(await Tn())return!0;try{gi.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"&&VA.test(t)}async function ge(){if(!gi.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,d,f,h]=r.split("|"),p=Number(i);return{name:o,title:u||null,windows:Number(s),attached:Number(a),lastActivityMs:Number.isFinite(p)?n-p*1e3:null,cwd:c||null,isBostrat:l==="1",sessionId:d||null,agent:f||(l==="1"?"claude":null),alternateOn:h==="1"}}).filter(r=>!WA.has(r.name)&&!r.name.startsWith("bostrat-view-"))}catch{return[]}}async function et(t){return(await ge()).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<=JA&&zA.test(e)}function ki(t){return t.trim().replace(/\s+/g,"-").toLowerCase().replace(/[^A-Za-z0-9_.-]/g,"").replace(/^-+|-+$/g,"")}async function Hh(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 tE(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 eE(t,e){let n=Date.now()+XA(),r=tE(e),o=!1,s=0;for(;;){if(await to(ZA),s+=1,!await Hh(t))return;let a=await Tt(t,{lines:15}),i=!o&&QA.test(a)&&!!r?.test(a);if(!i&&s>1&&!await eo(t))return;if(i){o=!0,await V({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 V({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=UA,n={}){if(!YA(t))throw new Error("displayName must be 1\u201364 chars (letters, digits, space . _ -)");let r=t.trim(),o=ki(r);if(!At(o))throw new Error("resulting tmux session name is invalid");if(!await xs())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 Hh(o))throw new Error(`tmux session "${o}" already exists`);let s=n.agentCmd||Ql,a=n.agent||vn(s),i=!!n.resumeSessionId,c=n.resumeSessionId||LA(),l=i?s:nu(s,c,o),u=i?n.pinned===!0:/(^|\s)--session-id(\s|=)/.test(l),d=a==="claude"&&ur(s),f=n.firstRun===!0;f||(d&&await gn(e),a==="codex"&&await Kr(e),a==="cursor"&&await Gr(e),await bh(e),await pi(e));let h=d&&!f?Qa():null,p=Vm(),w=["-e",`${Xa}=${p}`];h&&w.push("-e",`ANTHROPIC_API_KEY=${h}`),d&&w.push(...tu());try{await ft(L,U("new-session","-d","-s",o,"-c",e,...w))}catch(y){throw wi(h?wi(y,h):y,p)}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")),qA(l)&&eE(o,l).catch(()=>{}),{name:o,title:r,cwd:e,sessionId:c,agent:a,pinned:u,hookToken:p}}async function Re(t){if(!At(t))throw new Error("invalid session name");await ft(L,U("kill-session","-t",t))}async function Wh(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 qh(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=oE,rows:n=sE}={}){if(!At(t))return!0;if(await qh(t))return!1;try{let r=await Kh(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 to(80)}catch{}return!0}async function aE(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 eo(t){let e=await aE(t);if(!e)return!1;try{return await ft("pgrep",["-P",String(e)]),!1}catch(n){return n?.code===1}}async function Kh(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 xi(t,{cols:e=nE,rows:n=rE}={}){if(At(t)&&!await qh(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 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 to(80))}catch{}}async function En(t){return await xi(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=>iE.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 to(n);return V({flow:"tmux",phase:"send-keys",sessionName:t,kind:r||"keys",keys:o.join(" ")}).catch(()=>{}),o.length}async function no(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")),V({flow:"tmux",phase:"send-keys",sessionName:t,kind:n||"wipe",keys:`BSpace x${r}`}).catch(()=>{}),r}async function vi(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 to(n);V({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 to(s),await ft(L,U("send-keys","-t",t,"Enter"))}V({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,jh,ne,UA,Ql,HA,eu,WA,yi,Zr,Qr,Zl,KA,GA,ru,VA,zA,JA,XA,ZA,QA,nE,rE,Nt,oE,sE,iE,Si,Kt=M(()=>{us();ei();ni();li();mi();Ke();ls();ft=jA(DA);L=process.env.BOSTRAT_TMUX_BIN||"/usr/bin/tmux";jh=typeof process.getuid=="function"?process.getuid():0,ne=FA({explicit:process.env.BOSTRAT_TMUX_SOCKET,legacyExists:(()=>{try{return gi.existsSync(Lh(jh))}catch{return!1}})(),runtimeDir:process.env.XDG_RUNTIME_DIR,uid:jh}),UA=process.env.BOSTRAT_DEFAULT_CWD||process.env.HOME||"/",Ql=process.env.BOSTRAT_AGENT_CMD||"claude --dangerously-skip-permissions",HA="CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN";eu="bostrat-usage-probe",WA=new Set([eu]);yi="present",Zr="absent",Qr="unknown",Zl=5e3,KA=[250,1e3,3e3],GA=t=>new Promise(e=>setTimeout(e,t));ru={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"};VA=/^[A-Za-z0-9_.-]{1,64}$/;zA=/^[A-Za-z0-9 ._↻-]+$/,JA=64;XA=()=>Number(process.env.BOSTRAT_LAUNCH_VERIFY_MS)||12e3,ZA=1e3,QA=/not found|Unknown command/i;nE=Number(process.env.BOSTRAT_PROMPT_CAPTURE_COLS)||100,rE=Number(process.env.BOSTRAT_PROMPT_CAPTURE_ROWS)||40,Nt=Number(process.env.BOSTRAT_PROMPT_CAPTURE_LINES)||80,oE=Number(process.env.BOSTRAT_BOX_COLS)||120,sE=Number(process.env.BOSTRAT_BOX_ROWS)||40;iE=new Set(["Up","Down","Left","Right","Space","Enter","Tab","BTab","Escape","BSpace"]);Si=1600});import Ss from"node:fs";import pE from"node:fs/promises";import ro from"node:path";import mE from"node:os";function au(t){return t.replace(/[^A-Za-z0-9]/g,"-")}function iu(t){let e=ro.join(su,au(t)),n;try{n=Ss.readdirSync(e).filter(o=>o.endsWith(".jsonl"))}catch{return null}let r=null;for(let o of n){let s=ro.join(e,o);try{let{mtimeMs:a}=Ss.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=ro.join(su,au(t),`${e}.jsonl`);return Ss.existsSync(n)?n:null}function Zh(t){if(!t)return[];let e=ro.join(su,au(t)),n;try{n=Ss.readdirSync(e).filter(o=>o.endsWith(".jsonl"))}catch{return[]}let r=[];for(let o of n)try{let s=Ss.statSync(ro.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 pE.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 wE(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 vs(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=iu(t),o=!1,!r)return null}else return null;let s;try{s=wE(await Xt(r))}catch{return null}if(!s)return null;let a=Object.prototype.hasOwnProperty.call(Xh,s.model),i=Xh[s.model]||hE;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 Xh,hE,su,ye=M(()=>{Xh={"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},hE=2e5,su=process.env.BOSTRAT_CLAUDE_PROJECTS||ro.join(mE.homedir(),".claude","projects")});function gE(t,e){return!t||!e?null:Ge(t,e)}function yE(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 bE(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 kE(t){return Array.isArray(t)&&t.length>0&&t.every(e=>e&&e.type==="tool_result")}function cu(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 Qh(t,e){if(!t.uuid)return null;let n=cu(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 lu(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 p=c.attachment;p?.type==="queued_command"&&p.commandMode==="task-notification"&&typeof p.prompt=="string"&&p.prompt.trim()&&o.push({role:"user",text:p.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 p of l.content){let w=p?.type==="tool_use"?p.input?.file_path||p.input?.path:null;typeof w=="string"&&xE.test(w)&&s.set(p.id,w.split("/").pop())}if(kE(l.content)){let p=Qh(c,s);p&&o.push({role:"assistant",text:"",images:p,ts:c.timestamp?Date.parse(c.timestamp):null,model:null});continue}let d=yE(l.content),f=u==="assistant"?bE(l.content):null,h=u==="user"?Qh(c,s):null;!d&&!f&&!h||o.push({role:u,text:d,tools:f||void 0,images:h||void 0,ts:c.timestamp?Date.parse(c.timestamp):null,model:l.model||null})}return o.slice(-n)}async function tw(t,e,{turns:n=16}={}){let r=gE(t,e);if(!r)return"";let o=await lu(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}:** ${SE(s.text||c,700)} ${i}`.trim()}).join(`
53
-
54
- `):""}var xE,SE,Ai=M(()=>{ye();xE=/\.(png|jpe?g|gif|webp|bmp|svg|tiff?|avif|heic|heif|ico)$/i;SE=(t,e)=>t.length>e?`${t.slice(0,e).trimEnd()}\u2026`:t});import vE from"node:fs/promises";import{execFile as TE}from"node:child_process";import{promisify as AE}from"node:util";function ow(t){du=typeof t=="function"?t:null}function _E(t){let e=String(t||""),n=e.indexOf("/lib/node_modules/");return n>0?e.slice(0,n):null}function sw({sessionName:t,from:e,to:n}={}){let r=String(n||"").trim();!r||ew.has(r)||(ew.add(r),nw=nw.then(()=>IE({sessionName:t,from:e,to:r})).catch(()=>{}))}async function IE({sessionName:t,from:e,to:n}){await V({flow:"codex-update",phase:"start",sessionName:t,from:e,to:n}).catch(()=>{});try{let r=(await uu("/bin/sh",["-c","command -v codex"])).stdout.trim();if(!r)throw new Error("codex not on PATH");let o=await vE.realpath(r),s=_E(o),a=s?{...process.env,PATH:`${s}/bin:${process.env.PATH||""}`}:process.env;await uu("npm",["install","-g","@openai/codex"],{env:a,timeout:EE});let i=(await uu(r,["--version"])).stdout.trim().replace(/^codex-cli\s*/,"")||n;await V({flow:"codex-update",phase:"done",sessionName:t,from:e,to:n,version:i}).catch(()=>{}),await rw({sessionName:t,from:e,to:n,version:i,status:"updated"})}catch(r){let o=String(r?.message||r).slice(0,300);await V({flow:"codex-update",phase:"failed",sessionName:t,from:e,to:n,error:o}).catch(()=>{}),await rw({sessionName:t,from:e,to:n,status:"failed",error:o})}}async function rw(t){if(du)try{await du(t)}catch{}}var uu,EE,ew,nw,du,fu=M(()=>{Ke();uu=AE(TE),EE=Number(process.env.BOSTRAT_CODEX_UPDATE_TIMEOUT_MS)||5*6e4,ew=new Set,nw=Promise.resolve(),du=null});function $E(t,{provider:e,box:n}){let r=String(t).replace(/\r/g,"").split(`
55
- `);if(!aw.test(t))return null;let o=[],s=!1;for(let l=r.length-1;l>=0;l--){let u=r[l].match(RE);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"&&aw.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(lw.test(n[r]))return n.slice(r).join(`
57
- `);return e}function OE(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 CE(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 ME(t,e=""){let n=fr(t);if(Ts.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(iw);if(!u)continue;s<0&&(s=l);let d="";for(let f=l+1;f<Math.min(l+3,r.length);f++){let h=r[f].trim();if(h){if(iw.test(r[f])||/^Press enter/.test(h))break;d=h;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&&!lw.test(r[l])&&OE(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=CE(l.label);return{label:l.label,description:[l.desc,u].filter(Boolean).join(" \xB7 ")}})}]}}function BE(t,e=""){let n=fr(t);if(Ts.test(n)||!NE.test(n))return null;let r=n.trimEnd().split(`
59
- `).pop()||"";return PE.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 jE(t,e=""){let n=fr(t);if(Ts.test(n)||!cw.test(n))return null;let r=n.split(`
60
- `),o=r.findIndex(i=>cw.test(i)),s="";for(let i=o+1;i<r.length;i++){let c=r[i].match(DE);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 LE(t,e=""){let n=fr(t);return Ts.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 FE(t,e=""){let n=fr(t);return Ts.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 UE(t,e=""){let n=String(t);if(!/Press any key to log in/.test(n)||pu.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 WE(t,e=""){let n=String(t);if(!HE.test(n)||pu.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 qE(t,e=""){let n=String(t);return!/Scan this QR code to log in/.test(n)||pu.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 uw(t,e,n=""){if(t!=="cursor"&&t!=="codex")return null;if(t==="codex"){let r=BE(e,n)||jE(e,n)||LE(e,n)||FE(e,n)||ME(e,n);if(r)return r}if(t==="cursor"){let r=WE(e,n)||qE(e,n)||UE(e,n);if(r)return r}return $E(e,{provider:t,box:n})}function dw(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 RE,aw,Ts,lw,iw,NE,PE,cw,DE,pu,HE,Ei=M(()=>{RE=/^\s*[›>*\-❯]?\s*(\d+)[.)]\s+(.+?)\s*$/,aw=/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i;Ts=/(^|\n)\s*›/,lw=/^\s*Welcome to Codex\b/;iw=/^\s*(>)?\s*(\d+)\.\s+(.+?)\s*$/;NE=/Successfully logged in\./,PE=/^\s*Press Enter to continue\.\s*$/;cw=/Enter this one-time code/,DE=/^\s*([A-Z0-9]{2,10}-[A-Z0-9]{2,10})\s*$/;pu=/Run Everything|Add a follow-up|Plan, search, build anything/;HE=/click this link to log in|Signing in with the browser/});function zE(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(VE);return{from:r?.[1]||null,to:r?.[2]||null}}function _n(t){return new Promise(e=>setTimeout(e,t))}function fw(t,e){let n=Date.now(),r=JE();for(let[s,a]of _i)n-a>=r&&_i.delete(s);let o=`${t}::${e}`;return _i.has(o)?!1:(_i.set(o,n),!0)}function ZE(t){let e=0;for(let n of String(t).split(`
63
- `))XE.test(n)&&(e=Math.max(e,n.trimEnd().length));return e}function hu(t,e){let n=jt[t];if(!n?.busy)return{state:"idle",reason:null};if(gu(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=ZE(e);return t==="claude"&&r>0&&r<YE?{state:"unknown",reason:"narrow"}:{state:"idle",reason:null}}function wu(t,e){return hu(t,e).state}function mw(t,e){if(t!=="claude")return!1;let n=String(e||"").split(`
64
- `).slice(-t_).join(`
65
- `);return QE.test(n)}function Es(t,e){return wu(t,e)==="busy"}function Ii(t,e){return wu(t,e)!=="idle"}function Ri(t,e){let n=jt[t];return n?.up?n.up.test(e):!0}function e_(t,e){let n=jt[t];return n?gu(t,e)?!1:n.up.test(e)&&wu(t,e)==="idle":!0}function gu(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 pw(t,e,n){let r=Date.now()+n,o=0;for(await dr(t).catch(()=>{});;){let s=await Tt(t);if(e_(e,s)){await _n(As);return}if(e==="cursor"&&GE.test(s)&&!jt.cursor.up.test(s)&&o<3){if(!fw(t,"cursor-trust")){await _n(mu);continue}o+=1,await V({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(As);continue}if(e==="codex"&&o<3){let a=zE(s);if(a){if(!fw(t,`codex-update:${a.from}->${a.to}`)){await _n(mu);continue}o+=1,await V({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"}),sw({sessionName:t,from:a.from,to:a.to}),await _n(As);continue}}if(Date.now()>r){if(gu(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'),V({flow:"agent-ready",phase:"blocked",sessionName:t,agent:e,timeoutMs:n,gateAccepts:o,error:a}).catch(()=>{}),new Error(a)}if(await eo(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 V({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.`),V({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(As);return}await _n(mu)}}function hw({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 _s({cwd:t,sessionName:e,agent:n,agentCmd:r}={}){let{realCodex:o,realCursor:s}=hw({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=KE()}={}){let{label:a,realClaude:i,realCodex:c,realCursor:l}=hw({agent:r,agentCmd:o});if(i&&t&&await gn(t),c&&t&&await Kr(t),l&&t&&await Gr(t),(i||c||l)&&n){await pw(n,a,s);return}let u=jt[r]?r:jt[a]?a:null;if(process.env.BOSTRAT_FAKE_POLL_READY==="1"&&n&&u){await pw(n,u,s);return}await _n(As)}var KE,mu,As,jt,GE,VE,JE,_i,YE,XE,QE,t_,$i=M(()=>{Kt();us();ei();ni();fu();Ei();Ke();KE=()=>Number(process.env.BOSTRAT_AGENT_READY_TIMEOUT_MS)||9e4,mu=Number(process.env.BOSTRAT_AGENT_READY_POLL_MS)||500,As=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/}},GE=/Trust this workspace|\[a\]\s*Trust/,VE=/Update available!\s*([\d][\w.-]*)\s*->\s*([\d][\w.-]*)/;JE=()=>Number(process.env.BOSTRAT_GATE_RESEND_MS)||3e3,_i=new Map;YE=68,XE=/^\s*[─━]{10,}\s*$/;QE=/\bWaiting for \d+\b[^\n]*\bto finish\b|\/workflows to (?:stop|monitor)\b/,t_=15});function $e(t){return t==="codex"?{enter:!0,submitDelayMs:n_}:t==="claude"?{enter:!0,submitDelayMs:r_}:{enter:!0}}var n_,r_,Is=M(()=>{n_=(()=>{let t=Number(process.env.BOSTRAT_CODEX_SUBMIT_SETTLE_MS??120);return Number.isFinite(t)&&t>=0?t:120})(),r_=(()=>{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 o_){let o=0;for(let s of s_[r])s.test(e)&&o++;o>0&&(!n||o>n.score)&&(n={category:r,score:o})}return n}function ww(t){let e=0,n=0;for(let[r,o]of Object.entries(t||{}))a_.has(r)&&(e+=o||0),i_.has(r)&&(n+=o||0);return e>=5&&n===0?{category:"research",score:1}:n>=3?{category:"feature-build",score:1}:null}function Rs(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 o_,s_,a_,i_,yu=M(()=>{o_=["bug-fix","orchestration","design","ops-infra","docs-writing","research","feature-build"],s_={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/]};a_=new Set(["Read","Grep","Glob","LS","WebSearch","WebFetch","NotebookRead"]),i_=new Set(["Edit","Write","MultiEdit","NotebookEdit"])});function kw(t){let e=Rs(String(t||"")).toLowerCase(),n=[];for(let r of e.split(/[^a-z0-9]+/))r.length<2||c_.has(r)||n.push(r);return n}function l_(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(bw(n,"user",o))}else if(n.type==="turn.agent"){if(!o)continue;e.push(bw(n,"assistant",o))}}return e}function bw(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 $s(t){let e=l_(t),n=new Map,r=new Array(e.length).fill(0),o=0;e.forEach((a,i)=>{let c=kw(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 Oi(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(kw(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,h=Math.log(1+(t.N-f+.5)/(f+.5));for(let[p,w]of d){let y=t.lengths[p],k=w+gw*(1-yw+yw*(y/(t.avgdl||1))),x=h*(w*(gw+1)/k);c.set(p,(c.get(p)||0)+x)}}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 gw,yw,c_,bu=M(()=>{yu();gw=1.5,yw=.75,c_=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 Ci from"node:fs/promises";import xw from"node:path";async function u_(t){let e=xw.join(t,".bostrat","events"),n;try{n=await Ci.readdir(e)}catch{return $s([])}let r=[];for(let o of n)if(o.endsWith(".ndjson"))try{let s=await Ci.readFile(xw.join(e,o),"utf8");for(let a of s.split(`
66
- `))if(a.trim())try{r.push(JSON.parse(a))}catch{}}catch{}return $s(r)}function d_(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 f_(t,e,{k:n=6,maxChars:r=4e3,exclude:o=null}={}){let s=Oi(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?["",`## ${Sw}, 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 vw(t,e,n={}){let{k:r=6,maxChars:o=4e3,exclude:s=null}=n;try{let a=await Ci.readFile(e,"utf8");if(a.includes(Sw))return{appended:!1,reason:"already-enriched"};let i=await u_(t);if(!i.N)return{appended:!1,reason:"empty-index"};let c=f_(i,d_(a),{k:r,maxChars:o,exclude:s});return c?(await Ci.appendFile(e,`
45
+ `,"utf8")}catch(e){console.warn(`[handoff-debug] failed to write ${no}: ${e?.message||e}`)}}async function z(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&&vi())try{e.paneTail=dr((await xt(e.sessionName,{lines:35})).slice(-4e3))}catch{e.paneTail=null}(vi()||e.error||/^(checkpoint|spawn|hydrate|commit|done|summarize|clear|resume|ready|send|failed|launch)/.test(String(e.phase||e.step||"")))&&await rE(e)}async function zh({limit:t=80}={}){try{return(await Rs.readFile(no,"utf8")).split(`
46
+ `).filter(Boolean).slice(-t).map(r=>{try{let o=JSON.parse(r);return typeof o?.paneTail=="string"&&(o.paneTail=dr(o.paneTail)),o}catch{return{raw:dr(r)}}})}catch{return[]}}var nE,iu,no,Gh,Jh,Ge=C(()=>{Gt();nE=[/[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];iu=process.env.BOSTRAT_DEBUG_DIR||Vh.join(eE.homedir(),".bostrat","debug"),no=Vh.join(iu,"handoff.jsonl"),Gh=Number(process.env.BOSTRAT_HANDOFF_DEBUG_MAX)||500;Jh={DEBUG_DIR:iu,LOG_FILE:no}});import{execFile as oE}from"node:child_process";import{promisify as sE}from"node:util";import Ti from"node:fs";import{randomUUID as aE}from"node:crypto";function so(t){return new Promise(e=>setTimeout(e,t))}function Si(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 Xh(t){return`/tmp/tmux-${t}/default`}function iE({explicit:t,legacyExists:e,runtimeDir:n,uid:r}){if(t)return t;let o=Xh(r);return e?o:n?`${n}/bostrat/tmux-default`:o}function uu(){return process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1"?[]:["-e",`${lE}=1`]}function fu(t,e,n){let r=fr(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&&St(n)&&(s+=` --name ${n}`),s}function fr(t){return/(^|\/|\s)claude(\s|$)/.test(String(t||""))}function En(t){return/(^|\/|\s)claude(\s|$)/.test(t)?"claude":/cursor/.test(t)?"cursor":/codex/.test(t)?"codex":/gemini/.test(t)?"gemini":"agent"}function dE(t){let e=String(t||"").trim();return!e||/fake-|\.sh(\s|$)/.test(e)?!1:fr(e)||/(^|\/|\s)codex(\s|$)/.test(e)||/cursor-agent/.test(e)||/(^|\/|\s)gemini(\s|$)/.test(e)}async function Zh(t,{loginShell:e=!1,failOpen:n=!1}={}){let r=await Qh(t,{loginShell:e});return r===Ai?!0:r===ro?!1:n}async function Qh(t,{loginShell:e=!1,timeoutMs:n=cu}={}){if(!t)return ro;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}),Ai}catch(s){return s?.killed||s?.signal?oo:s?.code===1||s?.code===127?ro:oo}}async function Ei(t,{retries:e=fE,sleep:n=pE,probe:r=Qh}={}){let o=String(t||"").trim().split(/\s+/)[0],s=await r(o,{timeoutMs:cu});for(let a=0;s===oo&&a<e.length;a++)await n(e[a]),s=await r(o,{timeoutMs:cu*2});return s}function H(...t){return["-S",re,...t]}async function _n(){if(!Ti.existsSync(re))return!1;try{return await ft(L,H("list-sessions")),!0}catch(t){let e=t&&t.stderr?String(t.stderr):"";return!/no server running/i.test(e)}}async function $s(){if(await _n())return!0;try{Ti.mkdirSync(re.replace(/\/[^/]+$/,""),{recursive:!0}),await ft(L,H("new-session","-d","-s","keeper","sleep 2147483647"))}catch{}return await _n()}function St(t){return typeof t=="string"&&mE.test(t)}async function be(){if(!Ti.existsSync(re))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,H("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("|"),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:d||null,agent:f||(l==="1"?"claude":null),alternateOn:p==="1"}}).filter(r=>!uE.has(r.name)&&!r.name.startsWith("bostrat-view-"))}catch{return[]}}async function nt(t){return(await be()).find(n=>n.name===t)||null}function gE(t){if(typeof t!="string")return!1;let e=t.trim();return e.length>=1&&e.length<=wE&&hE.test(e)}function _i(t){return t.trim().replace(/\s+/g,"-").toLowerCase().replace(/[^A-Za-z0-9_.-]/g,"").replace(/^-+|-+$/g,"")}async function tw(t){try{let{stdout:e}=await ft(L,H("list-sessions","-F","#{session_name}"));return e.split(`
48
+ `).map(n=>n.trim()).includes(t)}catch{return!1}}function xE(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 vE(t,e){let n=Date.now()+yE(),r=xE(e),o=!1,s=0;for(;;){if(await so(bE),s+=1,!await tw(t))return;let a=await xt(t,{lines:15}),i=!o&&kE.test(a)&&!!r?.test(a);if(!i&&s>1&&!await ao(t))return;if(i){o=!0,await z({flow:"spawn",phase:"launch-retry",sessionName:t,agent:En(e),promptHead:e.slice(0,120)}).catch(()=>{}),await ft(L,H("send-keys","-t",t,"C-u")),await ft(L,H("send-keys","-t",t,"-l",e)),await ft(L,H("send-keys","-t",t,"Enter"));continue}if(Date.now()>n){await z({flow:"spawn",phase:"launch-failed",sessionName:t,agent:En(e),retried:o,error:"agent CLI never started after launch was typed"}).catch(()=>{});return}}}async function In(t,e=cE,n={}){if(!gE(t))throw new Error("displayName must be 1\u201364 chars (letters, digits, space . _ -)");let r=t.trim(),o=_i(r);if(!St(o))throw new Error("resulting tmux session name is invalid");if(!await $s())throw new Error(`host tmux server not running on ${re} and auto-start failed \u2014 start one: ${L} -S ${re} new-session -d -s keeper "sleep 2147483647"`);if(await tw(o))throw new Error(`tmux session "${o}" already exists`);let s=n.agentCmd||lu,a=n.agent||En(s),i=!!n.resumeSessionId,c=n.resumeSessionId||aE(),l=i?s:fu(s,c,o),u=i?n.pinned===!0:/(^|\s)--session-id(\s|=)/.test(l),d=a==="claude"&&fr(s),f=n.firstRun===!0;f||(d&&await kn(e),a==="codex"&&await Yr(e),a==="cursor"&&await Xr(e),await Oh(e),await ki(e));let p=d&&!f?ai():null,h=sh(),w=["-e",`${oi}=${h}`];p&&w.push("-e",`ANTHROPIC_API_KEY=${p}`),d&&w.push(...uu());try{await ft(L,H("new-session","-d","-s",o,"-c",e,...w))}catch(y){throw Si(p?Si(y,p):y,h)}return await pr(o),await ft(L,H("set-option","-t",o,"@bostrat-session","1")),await ft(L,H("set-option","-t",o,"@bostrat-title",r)),await ft(L,H("set-option","-t",o,"@bostrat-sid",c)),await ft(L,H("set-option","-t",o,"@bostrat-agent",a)),await ft(L,H("send-keys","-t",o,l,"Enter")),dE(l)&&vE(o,l).catch(()=>{}),{name:o,title:r,cwd:e,sessionId:c,agent:a,pinned:u,hookToken:h}}async function $e(t){if(!St(t))throw new Error("invalid session name");await ft(L,H("kill-session","-t",t))}async function ew(t,e){if(St(t))try{let n=e?H("set-option","-t",t,"@bostrat-sid",e):H("set-option","-u","-t",t,"@bostrat-sid");await ft(L,n)}catch{}}async function xt(t,{lines:e=40}={}){if(!St(t))return"";try{let n=H("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 nw(t){if(!St(t))return 0;try{let{stdout:e}=await ft(L,H("list-clients","-t",t,"-F","1"));return String(e||"").trim().split(`
49
+ `).filter(Boolean).length}catch{return 0}}async function pr(t,{cols:e=AE,rows:n=EE}={}){if(!St(t))return!0;if(await nw(t))return!1;try{let r=await rw(t);if(r.cols===e&&r.rows===n)return!0;await ft(L,H("resize-window","-t",t,"-x",String(e),"-y",String(n))),await ft(L,H("set-window-option","-t",t,"window-size","latest")),await so(80)}catch{}return!0}async function _E(t){if(!St(t))return 0;try{let{stdout:e}=await ft(L,H("display-message","-t",t,"-p","#{pane_pid}"));return Number(String(e||"").trim())||0}catch{return 0}}async function ao(t){let e=await _E(t);if(!e)return!1;try{return await ft("pgrep",["-P",String(e)]),!1}catch(n){return n?.code===1}}async function rw(t){if(!St(t))return{cols:0,rows:0};try{let{stdout:e}=await ft(L,H("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 Ii(t,{cols:e=SE,rows:n=TE}={}){if(St(t)&&!await nw(t))try{let r=await rw(t),o=Math.max(r.cols,e),s=Math.max(r.rows,n);(o>r.cols||s>r.rows)&&(await ft(L,H("resize-window","-t",t,"-x",String(o),"-y",String(s))),await ft(L,H("set-window-option","-t",t,"window-size","latest")),await so(80))}catch{}}async function Ve(t){return await Ii(t),xt(t,{lines:Nt})}async function _t(t,e,{settleMs:n=40,kind:r}={}){if(!St(t))throw new Error("invalid session name");let o=(Array.isArray(e)?e:[e]).filter(s=>IE.has(s));for(let s=0;s<o.length;s++)await ft(L,H("send-keys","-t",t,o[s])),n>0&&s<o.length-1&&await so(n);return z({flow:"tmux",phase:"send-keys",sessionName:t,kind:r||"keys",keys:o.join(" ")}).catch(()=>{}),o.length}async function io(t,e,{kind:n}={}){if(!St(t))throw new Error("invalid session name");let r=Math.max(0,Math.floor(Number(e)||0));return r>0&&await ft(L,H("send-keys","-t",t,"-N",String(r),"BSpace")),z({flow:"tmux",phase:"send-keys",sessionName:t,kind:n||"wipe",keys:`BSpace x${r}`}).catch(()=>{}),r}async function $i(t,e,{perCharDelayMs:n=120,kind:r}={}){if(!St(t))throw new Error("invalid session name");let o=[...String(e)];for(let s of o)await ft(L,H("send-keys","-t",t,"-l",s)),n>0&&await so(n);z({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(!St(t))throw new Error("invalid session name");if(typeof e=="string"&&e.length>0&&await ft(L,H("send-keys","-t",t,"-l",e)),n){let s=Number(r);Number.isFinite(s)&&s>0&&await so(s),await ft(L,H("send-keys","-t",t,"Enter"))}z({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,Yh,re,cE,lu,lE,du,uE,Ai,ro,oo,cu,fE,pE,pu,mE,hE,wE,yE,bE,kE,SE,TE,Nt,AE,EE,IE,Ri,Gt=C(()=>{bs();ci();li();wi();xi();Ge();ys();ft=sE(oE);L=process.env.BOSTRAT_TMUX_BIN||"/usr/bin/tmux";Yh=typeof process.getuid=="function"?process.getuid():0,re=iE({explicit:process.env.BOSTRAT_TMUX_SOCKET,legacyExists:(()=>{try{return Ti.existsSync(Xh(Yh))}catch{return!1}})(),runtimeDir:process.env.XDG_RUNTIME_DIR,uid:Yh}),cE=process.env.BOSTRAT_DEFAULT_CWD||process.env.HOME||"/",lu=process.env.BOSTRAT_AGENT_CMD||"claude --dangerously-skip-permissions",lE="CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN";du="bostrat-usage-probe",uE=new Set([du]);Ai="present",ro="absent",oo="unknown",cu=5e3,fE=[250,1e3,3e3],pE=t=>new Promise(e=>setTimeout(e,t));pu={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"};mE=/^[A-Za-z0-9_.-]{1,64}$/;hE=/^[A-Za-z0-9 ._↻-]+$/,wE=64;yE=()=>Number(process.env.BOSTRAT_LAUNCH_VERIFY_MS)||12e3,bE=1e3,kE=/not found|Unknown command/i;SE=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,AE=Number(process.env.BOSTRAT_BOX_COLS)||120,EE=Number(process.env.BOSTRAT_BOX_ROWS)||40;IE=new Set(["Up","Down","Left","Right","Space","Enter","Tab","BTab","Escape","BSpace"]);Ri=1600});import Os from"node:fs";import NE from"node:fs/promises";import co from"node:path";import PE from"node:os";function wu(t){return t.replace(/[^A-Za-z0-9]/g,"-")}function gu(t){let e=co.join(hu,wu(t)),n;try{n=Os.readdirSync(e).filter(o=>o.endsWith(".jsonl"))}catch{return null}let r=null;for(let o of n){let s=co.join(e,o);try{let{mtimeMs:a}=Os.statSync(s);(!r||a>r.mtimeMs)&&(r={full:s,mtimeMs:a})}catch{}}return r?r.full:null}function ze(t,e){if(!e)return null;let n=co.join(hu,wu(t),`${e}.jsonl`);return Os.existsSync(n)?n:null}function uw(t){if(!t)return[];let e=co.join(hu,wu(t)),n;try{n=Os.readdirSync(e).filter(o=>o.endsWith(".jsonl"))}catch{return[]}let r=[];for(let o of n)try{let s=Os.statSync(co.join(e,o));r.push({id:o.slice(0,-6),birthMs:s.birthtimeMs||s.ctimeMs||s.mtimeMs})}catch{}return r}async function Zt(t,e=131072){let n=await NE.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 DE(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 Cs(t,e=null,{fallbackNewest:n=!0}={}){if(!t)return null;let r,o;if(e){if(r=ze(t,e),o=!0,!r)return null}else if(n){if(r=gu(t),o=!1,!r)return null}else return null;let s;try{s=DE(await Zt(r))}catch{return null}if(!s)return null;let a=Object.prototype.hasOwnProperty.call(lw,s.model),i=lw[s.model]||BE;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 lw,BE,hu,ke=C(()=>{lw={"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},BE=2e5,hu=process.env.BOSTRAT_CLAUDE_PROJECTS||co.join(PE.homedir(),".claude","projects")});function jE(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===`
51
+ `){e.push(n),n="";continue}n+=s}return e.push(n),e.map(o=>o.trim()).filter(Boolean)}function Ms(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 Ns(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 yt(t,e=new Set){let n=[];for(let r=1;r<t.length;r++){let o=t[r];if(o==="<<")break;if(pw(o)){e.has(o)&&r++;continue}n.push(o)}return n}function mw(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 UE(t){let e=mw(t),n=Ft(yt(t).find(r=>!/^\d+(,\d+)?p$/.test(r)));return e&&n?e.from===e.to?`Read line ${e.from} of ${Tt(n)}`:`Read lines ${e.from}\u2013${e.to} of ${Tt(n)}`:t.includes("-i")&&n?`Edit ${Tt(n)}`:null}function yu(t){if(t.includes("--files")){let s=Ft(yt(t,dw)[0]);return s&&s!=="."?`List files in ${lo(s)}`:"List files"}let e=yt(t,dw),n=e[0];if(!n)return null;let r=Ft(e.slice(1).find(s=>s!==".")),o=uo(n,40);return r?`Search for \u201C${o}\u201D in ${lo(r)}`:`Search for \u201C${o}\u201D`}function bu(t){let e=yt(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 ku(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=yt(t)[0];return n?`Run ${Tt(n)}`:null}function HE(t){let e=yt(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 fw(t){return t.find(e=>/^https?:\/\//.test(e))||null}function KE(t){let e=Ns(Ms(t));if(!e.length)return null;if(/^(ba|z)?sh$/.test(Tt(e[0]))&&(e[1]==="-lc"||e[1]==="-c")&&e[2])return xu(e[2]);let n=Tt(e[0]);if(qE.has(n))return null;if(e.includes("--version"))return`Check ${n} version`;if(n.endsWith(".sh"))return`Run ${n}`;let r=WE[n];return r?r(e.map((o,s)=>s===0?n:o)):null}function xu(t){let e=String(t||"").trim();if(!e)return null;let n=e.indexOf("<<");if(n!==-1){let i=e.indexOf(`
52
+ `,n);i!==-1&&(e=e.slice(0,i))}let r=jE(e);for(let i=0;i<r.length-1;i++){let c=Ns(Ms(r[i])),l=Ns(Ms(r[i+1]));if(!(!c.length||!l.length)&&["nl","cat"].includes(Tt(c[0]))&&Tt(l[0])==="sed"){let u=mw(l),d=yt(c)[0];if(u&&d)return uo(u.from===u.to?`Read line ${u.from} of ${Tt(d)}`:`Read lines ${u.from}\u2013${u.to} of ${Tt(d)}`,88)}}let o=[];for(let i of r){let c=KE(i);c&&o.push({d:c,head:Tt(Ns(Ms(i))[0]||""),sub:yt(Ns(Ms(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":uo(s?s.d:o[0].d,88)}var uo,Ft,Tt,lo,pw,dw,LE,FE,WE,qE,hw=C(()=>{uo=(t,e)=>t.length>e?`${t.slice(0,e).trimEnd()}\u2026`:t,Ft=t=>t&&!/[$`]/.test(t)?t:null,Tt=t=>t.replace(/\/+$/,"").split("/").pop()||t,lo=t=>{let e=t.replace(/\/+$/,"").split("/").filter(Boolean);return e.length>3?e.slice(-2).join("/"):t},pw=t=>t.startsWith("-"),dw=new Set(["-g","--glob","-t","--type","-A","-B","-C","-m","--max-count","-e","--regexp","-f","--file"]);LE={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 ${Tt(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"},FE={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"};WE={git:t=>{let e=yt(t,new Set(["-C","-c"])),n=LE[e[0]];return n?n(e,t):null},gh:t=>{let e=yt(t),n=FE[e[0]];return n?n(e):null},sed:UE,rg:yu,grep:yu,egrep:yu,nl:t=>{let e=Ft(yt(t)[0]);return e?`Read ${Tt(e)}`:null},cat:t=>{let e=Ft(yt(t)[0]);return e?`Read ${Tt(e)}`:null},head:t=>{let e=Ft(yt(t,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return e?`Read the start of ${Tt(e)}`:null},tail:t=>{let e=Ft(yt(t,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return e?`Read the end of ${Tt(e)}`:null},wc:t=>{let e=Ft(yt(t)[0]);return e?`Count lines in ${Tt(e)}`:"Count input lines"},ls:t=>{let e=Ft(yt(t)[0]);return e&&e!=="."?`List files in ${lo(e)}`:"List files"},find:t=>Ft(t[1])&&!pw(t[1])&&t[1]!=="."?`Find files in ${lo(t[1])}`:"Find files",tree:()=>"List the directory tree",mkdir:t=>{let e=Ft(yt(t)[0]);return e?`Create directory ${lo(e)}`:null},touch:t=>{let e=Ft(yt(t)[0]);return e?`Create ${Tt(e)}`:null},rm:t=>{let e=Ft(yt(t)[0]);return e?`Delete ${lo(e)}`:null},mv:t=>{let e=Ft(yt(t)[0]);return e?`Move ${Tt(e)}`:null},cp:t=>{let e=Ft(yt(t)[0]);return e?`Copy ${Tt(e)}`:null},chmod:t=>{let e=Ft(yt(t)[1]);return e?`Change permissions on ${Tt(e)}`:null},diff:t=>{let e=yt(t);return e.length>=2?`Compare ${Tt(e[0])} and ${Tt(e[1])}`:null},curl:t=>{let e=fw(t);return e?`Fetch ${uo(e,56)}`:"Fetch a URL"},wget:t=>{let e=fw(t);return e?`Fetch ${uo(e,56)}`:"Fetch a URL"},npm:bu,pnpm:bu,yarn:bu,npx:t=>{let e=yt(t)[0];return e?`Run ${e}`:null},node:t=>ku(t,"Node"),python:t=>ku(t,"Python"),python3:t=>ku(t,"Python"),make:t=>{let e=yt(t)[0];return e?`Run make ${e}`:"Run make"},systemctl:HE,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=yt(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=yt(t)[0];return e?`Locate ${e}`:null},command:t=>t[1]==="-v"&&t[2]?`Locate ${t[2]}`:null,fly:t=>{let e=yt(t)[0];return e==="deploy"?"Deploy to Fly":e?`Run fly ${e}`:null}},qE=new Set(["pwd","echo","cd","sleep","true","false","test","[","set","export","exit","read"])});function fo(t){let e=t.split(`
53
+ `).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||xu(t)||fo(t)}function vu(t,e){if(t){if(Array.isArray(t)){for(let n of t)vu(n,e);return}if(typeof t=="object"){if(t.type==="tool_use"&&Su.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))vu(n,e)}}}async function ww(t,{maxBytes:e=1048576,limit:n=400}={}){let r;try{r=await Zt(t,e)}catch{return[]}let o=[];for(let s of r.split(`
54
+ `)){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(vu(c.content,l),!l.length)continue;let u=i.timestamp?Date.parse(i.timestamp):null;for(let d of l)o.push({...d,summary:Rn(d.command,d.description),ts:u})}return o.slice(-n)}function gw(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)),d=u===-1?r.length:u,f=r.slice(s,d);if(s=d,!f.length)continue;let p=f.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 Su,po=C(()=>{ke();hw();Su=new Set(["Bash"])});import yw from"node:fs";import Au from"node:fs/promises";import Tu from"node:path";import GE from"node:os";async function bw(t){try{return await Au.realpath(t)}catch{return t}}function zE(t=VE){let e=[],n=r=>{let o;try{o=yw.readdirSync(r,{withFileTypes:!0})}catch{return}for(let s of o){let a=Tu.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:yw.statSync(a).mtimeMs})}catch{}}}};return n(t),e.sort((r,o)=>o.mtimeMs-r.mtimeMs)}async function JE(t,e=1048576){let n;try{n=await Au.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(`
55
+ `);if(i!==-1)return o.slice(0,i);if(s+=a,o.length>=e)break}return o}finally{await n.close()}}async function YE(t){let e=await JE(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=zE();if(e){let o=n.find(s=>s.id===e);return o||null}let r=await bw(t);for(let o of n){let s=await YE(o.file);if(s&&(s===t||await bw(s)===r))return o}return null}async function kw(t,e,{limit:n=80,maxBytes:r=524288}={}){let o=await mr(t,e);if(!o)return[];let s;try{s=await Zt(o.file,r)}catch{return[]}let a=[],i=null,c=[],l=!1,u=!1,d=null;for(let f of s.split(`
56
+ `)){let p=f.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,d=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:hr,sourceId:h.payload?.turn_id||d||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,Eu.has(w.name)||c.push(w.name);continue}if(w.type!=="message"||w.role!=="assistant")continue;u=!0;let y=ZE(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 f of a)f.model||(f.model=i);return a.slice(-n)}function QE(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 t_(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+=`
57
+ `;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 e_(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=t_(i.slice(c.index+c[0].length).trimStart());l&&l.trim()&&o.push(l.trim())}),o}async function xw(t,e,{limit:n=400,maxBytes:r=524288}={}){let o=await mr(t,e);if(!o)return[];let s;try{s=await Zt(o.file,r)}catch{return[]}let a=[];for(let i of s.split(`
58
+ `)){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"&&Ps.has(u.name)){let p;try{p=JSON.parse(u.arguments||"{}")}catch{continue}let h=QE(p);h&&(d=[h])}else u.type==="custom_tool_call"&&u.name==="exec"&&(d=e_(u.input));if(!d.length)continue;let f=u.call_id||u.id||null;d.forEach((p,h)=>{a.push({id:f?h?`${f}:${h}`:f:null,tool:u.name,command:p,description:"",summary:Rn(p),ts:l.timestamp?Date.parse(l.timestamp):null})})}return a.slice(-n)}async function vw(t,e){let n=await mr(t,e);if(!n)return null;try{return Math.round((await Au.stat(n.file)).mtimeMs)}catch{return n.mtimeMs||null}}var VE,XE,ZE,Ps,Eu,hr,wr=C(()=>{ke();po();VE=process.env.BOSTRAT_CODEX_SESSIONS||Tu.join(process.env.CODEX_HOME||Tu.join(GE.homedir(),".codex"),"sessions");XE=new Set(["output_text","text"]),ZE=t=>typeof t=="string"?t.trim():Array.isArray(t)?t.filter(e=>e&&typeof e.text=="string"&&XE.has(e.type)).map(e=>e.text).join(`
59
+ `).trim():"";Ps=new Set(["exec_command","shell","exec"]),Eu=new Set(["wait","write_stdin"]),hr="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 Bs({error:t=null,status:e=null,text:n=""}={}){let r=String(t||"").trim().toLowerCase();if(r&&Sw.has(r))return Sw.get(r);let o=Number(e)||0;if(o===401)return"auth";if(o===403)return"entitlement";if(o===429)return"rate_limit";if(o===529)return"overloaded";if(o>=500)return"server";let s=String(n||"").toLowerCase();return/overloaded/.test(s)?"overloaded":/rate limit|too many requests|quota|usage limit/.test(s)?"rate_limit":/billing|subscription|not allowed|disabled .* access|upgrade your plan|no credits/.test(s)?"entitlement":/log ?in|authenticat|expired|invalid.*key|unauthorized/.test(s)?"auth":/server|internal error|5\d\d/.test(s)?"server":"other"}function Tw(t){if(!t||t.role!=="assistant")return null;if(t.apiError){let e=t.apiError;return{cls:e.cls||Bs({error:e.code,status:e.status,text:t.text}),code:e.code||null,status:e.status||null,requestId:e.requestId||null}}if(t.failed){let e=String(t.text||"");return{cls:e===hr?"other":Bs({text:e}),code:null,status:null,requestId:null}}return null}function Aw(t,{codexFailedText:e=null}={}){let n=String(t?.text||"").trim();return n?t?.model==="<synthetic>"?/^No response requested\.$/.test(n)?null:{cls:Bs({text:n}),code:null,status:n_(n),requestId:null,text:n}:e&&n===e?{cls:"other",code:null,status:null,requestId:null,text:n}:null:null}function n_(t){let e=/^API Error:\s*(\d{3})\b/.exec(t);return e?Number(e[1]):null}var VF,Sw,Ci=C(()=>{wr();VF=Object.freeze(["entitlement","auth","rate_limit","overloaded","server","other"]),Sw=new Map([["oauth_org_not_allowed","entitlement"],["permission_error","entitlement"],["billing_error","entitlement"],["authentication_error","auth"],["oauth_token_expired","auth"],["invalid_api_key","auth"],["rate_limit_error","rate_limit"],["overloaded_error","overloaded"],["server_error","server"],["api_error","server"],["internal_server_error","server"]])});function r_(t,e){return!t||!e?null:ze(t,e)}function o_(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(`
60
+ `).trim():""}function s_(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 a_(t){return Array.isArray(t)&&t.length>0&&t.every(e=>e&&e.type==="tool_result")}function _u(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 Ew(t,e){if(!t.uuid)return null;let n=_u(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 Iu(t,{maxBytes:e=524288,limit:n=80}={}){let r;try{r=await Zt(t,e)}catch{return[]}let o=[],s=new Map;for(let a of r.split(`
61
+ `)){let i=a.trim();if(!i||i[0]!=="{")continue;let c;try{c=JSON.parse(i)}catch{continue}if(c.type==="attachment"){let w=c.attachment;w?.type==="queued_command"&&w.commandMode==="task-notification"&&typeof w.prompt=="string"&&w.prompt.trim()&&o.push({role:"user",text:w.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 w of l.content){let y=w?.type==="tool_use"?w.input?.file_path||w.input?.path:null;typeof y=="string"&&i_.test(y)&&s.set(w.id,y.split("/").pop())}if(a_(l.content)){let w=Ew(c,s);w&&o.push({role:"assistant",text:"",images:w,ts:c.timestamp?Date.parse(c.timestamp):null,model:null});continue}let d=o_(l.content),f=u==="assistant"?s_(l.content):null,p=u==="user"?Ew(c,s):null;if(!d&&!f&&!p)continue;let h=u==="assistant"&&c.isApiErrorMessage?{code:typeof c.error=="string"?c.error:null,status:Number(c.apiErrorStatus)||null,requestId:c.requestId||null,cls:Bs({error:c.error,status:c.apiErrorStatus,text:d})}:null;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,apiError:h||void 0})}return o.slice(-n)}async function _w(t,e,{turns:n=16}={}){let r=r_(t,e);if(!r)return"";let o=await Iu(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}:** ${c_(s.text||c,700)} ${i}`.trim()}).join(`
62
+
63
+ `):""}var i_,c_,Mi=C(()=>{Ci();ke();i_=/\.(png|jpe?g|gif|webp|bmp|svg|tiff?|avif|heic|heif|ico)$/i;c_=(t,e)=>t.length>e?`${t.slice(0,e).trimEnd()}\u2026`:t});import l_ from"node:fs/promises";import{execFile as u_}from"node:child_process";import{promisify as d_}from"node:util";function Ow(t){$u=typeof t=="function"?t:null}function p_(t){let e=String(t||""),n=e.indexOf("/lib/node_modules/");return n>0?e.slice(0,n):null}function Cw({sessionName:t,from:e,to:n}={}){let r=String(n||"").trim();!r||Iw.has(r)||(Iw.add(r),Rw=Rw.then(()=>m_({sessionName:t,from:e,to:r})).catch(()=>{}))}async function m_({sessionName:t,from:e,to:n}){await z({flow:"codex-update",phase:"start",sessionName:t,from:e,to:n}).catch(()=>{});try{let r=(await Ru("/bin/sh",["-c","command -v codex"])).stdout.trim();if(!r)throw new Error("codex not on PATH");let o=await l_.realpath(r),s=p_(o),a=s?{...process.env,PATH:`${s}/bin:${process.env.PATH||""}`}:process.env;await Ru("npm",["install","-g","@openai/codex"],{env:a,timeout:f_});let i=(await Ru(r,["--version"])).stdout.trim().replace(/^codex-cli\s*/,"")||n;await z({flow:"codex-update",phase:"done",sessionName:t,from:e,to:n,version:i}).catch(()=>{}),await $w({sessionName:t,from:e,to:n,version:i,status:"updated"})}catch(r){let o=String(r?.message||r).slice(0,300);await z({flow:"codex-update",phase:"failed",sessionName:t,from:e,to:n,error:o}).catch(()=>{}),await $w({sessionName:t,from:e,to:n,status:"failed",error:o})}}async function $w(t){if($u)try{await $u(t)}catch{}}var Ru,f_,Iw,Rw,$u,Ou=C(()=>{Ge();Ru=d_(u_),f_=Number(process.env.BOSTRAT_CODEX_UPDATE_TIMEOUT_MS)||5*6e4,Iw=new Set,Rw=Promise.resolve(),$u=null});function w_(t,{provider:e,box:n}){let r=String(t).replace(/\r/g,"").split(`
64
+ `);if(!Mw.test(t))return null;let o=[],s=!1;for(let l=r.length-1;l>=0;l--){let u=r[l].match(h_);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"&&Mw.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 gr(t){let e=String(t??"").replace(/\r/g,""),n=e.split(`
65
+ `);for(let r=n.length-1;r>=0;r--)if(Bw.test(n[r]))return n.slice(r).join(`
66
+ `);return e}function g_(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 y_(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 b_(t,e=""){let n=gr(t);if(Ds.test(n)||!/Sign in with ChatGPT/.test(n)||!/Press enter to continue/.test(n))return null;let r=n.split(`
67
+ `),o=[],s=-1;for(let l=0;l<r.length;l++){let u=r[l].match(Nw);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(Nw.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&&!Bw.test(r[l])&&g_(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=y_(l.label);return{label:l.label,description:[l.desc,u].filter(Boolean).join(" \xB7 ")}})}]}}function v_(t,e=""){let n=gr(t);if(Ds.test(n)||!k_.test(n))return null;let r=n.trimEnd().split(`
68
+ `).pop()||"";return x_.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 T_(t,e=""){let n=gr(t);if(Ds.test(n)||!Pw.test(n))return null;let r=n.split(`
69
+ `),o=r.findIndex(i=>Pw.test(i)),s="";for(let i=o+1;i<r.length;i++){let c=r[i].match(S_);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 A_(t,e=""){let n=gr(t);return Ds.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 E_(t,e=""){let n=gr(t);return Ds.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 __(t,e=""){let n=String(t);if(!/Press any key to log in/.test(n)||Cu.test(n))return null;let r=n.replace(/\r/g,"").split(`
70
+ `).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 R_(t,e=""){let n=String(t);if(!I_.test(n)||Cu.test(n))return null;let r=n.replace(/\r/g,"").split(`
71
+ `),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 $_(t,e=""){let n=String(t);return!/Scan this QR code to log in/.test(n)||Cu.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 Dw(t,e,n=""){if(t!=="cursor"&&t!=="codex")return null;if(t==="codex"){let r=v_(e,n)||T_(e,n)||A_(e,n)||E_(e,n)||b_(e,n);if(r)return r}if(t==="cursor"){let r=R_(e,n)||$_(e,n)||__(e,n);if(r)return r}return w_(e,{provider:t,box:n})}function jw(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 h_,Mw,Ds,Bw,Nw,k_,x_,Pw,S_,Cu,I_,Ni=C(()=>{h_=/^\s*[›>*\-❯]?\s*(\d+)[.)]\s+(.+?)\s*$/,Mw=/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i;Ds=/(^|\n)\s*›/,Bw=/^\s*Welcome to Codex\b/;Nw=/^\s*(>)?\s*(\d+)\.\s+(.+?)\s*$/;k_=/Successfully logged in\./,x_=/^\s*Press Enter to continue\.\s*$/;Pw=/Enter this one-time code/,S_=/^\s*([A-Z0-9]{2,10}-[A-Z0-9]{2,10})\s*$/;Cu=/Run Everything|Add a follow-up|Plan, search, build anything/;I_=/click this link to log in|Signing in with the browser/});function P_(t){let e=String(t||"");if(!Bt.codex.block.test(e))return null;let n=gr(e);if(!Bt.codex.block.test(n))return null;let r=n.match(N_);return{from:r?.[1]||null,to:r?.[2]||null}}function $n(t){return new Promise(e=>setTimeout(e,t))}function Lw(t,e){let n=Date.now(),r=B_();for(let[s,a]of Pi)n-a>=r&&Pi.delete(s);let o=`${t}::${e}`;return Pi.has(o)?!1:(Pi.set(o,n),!0)}function L_(t){let e=0;for(let n of String(t).split(`
72
+ `))j_.test(n)&&(e=Math.max(e,n.trimEnd().length));return e}function Nu(t,e){let n=Bt[t];if(!n?.busy)return{state:"idle",reason:null};if(Bu(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=L_(e);return t==="claude"&&r>0&&r<D_?{state:"unknown",reason:"narrow"}:{state:"idle",reason:null}}function Pu(t,e){return Nu(t,e).state}function Uw(t,e){if(t!=="claude")return!1;let n=String(e||"").split(`
73
+ `).slice(-U_).join(`
74
+ `);return F_.test(n)}function Ls(t,e){return Pu(t,e)==="busy"}function Bi(t,e){return Pu(t,e)!=="idle"}function Di(t,e){let n=Bt[t];return n?.up?n.up.test(e):!0}function H_(t,e){let n=Bt[t];return n?Bu(t,e)?!1:n.up.test(e)&&Pu(t,e)==="idle":!0}function Bu(t,e){let n=Bt[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,{bailOnDialog:r=!1}={}){let o=Date.now()+n,s=0;for(await pr(t).catch(()=>{});;){let a=await xt(t);if(H_(e,a)){await $n(js);return}if(r&&e==="claude"&&M_.test(a)&&!Bt.claude.up.test(a)){z({flow:"agent-ready",phase:"dialog",sessionName:t,agent:e,dialog:"resume-confirm"}).catch(()=>{});return}if(e==="cursor"&&C_.test(a)&&!Bt.cursor.up.test(a)&&s<3){if(!Lw(t,"cursor-trust")){await $n(Mu);continue}s+=1,await z({flow:"agent-ready",phase:"gate-accept",sessionName:t,agent:e,attempt:s}).catch(()=>{}),await Pt(t,"a",{enter:!1,kind:"cursor-trust-accept"}),await $n(js);continue}if(e==="codex"&&s<3){let i=P_(a);if(i){if(!Lw(t,`codex-update:${i.from}->${i.to}`)){await $n(Mu);continue}s+=1,await z({flow:"agent-ready",phase:"gate-accept",sessionName:t,agent:e,attempt:s,update:`${i.from} -> ${i.to}`}).catch(()=>{}),await Pt(t,"3",{enter:!1,kind:"codex-update-skip"}),Cw({sessionName:t,from:i.from,to:i.to}),await $n(js);continue}}if(Date.now()>o){if(Bu(e,a)){let i=`${e} is blocked on an interactive prompt`;throw e==="codex"?i=Bt.codex.auth.test(a)?"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"&&Bt.cursor.auth.test(a)?i="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"&&Bt.claude.auth.test(a)?i="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"&&Bt.claude.block.test(a)&&(i='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'),z({flow:"agent-ready",phase:"blocked",sessionName:t,agent:e,timeoutMs:n,gateAccepts:s,error:i}).catch(()=>{}),new Error(i)}if(await ao(t)){let i=`${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 z({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:t,agent:e,timeoutMs:n,gateAccepts:s,error:i}).catch(()=>{}),new Error(i)}console.warn(`[agent-ready] ${e} readiness unconfirmed in ${t} after ${n}ms \u2014 driving the box anyway.`),z({flow:"agent-ready",phase:"timeout",sessionName:t,agent:e,timeoutMs:n,gateAccepts:s,paneBlocked:!!Bt[e]?.block?.test(a),paneUp:!!Bt[e]?.up?.test(a),paneBusy:!!Bt[e]?.busy?.test(a)}).catch(()=>{}),await $n(js);return}await $n(Mu)}}function Hw({agent:t,agentCmd:e}={}){let n=e?En(e):En(t||"");return{label:n,realClaude:e?fr(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 Fs({cwd:t,sessionName:e,agent:n,agentCmd:r}={}){let{realCodex:o,realCursor:s}=Hw({agent:n,agentCmd:r});return!e||!o&&!s?null:On({cwd:t,sessionName:e,agent:n,agentCmd:r}).catch(()=>{})}async function On({cwd:t,sessionId:e,sessionName:n,agent:r,agentCmd:o,timeoutMs:s=O_(),bailOnDialog:a=!1}={}){let{label:i,realClaude:c,realCodex:l,realCursor:u}=Hw({agent:r,agentCmd:o});if(c&&t&&await kn(t),l&&t&&await Yr(t),u&&t&&await Xr(t),(c||l||u)&&n){await Fw(n,i,s,{bailOnDialog:a});return}let d=Bt[r]?r:Bt[i]?i:null;if(process.env.BOSTRAT_FAKE_POLL_READY==="1"&&n&&d){await Fw(n,d,s);return}await $n(js)}var O_,Mu,js,Bt,C_,M_,N_,B_,Pi,D_,j_,F_,U_,ji=C(()=>{Gt();bs();ci();li();Ou();Ni();Ge();O_=()=>Number(process.env.BOSTRAT_AGENT_READY_TIMEOUT_MS)||9e4,Mu=Number(process.env.BOSTRAT_AGENT_READY_POLL_MS)||500,js=Number(process.env.BOSTRAT_AGENT_READY_SETTLE_MS)||800,Bt={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/}},C_=/Trust this workspace|\[a\]\s*Trust/,M_=/Resume from summary/i,N_=/Update available!\s*([\d][\w.-]*)\s*->\s*([\d][\w.-]*)/;B_=()=>Number(process.env.BOSTRAT_GATE_RESEND_MS)||3e3,Pi=new Map;D_=68,j_=/^\s*[─━]{10,}\s*$/;F_=/\bWaiting for \d+\b[^\n]*\bto finish\b|\/workflows to (?:stop|monitor)\b/,U_=15});function Oe(t){return t==="codex"?{enter:!0,submitDelayMs:W_}:t==="claude"?{enter:!0,submitDelayMs:q_}:{enter:!0}}var W_,q_,Us=C(()=>{W_=(()=>{let t=Number(process.env.BOSTRAT_CODEX_SUBMIT_SETTLE_MS??120);return Number.isFinite(t)&&t>=0?t:120})(),q_=(()=>{let t=Number(process.env.BOSTRAT_CLAUDE_SUBMIT_SETTLE_MS??120);return Number.isFinite(t)&&t>=0?t:120})()});function yr(t){let e=String(t||"").toLowerCase();if(!e.trim())return null;let n=null;for(let r of K_){let o=0;for(let s of G_[r])s.test(e)&&o++;o>0&&(!n||o>n.score)&&(n={category:r,score:o})}return n}function Ww(t){let e=0,n=0;for(let[r,o]of Object.entries(t||{}))V_.has(r)&&(e+=o||0),z_.has(r)&&(n+=o||0);return e>=5&&n===0?{category:"research",score:1}:n>=3?{category:"feature-build",score:1}:null}function Hs(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 K_,G_,V_,z_,Du=C(()=>{K_=["bug-fix","orchestration","design","ops-infra","docs-writing","research","feature-build"],G_={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/]};V_=new Set(["Read","Grep","Glob","LS","WebSearch","WebFetch","NotebookRead"]),z_=new Set(["Edit","Write","MultiEdit","NotebookEdit"])});function Vw(t){let e=Hs(String(t||"")).toLowerCase(),n=[];for(let r of e.split(/[^a-z0-9]+/))r.length<2||J_.has(r)||n.push(r);return n}function Y_(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(Gw(n,"user",o))}else if(n.type==="turn.agent"){if(!o)continue;e.push(Gw(n,"assistant",o))}}return e}function Gw(t,e,n){let r=yr(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 Ws(t){let e=Y_(t),n=new Map,r=new Array(e.length).fill(0),o=0;e.forEach((a,i)=>{let c=Vw(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 Li(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(Vw(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[h,w]of d){let y=t.lengths[h],k=w+qw*(1-Kw+Kw*(y/(t.avgdl||1))),x=p*(w*(qw+1)/k);c.set(h,(c.get(h)||0)+x)}}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 qw,Kw,J_,ju=C(()=>{Du();qw=1.5,Kw=.75,J_=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 Fi from"node:fs/promises";import zw from"node:path";async function X_(t){let e=zw.join(t,".bostrat","events"),n;try{n=await Fi.readdir(e)}catch{return Ws([])}let r=[];for(let o of n)if(o.endsWith(".ndjson"))try{let s=await Fi.readFile(zw.join(e,o),"utf8");for(let a of s.split(`
75
+ `))if(a.trim())try{r.push(JSON.parse(a))}catch{}}catch{}return Ws(r)}function Z_(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}
76
+ ${o}`.trim()||e.slice(0,2e3)}function Q_(t,e,{k:n=6,maxChars:r=4e3,exclude:o=null}={}){let s=Li(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?["",`## ${Jw}, 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(`
77
+ `):""}async function Yw(t,e,n={}){let{k:r=6,maxChars:o=4e3,exclude:s=null}=n;try{let a=await Fi.readFile(e,"utf8");if(a.includes(Jw))return{appended:!1,reason:"already-enriched"};let i=await X_(t);if(!i.N)return{appended:!1,reason:"empty-index"};let c=Q_(i,Z_(a),{k:r,maxChars:o,exclude:s});return c?(await Fi.appendFile(e,`
69
78
  `+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 Sw,Tw=M(()=>{bu();Sw="Relevant prior discussion (verbatim, retrieved"});import ku from"node:fs/promises";import oo from"node:path";import p_ from"node:os";import{EventEmitter as m_}from"node:events";import{randomUUID as h_}from"node:crypto";function so(t){return t?.cwd?oo.join(t.cwd,".bostrat","events"):oo.join(xu,"events")}async function b_(t,e){if(!Mi.has(e)){let o=(await F(t,e)).reduce((s,a)=>a.seq>s?a.seq:s,0);Mi.set(e,o)}let n=Mi.get(e)+1;return Mi.set(e,n),n}function k_(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||!w_.has(e.type))throw new Error(`appendEvent: unknown event type "${e?.type}"`);if(e.actor&&!g_.has(e.actor))throw new Error(`appendEvent: bad actor "${e.actor}"`);if(e.source&&!y_.has(e.source))throw new Error(`appendEvent: bad source "${e.source}"`);let r=typeof t=="string"?oo.join(xu,"events"):so(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=k_(c,Number(e.payload?.ts??e.ts)||Date.now())}let s=await b_(r,n),a=e.userId??process.env.BOSTRAT_OWNER??null,i={id:e.id||h_(),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 ku.mkdir(r,{recursive:!0}),await ku.appendFile(Aw(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"?oo.join(xu,"events"):so(t));let o;try{o=await ku.readFile(Aw(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 Zt.on(n,e),()=>Zt.off(n,e)}var w_,g_,y_,Zt,xu,Aw,Mi,ot=M(()=>{w_=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","decision.recorded","changelog.published","stall.detected","error"]),g_=new Set(["user","agent","orchestrator","system","peer"]),y_=new Set(["hook","otel","statusline","transcript","pane","orchestrator","vendor"]),Zt=new m_;Zt.setMaxListeners(0);xu=process.env.BOSTRAT_STATE_DIR||oo.join(process.env.HOME||p_.tmpdir(),".bostrat");Aw=(t,e)=>oo.join(t,`${e}.ndjson`),Mi=new Map});function x_(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 Os(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 Cs(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 yt(t,e=new Set){let n=[];for(let r=1;r<t.length;r++){let o=t[r];if(o==="<<")break;if(Rw(o)){e.has(o)&&r++;continue}n.push(o)}return n}function $w(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 T_(t){let e=$w(t),n=Lt(yt(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 Su(t){if(t.includes("--files")){let s=Lt(yt(t,_w)[0]);return s&&s!=="."?`List files in ${ao(s)}`:"List files"}let e=yt(t,_w),n=e[0];if(!n)return null;let r=Lt(e.slice(1).find(s=>s!==".")),o=io(n,40);return r?`Search for \u201C${o}\u201D in ${ao(r)}`:`Search for \u201C${o}\u201D`}function vu(t){let e=yt(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 Tu(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=yt(t)[0];return n?`Run ${Et(n)}`:null}function A_(t){let e=yt(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 Iw(t){return t.find(e=>/^https?:\/\//.test(e))||null}function I_(t){let e=Cs(Os(t));if(!e.length)return null;if(/^(ba|z)?sh$/.test(Et(e[0]))&&(e[1]==="-lc"||e[1]==="-c")&&e[2])return Au(e[2]);let n=Et(e[0]);if(__.has(n))return null;if(e.includes("--version"))return`Check ${n} version`;if(n.endsWith(".sh"))return`Run ${n}`;let r=E_[n];return r?r(e.map((o,s)=>s===0?n:o)):null}function Au(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=x_(e);for(let i=0;i<r.length-1;i++){let c=Cs(Os(r[i])),l=Cs(Os(r[i+1]));if(!(!c.length||!l.length)&&["nl","cat"].includes(Et(c[0]))&&Et(l[0])==="sed"){let u=$w(l),d=yt(c)[0];if(u&&d)return io(u.from===u.to?`Read line ${u.from} of ${Et(d)}`:`Read lines ${u.from}\u2013${u.to} of ${Et(d)}`,88)}}let o=[];for(let i of r){let c=I_(i);c&&o.push({d:c,head:Et(Cs(Os(i))[0]||""),sub:yt(Cs(Os(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":io(s?s.d:o[0].d,88)}var io,Lt,Et,ao,Rw,_w,S_,v_,E_,__,Ow=M(()=>{io=(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,ao=t=>{let e=t.replace(/\/+$/,"").split("/").filter(Boolean);return e.length>3?e.slice(-2).join("/"):t},Rw=t=>t.startsWith("-"),_w=new Set(["-g","--glob","-t","--type","-A","-B","-C","-m","--max-count","-e","--regexp","-f","--file"]);S_={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"},v_={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"};E_={git:t=>{let e=yt(t,new Set(["-C","-c"])),n=S_[e[0]];return n?n(e,t):null},gh:t=>{let e=yt(t),n=v_[e[0]];return n?n(e):null},sed:T_,rg:Su,grep:Su,egrep:Su,nl:t=>{let e=Lt(yt(t)[0]);return e?`Read ${Et(e)}`:null},cat:t=>{let e=Lt(yt(t)[0]);return e?`Read ${Et(e)}`:null},head:t=>{let e=Lt(yt(t,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return e?`Read the start of ${Et(e)}`:null},tail:t=>{let e=Lt(yt(t,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return e?`Read the end of ${Et(e)}`:null},wc:t=>{let e=Lt(yt(t)[0]);return e?`Count lines in ${Et(e)}`:"Count input lines"},ls:t=>{let e=Lt(yt(t)[0]);return e&&e!=="."?`List files in ${ao(e)}`:"List files"},find:t=>Lt(t[1])&&!Rw(t[1])&&t[1]!=="."?`Find files in ${ao(t[1])}`:"Find files",tree:()=>"List the directory tree",mkdir:t=>{let e=Lt(yt(t)[0]);return e?`Create directory ${ao(e)}`:null},touch:t=>{let e=Lt(yt(t)[0]);return e?`Create ${Et(e)}`:null},rm:t=>{let e=Lt(yt(t)[0]);return e?`Delete ${ao(e)}`:null},mv:t=>{let e=Lt(yt(t)[0]);return e?`Move ${Et(e)}`:null},cp:t=>{let e=Lt(yt(t)[0]);return e?`Copy ${Et(e)}`:null},chmod:t=>{let e=Lt(yt(t)[1]);return e?`Change permissions on ${Et(e)}`:null},diff:t=>{let e=yt(t);return e.length>=2?`Compare ${Et(e[0])} and ${Et(e[1])}`:null},curl:t=>{let e=Iw(t);return e?`Fetch ${io(e,56)}`:"Fetch a URL"},wget:t=>{let e=Iw(t);return e?`Fetch ${io(e,56)}`:"Fetch a URL"},npm:vu,pnpm:vu,yarn:vu,npx:t=>{let e=yt(t)[0];return e?`Run ${e}`:null},node:t=>Tu(t,"Node"),python:t=>Tu(t,"Python"),python3:t=>Tu(t,"Python"),make:t=>{let e=yt(t)[0];return e?`Run make ${e}`:"Run make"},systemctl:A_,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=yt(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=yt(t)[0];return e?`Locate ${e}`:null},command:t=>t[1]==="-v"&&t[2]?`Locate ${t[2]}`:null,fly:t=>{let e=yt(t)[0];return e==="deploy"?"Deploy to Fly":e?`Run fly ${e}`:null}},__=new Set(["pwd","echo","cd","sleep","true","false","test","[","set","export","exit","read"])});function co(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||Au(t)||co(t)}function Eu(t,e){if(t){if(Array.isArray(t)){for(let n of t)Eu(n,e);return}if(typeof t=="object"){if(t.type==="tool_use"&&_u.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))Eu(n,e)}}}async function Cw(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(Eu(c.content,l),!l.length)continue;let u=i.timestamp?Date.parse(i.timestamp):null;for(let d of l)o.push({...d,summary:Rn(d.command,d.description),ts:u})}return o.slice(-n)}function Mw(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((p,w)=>w>=s&&(p.ts||0)>(l.ts||0)),d=u===-1?r.length:u,f=r.slice(s,d);if(s=d,!f.length)continue;let h=f.map(p=>({...p,n:i(p)}));o.push({id:`batch-${l.ts}-${l.box}`,anchorTs:l.ts,anchorBox:l.box,agent:l.agent,boxRole:l.boxRole,commands:h,ts:Math.max(...h.map(p=>p.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 _u,lo=M(()=>{ye();Ow();_u=new Set(["Bash"])});import Nw from"node:fs";import Ru from"node:fs/promises";import Iu from"node:path";import R_ from"node:os";async function Pw(t){try{return await Ru.realpath(t)}catch{return t}}function O_(t=$_){let e=[],n=r=>{let o;try{o=Nw.readdirSync(r,{withFileTypes:!0})}catch{return}for(let s of o){let a=Iu.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:Nw.statSync(a).mtimeMs})}catch{}}}};return n(t),e.sort((r,o)=>o.mtimeMs-r.mtimeMs)}async function C_(t,e=1048576){let n;try{n=await Ru.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 M_(t){let e=await C_(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=O_();if(e){let o=n.find(s=>s.id===e);return o||null}let r=await Pw(t);for(let o of n){let s=await M_(o.file);if(s&&(s===t||await Pw(s)===r))return o}return null}async function Bw(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,d=null;for(let f of s.split(`
78
- `)){let h=f.trim();if(!h||h[0]!=="{")continue;let p;try{p=JSON.parse(h)}catch{continue}if((p.type==="turn_context"&&p.payload?.model||p.type==="session_meta"&&p.payload?.model)&&(i=p.payload.model),p.type==="event_msg"){let x=p.payload?.type;x==="task_started"?(l=!0,u=!1,d=p.payload?.turn_id||null):x==="task_complete"&&l&&(l=!1,!u&&p.payload?.last_agent_message==null&&a.push({role:"assistant",failed:!0,text:Ou,sourceId:p.payload?.turn_id||d||void 0,ts:p.timestamp?Date.parse(p.timestamp):null,model:i}));continue}if(p.type!=="response_item")continue;let w=p.payload;if(!w)continue;if((w.type==="function_call"||w.type==="custom_tool_call")&&w.name){u=!0,$u.has(w.name)||c.push(w.name);continue}if(w.type!=="message"||w.role!=="assistant")continue;u=!0;let y=P_(w.content),k=c.length?c.slice():null;c=[],!(!y&&!k)&&a.push({role:"assistant",text:y,tools:k||void 0,ts:p.timestamp?Date.parse(p.timestamp):null,model:i})}if(i)for(let f of a)f.model||(f.model=i);return a.slice(-n)}function B_(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 D_(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 j_(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=D_(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 d=[];if(u.type==="function_call"&&Ms.has(u.name)){let h;try{h=JSON.parse(u.arguments||"{}")}catch{continue}let p=B_(h);p&&(d=[p])}else u.type==="custom_tool_call"&&u.name==="exec"&&(d=j_(u.input));if(!d.length)continue;let f=u.call_id||u.id||null;d.forEach((h,p)=>{a.push({id:f?p?`${f}:${p}`:f:null,tool:u.name,command:h,description:"",summary:Rn(h),ts:l.timestamp?Date.parse(l.timestamp):null})})}return a.slice(-n)}async function jw(t,e){let n=await mr(t,e);if(!n)return null;try{return Math.round((await Ru.stat(n.file)).mtimeMs)}catch{return n.mtimeMs||null}}var $_,N_,P_,Ms,$u,Ou,uo=M(()=>{ye();lo();$_=process.env.BOSTRAT_CODEX_SESSIONS||Iu.join(process.env.CODEX_HOME||Iu.join(R_.homedir(),".codex"),"sessions");N_=new Set(["output_text","text"]),P_=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():"";Ms=new Set(["exec_command","shell","exec"]),$u=new Set(["wait","write_stdin"]),Ou="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 Ns(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(Lw.test(n[c])){r=c;break}if(r<=0)return null;let o=-1;for(let c=r-1;c>=0;c--)if(Lw.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(L_);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 Fw(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 Uw(t,e,n,{busy:r=!1}={}){let o=Ns(t,n);return o&&Cu(e,o)?"stuck":r||o?"submitted":"unknown"}function Cu(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 Lw,L_,Mu=M(()=>{Lw=/^\s*─{8,}\s*$/,L_=/^❯[  ]?(.*)$/});function K_(t){return F_.test(String(t||"").trimStart())}function qw(t){let e=String(t||"");if(!K_(e.trimStart()))return null;let n=e.replace(U_,"").trim(),r=G_(n),o=[];for(let u of W_){let d=u.from.map(f=>fo(r.get(f))).find(f=>f&&!Hw(f));d&&o.push({h:u.h,text:Ps(d,H_)})}let s=fo(r.get("Current Work"))||fo(r.get("Primary Request and Intent"))||z_(n),a=Pi(s),i=Ps(Ni(Bu(a[0]||"")),q_)||"Context resumed from summary",c=[],l=a.slice(1).join(" ").trim();l&&c.push(Ps(Ni(Bu(l)),Pu));for(let u of["Pending Tasks","Optional Next Step"]){let d=Pi(fo(r.get(u)))[0]||"";if(!(!d||Hw(d))){c.push(Ps(`Left to do: ${Ni(Bu(d))}`,Pu));break}}if(!c.length){let u=Pi(fo(r.get("Problem Solving"))||"")[0];u&&c.push(Ps(Ni(u),Pu))}return{kind:"resume-summary",title:i,bullets:c.slice(0,2),sections:o,rawChars:e.length}}function G_(t){let e=new Map,n=[];Nu.lastIndex=0;for(let r=Nu.exec(t);r;r=Nu.exec(t))n.push({name:V_(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 V_(t){return Ww.find(n=>n.toLowerCase()===t.toLowerCase())||t}function fo(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 z_(t){let e=t.replace(/^[\s\S]*?\bSummary:\s*/i,"");return fo(e.split(/\n{2,}/).slice(0,2).join(" "))}function Pi(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 Bu(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 Ni(t){return String(t||"").replace(/(?<![:\w/])(?:\/[\w.@+-]+){4,}/g,e=>`\u2026/${e.split("/").slice(-2).join("/")}`)}function Hw(t){return/^(none|nothing|n\/a|no pending|there are no)\b/i.test(String(t||"").trim())}function Ps(t,e){let n=String(t||"").trim();if(n.length<=e)return n;let r=Pi(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 F_,Ww,Nu,U_,H_,W_,q_,Pu,Kw=M(()=>{F_=/^This session is being continued from a previous conversation that ran out of context\./,Ww=["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"],Nu=new RegExp(String.raw`^[ \t]*#{0,4}[ \t]*(?:\d+[.)][ \t]*)?\*{0,2}(${Ww.join("|")})[:*\t ]*$`,"gim"),U_=/\n+If you need specific details from before compaction[\s\S]*$|\n+Continue the conversation from where it left off[\s\S]*$/,H_=420,W_=[{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"]}],q_=116,Pu=168});function Vw(t){return Du.has(String(t||"").replace(/^\//,"").toLowerCase())}function Bi(t){let e=String(t||"").trim();if(!e)return null;let n=qw(e);if(n)return n;let r=e.match(J_);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(X_);if(s){let i=s[1].toLowerCase();return Du.has(i)?{kind:"suppress"}:{kind:"command",command:`/${i}`}}let a=e.match(iI);if(a&&Du.has(a[1].toLowerCase()))return{kind:"suppress"};if(Z_.test(e))return{kind:"suppress"};if(tI.test(e))return{kind:"suppress"};if(Q_.test(e))return{kind:"suppress"};if(eI.test(e)){let i=l=>cI(e.match(l)?.[1].trim()||"")||null,c=i(aI);return{kind:"task",summary:i(nI)||"",taskId:i(rI),toolUseId:i(oI),status:i(sI)?.toLowerCase()||null,resultHead:c?c.length>Gw?`${c.slice(0,Gw).trimEnd()}\u2026`:c:null}}return null}function cI(t){return t.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&amp;/g,"&")}function zw(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 Jw(t){return t?.kind==="skill"?"skill-run":t?.kind==="task"?"task-done":t?.kind==="resume-summary"?"context-resumed":"command-run"}var J_,Y_,X_,Z_,Q_,tI,eI,nI,rI,oI,sI,aI,Gw,Du,iI,ju=M(()=>{Kw();J_=/^Base directory for this skill:\s*(\S+)/,Y_=/^Run the "([^"]+)" workflow\./,X_=/<command-name>\s*\/?([a-z0-9:_-]+)\s*<\/command-name>/i,Z_=/^<local-command-(?:stdout|caveat)>/i,Q_=/^\[Image: original \d+x\d+, displayed at \d+x\d+\.\s*Multiply coordinates by [\d.]+ to map to original image\.\]$/,tI=/^Continue from where you left off\.$/,eI=/^<task-notification>/i,nI=/<summary>([\s\S]*?)<\/summary>/i,rI=/<task-id>([\s\S]*?)<\/task-id>/i,oI=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i,sI=/<status>([\s\S]*?)<\/status>/i,aI=/<result>([\s\S]*?)(?:<\/result>|$)/i,Gw=600,Du=new Set(["model","clear","compact","login","exit","quit"]);iI=/^\/([a-z0-9:_-]+)$/i});import lI from"node:crypto";function pI(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,Xw)){let o=Bs(r?.question);if(!o)return null;let s=Array.isArray(r?.options)?r.options:[],a=[];for(let i of s.slice(0,uI)){let c=Bs(i?.label);if(!c)return null;let l=Bs(i?.description);a.push(l?{label:c,description:l}:{label:c})}if(a.length<dI)return null;n.push({question:o,header:Bs(r?.header).slice(0,fI),multiSelect:r?.multiSelect===!0,options:a})}return n.length?n:null}function Fu(t){if(typeof t!="string"||!t.includes("```bostrat-question"))return null;Yw.lastIndex=0;let e=null;for(let o;o=Yw.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=pI(n);return r?{text:t.slice(0,e.index).trimEnd(),questions:r}:null}function Uu(t,e,n){let r=lI.createHash("sha256").update(JSON.stringify(n)).digest("hex").slice(0,8);return`${t}:ask:${e||"turn"}:${r}`}function Hu(t,{leadBoxId:e,provider:n,isAnswered:r,maxQuestions:o=Xw}={}){if(!Array.isArray(t)||!e||!Lu.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||Fu(s.text)?.questions;if(!a?.length)return null;let i=a.slice(0,Math.max(1,o)),c=Uu(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 Zw(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=Bs(n),s;return r.length?r.length===1?s=`${r[0].name}: ${r[0].picks}`:s=`Answers:
79
+ - `).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 Jw,Xw=C(()=>{ju();Jw="Relevant prior discussion (verbatim, retrieved"});import Lu from"node:fs/promises";import mo from"node:path";import tI from"node:os";import{EventEmitter as eI}from"node:events";import{randomUUID as nI}from"node:crypto";function ho(t){return t?.cwd?mo.join(t.cwd,".bostrat","events"):mo.join(Fu,"events")}async function aI(t,e){if(!Ui.has(e)){let o=(await B(t,e)).reduce((s,a)=>a.seq>s?a.seq:s,0);Ui.set(e,o)}let n=Ui.get(e)+1;return Ui.set(e,n),n}function iI(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||!rI.has(e.type))throw new Error(`appendEvent: unknown event type "${e?.type}"`);if(e.actor&&!oI.has(e.actor))throw new Error(`appendEvent: bad actor "${e.actor}"`);if(e.source&&!sI.has(e.source))throw new Error(`appendEvent: bad source "${e.source}"`);let r=typeof t=="string"?mo.join(Fu,"events"):ho(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=iI(c,Number(e.payload?.ts??e.ts)||Date.now())}let s=await aI(r,n),a=e.userId??process.env.BOSTRAT_OWNER??null,i={id:e.id||nI(),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(Zw(r,n),JSON.stringify(i)+`
80
+ `),Qt.emit("event",i),Qt.emit(`track:${n}`,i),i}async function B(t,e){let n,r;typeof t=="string"&&e?(n=t,r=e):(r=typeof t=="string"?t:t?.id,n=typeof t=="string"?mo.join(Fu,"events"):ho(t));let o;try{o=await Lu.readFile(Zw(n,r),"utf8")}catch{return[]}let s=[];for(let a of o.split(`
81
+ `))if(a.trim())try{s.push(JSON.parse(a))}catch{}return s}function Qw(t,e){let n=`track:${t}`;return Qt.on(n,e),()=>Qt.off(n,e)}var rI,oI,sI,Qt,Fu,Zw,Ui,st=C(()=>{rI=new Set(["session.ready","turn.user","turn.agent","turn.retracted","peer.message","provider.error","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","decision.recorded","changelog.published","stall.detected","error"]),oI=new Set(["user","agent","orchestrator","system","peer"]),sI=new Set(["hook","otel","statusline","transcript","pane","orchestrator","vendor"]),Qt=new eI;Qt.setMaxListeners(0);Fu=process.env.BOSTRAT_STATE_DIR||mo.join(process.env.HOME||tI.tmpdir(),".bostrat");Zw=(t,e)=>mo.join(t,`${e}.ndjson`),Ui=new Map});function qs(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(tg.test(n[c])){r=c;break}if(r<=0)return null;let o=-1;for(let c=r-1;c>=0;c--)if(tg.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(cI);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 $t(t){return String(t||"").replace(/\s+/g," ").trim()}function eg(t,e,{slackMs:n=2e4}={}){let r=$t(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&&$t(o.text).includes(r))}function ng(t,e,n,{busy:r=!1}={}){let o=qs(t,n);return o&&Uu(e,o)?"stuck":r||o?"submitted":"unknown"}function Uu(t,e){let n=$t(t),r=$t(e).replace(/^…\s*/,"").replace(/\s*…$/,"");return!n||!r||r.length<Math.min(n.length,12)?!1:n===r||n.includes(r)}var tg,cI,Hu=C(()=>{tg=/^\s*─{8,}\s*$/,cI=/^❯[  ]?(.*)$/});function mI(t){return lI.test(String(t||"").trimStart())}function sg(t){let e=String(t||"");if(!mI(e.trimStart()))return null;let n=e.replace(uI,"").trim(),r=hI(n),o=[];for(let u of fI){let d=u.from.map(f=>wo(r.get(f))).find(f=>f&&!rg(f));d&&o.push({h:u.h,text:Ks(d,dI)})}let s=wo(r.get("Current Work"))||wo(r.get("Primary Request and Intent"))||gI(n),a=Wi(s),i=Ks(Hi(Ku(a[0]||"")),pI)||"Context resumed from summary",c=[],l=a.slice(1).join(" ").trim();l&&c.push(Ks(Hi(Ku(l)),qu));for(let u of["Pending Tasks","Optional Next Step"]){let d=Wi(wo(r.get(u)))[0]||"";if(!(!d||rg(d))){c.push(Ks(`Left to do: ${Hi(Ku(d))}`,qu));break}}if(!c.length){let u=Wi(wo(r.get("Problem Solving"))||"")[0];u&&c.push(Ks(Hi(u),qu))}return{kind:"resume-summary",title:i,bullets:c.slice(0,2),sections:o,rawChars:e.length}}function hI(t){let e=new Map,n=[];Wu.lastIndex=0;for(let r=Wu.exec(t);r;r=Wu.exec(t))n.push({name:wI(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 wI(t){return og.find(n=>n.toLowerCase()===t.toLowerCase())||t}function wo(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 gI(t){let e=t.replace(/^[\s\S]*?\bSummary:\s*/i,"");return wo(e.split(/\n{2,}/).slice(0,2).join(" "))}function Wi(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 Ku(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 Hi(t){return String(t||"").replace(/(?<![:\w/])(?:\/[\w.@+-]+){4,}/g,e=>`\u2026/${e.split("/").slice(-2).join("/")}`)}function rg(t){return/^(none|nothing|n\/a|no pending|there are no)\b/i.test(String(t||"").trim())}function Ks(t,e){let n=String(t||"").trim();if(n.length<=e)return n;let r=Wi(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 lI,og,Wu,uI,dI,fI,pI,qu,ag=C(()=>{lI=/^This session is being continued from a previous conversation that ran out of context\./,og=["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"],Wu=new RegExp(String.raw`^[ \t]*#{0,4}[ \t]*(?:\d+[.)][ \t]*)?\*{0,2}(${og.join("|")})[:*\t ]*$`,"gim"),uI=/\n+If you need specific details from before compaction[\s\S]*$|\n+Continue the conversation from where it left off[\s\S]*$/,dI=420,fI=[{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"]}],pI=116,qu=168});function cg(t){return Gu.has(String(t||"").replace(/^\//,"").toLowerCase())}function qi(t){let e=String(t||"").trim();if(!e)return null;let n=sg(e);if(n)return n;let r=e.match(yI);if(r)return{kind:"skill",name:r[1].split("/").filter(Boolean).pop()||"skill"};let o=e.match(bI);if(o)return{kind:"skill",name:o[1]};let s=e.match(kI);if(s){let i=s[1].toLowerCase();return Gu.has(i)?{kind:"suppress"}:{kind:"command",command:`/${i}`}}let a=e.match($I);if(a&&Gu.has(a[1].toLowerCase()))return{kind:"suppress"};if(xI.test(e))return{kind:"suppress"};if(SI.test(e))return{kind:"suppress"};if(vI.test(e))return{kind:"suppress"};if(TI.test(e)){let i=l=>OI(e.match(l)?.[1].trim()||"")||null,c=i(RI);return{kind:"task",summary:i(AI)||"",taskId:i(EI),toolUseId:i(_I),status:i(II)?.toLowerCase()||null,resultHead:c?c.length>ig?`${c.slice(0,ig).trimEnd()}\u2026`:c:null}}return null}function OI(t){return t.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&amp;/g,"&")}function lg(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 ug(t){return t?.kind==="skill"?"skill-run":t?.kind==="task"?"task-done":t?.kind==="resume-summary"?"context-resumed":"command-run"}var yI,bI,kI,xI,vI,SI,TI,AI,EI,_I,II,RI,ig,Gu,$I,Vu=C(()=>{ag();yI=/^Base directory for this skill:\s*(\S+)/,bI=/^Run the "([^"]+)" workflow\./,kI=/<command-name>\s*\/?([a-z0-9:_-]+)\s*<\/command-name>/i,xI=/^<local-command-(?:stdout|caveat)>/i,vI=/^\[Image: original \d+x\d+, displayed at \d+x\d+\.\s*Multiply coordinates by [\d.]+ to map to original image\.\]$/,SI=/^Continue from where you left off\.$/,TI=/^<task-notification>/i,AI=/<summary>([\s\S]*?)<\/summary>/i,EI=/<task-id>([\s\S]*?)<\/task-id>/i,_I=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i,II=/<status>([\s\S]*?)<\/status>/i,RI=/<result>([\s\S]*?)(?:<\/result>|$)/i,ig=600,Gu=new Set(["model","clear","compact","login","exit","quit"]);$I=/^\/([a-z0-9:_-]+)$/i});import CI from"node:crypto";function BI(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,fg)){let o=Gs(r?.question);if(!o)return null;let s=Array.isArray(r?.options)?r.options:[],a=[];for(let i of s.slice(0,MI)){let c=Gs(i?.label);if(!c)return null;let l=Gs(i?.description);a.push(l?{label:c,description:l}:{label:c})}if(a.length<NI)return null;n.push({question:o,header:Gs(r?.header).slice(0,PI),multiSelect:r?.multiSelect===!0,options:a})}return n.length?n:null}function Ju(t){if(typeof t!="string"||!t.includes("```bostrat-question"))return null;dg.lastIndex=0;let e=null;for(let o;o=dg.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=BI(n);return r?{text:t.slice(0,e.index).trimEnd(),questions:r}:null}function Yu(t,e,n){let r=CI.createHash("sha256").update(JSON.stringify(n)).digest("hex").slice(0,8);return`${t}:ask:${e||"turn"}:${r}`}function Xu(t,{leadBoxId:e,provider:n,isAnswered:r,maxQuestions:o=fg}={}){if(!Array.isArray(t)||!e||!zu.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||Ju(s.text)?.questions;if(!a?.length)return null;let i=a.slice(0,Math.max(1,o)),c=Yu(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 pg(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=Gs(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 Lu,Xw,uI,dI,fI,Yw,Bs,Qw,Wu=M(()=>{Lu=new Set(["cursor","codex"]),Xw=4,uI=4,dI=2,fI=24,Yw=/^[ \t]{0,3}(`{3,})bostrat-question[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]{0,3}\1`*[ \t]*$/gm,Bs=t=>typeof t=="string"?t.trim():"";Qw=`
86
+ ${o}`),s||""}var zu,fg,MI,NI,PI,dg,Gs,mg,Zu=C(()=>{zu=new Set(["cursor","codex"]),fg=4,MI=4,NI=2,PI=24,dg=/^[ \t]{0,3}(`{3,})bostrat-question[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]{0,3}\1`*[ \t]*$/gm,Gs=t=>typeof t=="string"?t.trim():"";mg=`
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,66 +103,67 @@ 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 mI(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 wI(t,e,n){let r=tg(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$/,d=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 O=v[0].split("/").pop().toLowerCase();d.has(O)||d.set(O,[]),d.get(O).push(g.payload?.ts??g.ts)}}let f=3*6e4,h=20*6e4,p=(g,m)=>!!(g?.name&&d.get(String(g.name).toLowerCase()))?.some(O=>O>=m-f&&O<=m+h);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:st(g)};m.toolUseId&&i.set(m.toolUseId,v);let O=String(m.summary||"").match(u);O&&l.set(O[1],v)}let w=new Map,y=new Map,k=null,x=new Map,E=new Map,$=new Map,G=new Map,C=new Map,N=new Map,T=new Map,B=new Map,j=new Map,at=new Map,rt=new Map,A=new Map,D=new Map,X=()=>{for(let g of D.values())g.questions.length&&e.push(g);D.clear()},bt=null,dt=6e4,kt=new Map,xt=(g,m)=>{let v=o.get(g);if(!v?.length)return!1;let O=Ot(m),it=s.get(g);return v.some(ct=>{if(!O.startsWith(ct))return!1;let mt=Ot(O.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||Bi(m.text);if(v){if(v.kind==="task"){if(v.toolUseId&&a.has(v.toolUseId))break;let O=String(v.summary||"").match(u);if(!v.toolUseId&&O&&c.has(O[1]))break}if(v.kind==="command"&&Vw(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:st(g),box:g.boxId,agent:g.provider});break}v.kind!=="suppress"&&e.push({id:g.id,kind:"event",type:Jw(v),name:v.name??null,command:v.command??null,summary:v.summary??null,status:v.status??null,ts:st(g),box:g.boxId,agent:g.provider});break}}if(r.has(`${g.boxId}|${st(g)}`)||g.source==="transcript"&&xt(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:st(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"&&(bt=null);break}for(let v of x.values())v.status="stale";x.clear();for(let v of $.values())v.status="stale";$.clear(),bt&&bt.box===g.boxId&&(e.push(mI(bt)),bt=null),e.push({id:g.id,kind:"message",role:"user",text:m.text,ts:st(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:st(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=>!p(mt,st(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)}(!bt||bt.box===g.boxId)&&(bt=null);let O=g.provider==="codex"?(m.tools||[]).filter(mt=>!$u.has(mt)&&!Ms.has(mt)):m.tools||[],it=m.text,ct=null;if(Lu.has(g.provider)){let mt=Fu(String(m.text||""));mt&&(it=mt.text,ct={questions:mt.questions})}e.push({id:g.id,kind:"message",role:"assistant",text:it,ts:st(g),box:g.boxId,agent:g.provider,boxRole:m.boxRole,...ct?{ask:ct}:{},...O.length?{tools:O}:{},...m.model?{model:m.model}:{},...m.sourceId?{sourceId:m.sourceId}:{},...v.length?{images:v}:{}}),ct&&(bt={id:g.id,groupId:Uu(g.provider,m.sourceId||g.id,ct.questions),provider:g.provider,box:g.boxId,questions:ct.questions,ts:st(g)});break}case"job.started":{if(!m.id)break;let v=st(g),O=i.get(m.id);if(!O&&(m.kind||"agent")==="agent"&&m.name){let b=l.get(m.name);b&&b.ts>=v&&(O=b)}let it={jobId:m.id,jobKind:m.kind||"agent",name:m.name||null,detail:m.detail||null,status:O?O.status==="killed"?"stopped":O.status&&O.status!=="completed"?"failed":"done":"running",startedTs:v,finishedTs:O?.ts??null,summary:O?.summary??null,resultHead:O?.resultHead??null},ct=kt.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]};kt.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 O of x.values())O.status="stale";x.clear();for(let O of $.values())O.status="stale";$.clear()}let v=be(g,`pr-${m.change}`);if(v.box=g.boxId??null,hI.has(m.change)&&m.number!=null){let O=wI(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(O)??[];it.push(v),y.set(O,it)}}else if(m.change==="merged"||m.change==="closed"||m.change==="lost"){let O=tg(m),it=k&&!k.complete||w.size>=2;if(w.has(O))w.delete(O),y.delete(O);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:st(g),ts:st(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:st(g)}),k.remaining=[...w.values()],k.complete=w.size===0;break}}e.push(v);break}case"pr.offered":{if(!m.offerId)break;for(let O of x.values())O.status="stale";x.clear();for(let O of $.values())O.status="stale";$.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:st(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 O of $.values())O.status="stale";$.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:st(g),box:g.boxId,agent:g.provider};$.set(m.offerId,v),G.set(m.offerId,v),e.push(v);break}case"pr.exists.answered":{let v=G.get(m.offerId);v&&(v.status=m.choice||"dismiss",$.delete(m.offerId));break}case"box.state.changed":{let v=m.change==="model"?"model-change":m.change;if(!v)break;let O=be(g,v);v==="model-change"&&(O.to=m.model),e.push(O);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:st(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:st(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:st(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:st(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:st(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:st(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:st(g),box:g.boxId,agent:g.provider});break}case"box.fullscreen.detected":{if(!m.offerId)break;for(let O of T.values())O.box===(m.box||g.boxId)&&(O.status="stale",T.delete(O.offerId));let v={id:g.id,kind:"fullscreen-offer",offerId:m.offerId,status:"open",ts:st(g),box:m.box||g.boxId,agent:m.agent||g.provider};T.set(m.offerId,v),B.set(m.offerId,v),e.push(v);break}case"box.fullscreen.answered":{let v=B.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 O of C.values())O.key===m.key&&(O.status="stale",C.delete(O.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:st(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:st(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 O of j.values())O.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:st(g),box:g.boxId,agent:g.provider};j.set(m.proposalId,v),at.set(m.proposalId,v),e.push(v);break}case"ticket.create.answered":{let v=at.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 O of rt.values())O.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:st(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},O=m.proposalId?at.get(m.proposalId):null;if(O){O.created=v;break}e.push({id:g.id,kind:"ticket-created",...v,ts:st(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:st(g),at:st(g),box:g.boxId,agent:g.provider});break}case"prompt.answered":{if(bt=null,m.control||!m.question)break;let v=m.groupId||m.promptId;if(!v)break;let O=D.get(v);O||(O={id:g.id,kind:"prompt",groupId:v,provider:g.provider,box:g.boxId,agent:g.provider,questionTotal:m.questionTotal??1,questions:[],ts:st(g)},D.set(v,O));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=O.questions.findIndex(b=>b.index===it&&Ot(b.question)===Ot(ct.question));mt>=0?O.questions[mt]=ct:O.questions.push(ct),O.questions.sort((b,_)=>b.index-_.index),O.questionTotal=Math.max(O.questionTotal,m.questionTotal??1),O.questions.length>=O.questionTotal&&(e.push(O),D.delete(v));break}default:break}}return yI(e.sort((g,m)=>(g.ts??0)-(m.ts??0)))}function yI(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<=gI){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 qu(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:bI(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 Mw(n,r)}function bI(t){let e=String(t.summary||"").trim();return e&&e!==t.command&&e!==co(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:st(t),ts:st(t)}}function eg(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)+kI,s=n;for(;s+1<e.length;){let a=e[s+1];if((a?.ts??0)>o||a?.kind==="event"&&xI.has(a.type))break;s++}s>n&&e.splice(s,0,...e.splice(n,1)),n=s}return e}function ng(t){let e=[...t];for(let n=0;n<e.length;n++){let r=e[n];if(r?.kind!=="event"||!vI.has(r.type)||!r.box)continue;let o=(r.ts??0)+SI,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 st,hI,tg,gI,kI,xI,SI,vI,Ku=M(()=>{lo();uo();Mu();ju();Wu();st=t=>t.payload?.ts??t.ts;hI=new Set(["opened","ci-fixed","reconciled","pushed"]),tg=t=>`${t.repo??""}#${t.number}`;gI=2*6e4;kI=12e4,xI=new Set(["archived","unarchived","opened"]);SI=2500,vI=new Set(["pr-opened","pr-merged","pr-auto-armed"])});function II(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 OI(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<EI&&(o.add(c.path),n.push(c.path)),c.head&&!s.has(c.head)&&r.length<_I&&(s.add(c.head),r.push(c.head))}return{files:n,heads:r}}function ag(t,{trackName:e="this Track",now:n=null,mode:r="failover"}={}){let o=II(t),s=$I(t),a=s?.payload?.content??null,i=s?s.payload?.ts??s.ts??null:null,c=hr(t??[]).filter(f=>f?.kind==="message"&&typeof f.text=="string"&&f.text.trim()).slice(-TI);if(!a&&!c.length)return null;let l=[];if(l.push(`# Reconstructed resume brief \u2014 ${e}`),l.push(""),l.push(sg[r]??sg.failover),l.push(""),o.lastPush?.sha){let f=og(n,o.lastPush.ts),h=f?` (~${f} min before the loss)`:"";l.push(`**Code state:** last pushed ref \`${o.lastPush.ref}\` @ \`${o.lastPush.sha.slice(0,12)}\`${h}`+(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=og(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=OI(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"}:** ${RI(f.text,AI)}`),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<=rg?d:`${d.slice(0,rg)}
108
-
109
- [\u2026 brief truncated]`}var TI,AI,rg,EI,_I,RI,og,sg,ig=M(()=>{Ku();TI=12,AI=2e3,rg=48e3,EI=30,_I=10;RI=(t,e)=>{let n=String(t??"").trim();return n.length<=e?n:`${n.slice(0,e-1)}\u2026`},og=(t,e)=>t&&e?Math.max(1,Math.round((t-e)/6e4)):null;sg={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 CI from"node:fs";import $n from"node:fs/promises";import On from"node:path";function mg(t){let e=lr(String(t??"")),n=Buffer.byteLength(e,"utf8");return n<=cg?{content:e,bytes:n,truncated:!1}:{content:`${Buffer.from(e,"utf8").subarray(0,cg).toString("utf8").replace(/�+$/,"")}
110
-
111
- [\u2026 truncated by bostrat at 32 KiB \u2014 full artifact in the workspace]`,bytes:n,truncated:!0}}function UI(t){let e=String(t||"").split(/\r?\n/).map(s=>s.trim()).filter(Boolean),n=[],r=[];for(let s of e)if(ug.test(s)){if(r.length>=kg)continue;let a=FI(s.replace(ug,"").replace(/[.;,:]+$/,""),xg,jI);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>lg&&(o=`${o.slice(0,lg-1).trimEnd()}\u2026`),{text:o,items:r.length>1?r:[]}}async function Sg(t,e,{timeoutMs:n=9e4}={}){let r=On.join(e,BI),o=On.join(r,DI);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 ji(t,a,LI(o)),await Rg(o,s,n),UI(await $n.readFile(o,"utf8"))}function vg(t,e){let n=(e||"").trim();if(!n)return!1;if(t==="assistant")return n===wg||n===bg;let r=n.replace(/^\/[a-z0-9:_-]+\s+/i,"");return r.startsWith(hg)||n===MI||r.startsWith(gg)||r.startsWith(yg)}function Tg(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-HI;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 Ag(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(vg(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 Li(t){return Gu.get(t)||null}async function _g(t){let e=Gu.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,fg,pg)};return Gu.set(t,r),KI(r,n.cwd).catch(o=>{r.error=o?.message||String(o),r.finishedAt=Date.now()}),r}async function KI(t,e){t.step="summarize",await Ig(t.name,e),t.step="clear";let n=await et(t.name);await ji(t.name,n,"/clear"),await Ju(WI),t.step="resume",await ji(t.name,n,PI),t.step="done",t.finishedAt=Date.now()}async function Ig(t,e,{timeoutMs:n=qI}={}){let r=On.join(e,fg),o=On.join(r,pg);await $n.mkdir(r,{recursive:!0});let s=await Di(o),a=await et(t);await V({flow:"checkpoint",phase:"summarize-start",sessionName:t,cwd:e,file:o,beforeMtime:s}),await ji(t,a,NI(o)),await Rg(o,s,n),await V({flow:"checkpoint",phase:"summarize-done",sessionName:t,file:o,afterMtime:await Di(o)});let i=await vw(e,o,{exclude:u=>vg(u.role,u.text)});await V({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:{...mg(u),ts:Date.now()}})}catch{}}await Sh(e);let l=await GI(r,o);return c&&await Mh(c,l||o,{box:t,agent:a?.agent??null}),o}async function Vu(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 Ig(t,n.cwd,e?{timeoutMs:e}:void 0)}async function zu(t,e,{trackName:n="this Track"}={}){let r=await F({id:t,cwd:e}),o=ag(r,{trackName:n,now:Date.now(),mode:"in-place"});if(!o)return null;let s=On.join(e,dg);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:{...mg(o),reconstructed:!0,ts:Date.now()}}).catch(()=>{}),dg}async function Di(t){try{return(await $n.stat(t)).mtimeMs}catch{return 0}}async function Rg(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 Ju(2e3)}}async function GI(t,e){try{if(!CI.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 Ju(t){return new Promise(e=>setTimeout(e,t))}async function ji(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 Ju(150),await no(t,Si,{kind:"drive-wipe"}),await Pt(t,n,{kind:"orchestration-drive",...$e(r.agent)})}var fg,pg,cg,hg,wg,gg,MI,NI,PI,yg,bg,BI,DI,lg,kg,xg,jI,LI,ug,FI,HI,WI,qI,Gu,dg,Yu=M(()=>{Kt();$i();Ke();Is();Tw();li();ot();mi();ig();fg=".bostrat/handoff",pg="latest.md",cg=32*1024;hg="Checkpoint: write a work-in-progress handoff",wg="HANDOFF WRITTEN",gg="Resume from .bostrat/handoff/latest.md",MI="/clear",NI=t=>`${hg} 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 ${wg} and take no further action.`,PI=`${gg}: read it, restate the Objective and the single next step in one line, then continue the work from 'Next steps'.`,yg="Beat: write a",bg="BEAT WRITTEN",BI=".bostrat/arc",DI="beat.txt",lg=200,kg=4,xg=5,jI=36,LI=t=>`${yg} 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 ${kg} further lines, each starting with "- " and naming ONE piece in at most ${xg} 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 ${bg} and take no further action.`,ug=/^(?:[-–—*•·]|\d+[.)])\s+/,FI=(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};HI=6e5;WI=3500,qI=3e5,Gu=new Map;dg=".bostrat/handoff/status-latest.md"});function Og(t,e,n){if(t==null)return e==="from"?-1/0:1/0;if(!VI.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 zI(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:Og(o.from,"from",n),toMs:Og(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 XI(t){if(!t)return null;let e=String(t).trim();return Xu[e]?e:$g[e]?$g[e]:Object.keys(Xu).find(r=>e.startsWith(r))||null}function Cg(t,e){let n=XI(t);if(!n)return null;let r=YI(e);return r===null?null:JI[n].find(o=>r>=o.fromMs&&r<=o.toMs)||null}function Cn(t,e={},n){let r=Cg(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 Xu,$g,VI,JI,Mg,Ds=M(()=>{Xu={"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)."}]},$g={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"},VI=/^\d{4}-\d{2}-\d{2}$/;JI=zI(Xu);Mg=(t,e)=>Cg(t,e)!==null});function ZI(t){return t?{input:t.input||0,output:t.output||0,cacheRead:t.cacheRead||0,cacheWrite:t.cacheWrite??t.cacheCreation??0}:null}function Pg(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=ZI(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&&!Mg(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(f=>f.type==="cost.recorded"),r={},o={},s={},a=0,i=0,c=0,l=0,u=new Set,d=Ng();for(let f of n){let{usd:h,model:p,tokens:w,repriced:y,unpriced:k,asRecorded:x}=Ve(f);i+=x;let E=f.provider||"unknown",$=f.boxId||"unattributed";if(y&&c++,k&&(l++,u.add(p)),a+=h,Pg(d,w),r[p]||={usd:0,tokens:Ng(),events:0},r[p].usd+=h,r[p].events+=1,Pg(r[p].tokens,w),o[E]||={usd:0,events:0},o[E].usd+=h,o[E].events+=1,s[$]||={usd:0,events:0,provider:E,models:new Set,label:e[$]||$},s[$].usd+=h,s[$].events+=1,p!=="unknown"&&s[$].models.add(p),f.epoch!=null){let G=(s[$].epochs||={})[f.epoch]||={usd:0,events:0,provider:E,models:new Set};G.usd+=h,G.events+=1,G.provider=E,p!=="unknown"&&G.models.add(p)}}return{totalUsd:po(a),asRecordedUsd:po(i),totalTokens:d,turns:n.length,repricedTurns:c,unpricedTurns:l,unpricedModels:[...u],byModel:Fi(r,f=>({...f,usd:po(f.usd)})),byProvider:Fi(o,f=>({...f,usd:po(f.usd)})),byBox:Fi(s,f=>({usd:po(f.usd),events:f.events,provider:f.provider,label:f.label,models:[...f.models],...f.epochs?{epochs:Fi(f.epochs,h=>({usd:po(h.usd),events:h.events,provider:h.provider,models:[...h.models]}))}:{}}))}}var Ng,po,Fi,wr=M(()=>{Ds();Ng=()=>({input:0,output:0,cacheRead:0,cacheCreation:0});po=t=>Math.round(t*1e4)/1e4,Fi=(t,e)=>Object.fromEntries(Object.entries(t).map(([n,r])=>[n,e(r)]))});function QI(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 Bg(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,h]=d.split("#");return`${f.split("/").pop()}#${h}`});n.push(`Merged ${u.slice(0,4).join(", ")}${u.length>4?` +${u.length-4}`:""}`)}else s&&n.push(Zu(s,"PR")+" opened");let a=Object.keys(t?.subtasks||{}).length||r.filter(u=>u.type==="subtask-delegated").length;a&&n.push(Zu(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(`${Zu(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)?QI(t.archivedAt-t.createdAt):null;return n.length&&l&&n.push(l),n.length?n.join(" \xB7 "):null}var Zu,Dg=M(()=>{wr();Zu=(t,e)=>`${t} ${e}${t===1?"":"s"}`});import{execFile as tR}from"node:child_process";import{promisify as eR}from"node:util";import{randomUUID as nR}from"node:crypto";async function Qu(t,e){let n=Date.now()+e;for(;;){if(await eo(t))return!0;if(Date.now()>n)return!1;await Ui(oR)}}async function aR(t,e){let n=Lg[e]||Lg.default;n.escape&&(await It(t,["Escape"],{kind:"swap-exit"}),await Ui(150)),n.wipe&&await no(t,Si,{kind:"swap-exit"}),await vi(t,n.text,{perCharDelayMs:90,kind:"swap-exit"});let r=$e(e).submitDelayMs||0;await Ui(Math.max(r,250)),await It(t,["Enter"],{kind:"swap-exit"})}async function iR(t,e){try{let{stdout:n}=await mo(L,U("show-environment","-t",t,e));return!String(n||"").trimStart().startsWith("-")}catch{return!1}}async function Fg(t){await mo(L,U("respawn-pane","-k","-t",t))}async function td(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)||rR;await V({flow:"swap",phase:"start",sessionName:t,from:o,to:s,cwd:r.cwd});let i=!1;if(!await eo(t)&&(await aR(t,o),!await Qu(t,a)&&(i=!0,await V({flow:"swap",phase:"respawn-forced",sessionName:t,from:o}),await Fg(t),!await Qu(t,jg))))throw new Error(`pane shell did not come back after respawn-pane in "${t}"`);let c=s==="claude"&&ur(n),l=c?Qa():null,u=await iR(t,"ANTHROPIC_API_KEY"),d=!1;try{l?(await mo(L,U("set-environment","-t",t,"ANTHROPIC_API_KEY",l)),d=!0):u&&(await mo(L,U("set-environment","-u","-t",t,"ANTHROPIC_API_KEY")),d=!0)}catch(y){throw l?wi(y,l):y}if(d&&!i&&(await Fg(t),!await Qu(t,jg)))throw new Error(`pane shell did not come back after env respawn in "${t}"`);let f=!!e.resumeSessionId,h=e.resumeSessionId||nR(),p=f?n:nu(n,h,t),w=f?e.pinned===!0:/(^|\s)--session-id(\s|=)/.test(p);return c&&await gn(r.cwd),s==="codex"&&await Kr(r.cwd),s==="cursor"&&await Gr(r.cwd),await dr(t),await mo(L,U("set-option","-t",t,"@bostrat-sid",h)),await mo(L,U("set-option","-t",t,"@bostrat-agent",s)),await Ui(sR),await Pt(t,p,{kind:"swap-launch"}),await V({flow:"swap",phase:"done",sessionName:t,from:o,to:s,sid:h,forced:i,envRespawned:d}),{name:t,cwd:r.cwd,sessionId:h,agent:s,pinned:w,forced:i,envRespawned:d}}var mo,Ui,rR,jg,oR,sR,Lg,Ug=M(()=>{Kt();us();ei();ni();Is();Ke();mo=eR(tR),Ui=t=>new Promise(e=>setTimeout(e,t)),rR=Number(process.env.BOSTRAT_SWAP_EXIT_TIMEOUT_MS)||15e3,jg=Number(process.env.BOSTRAT_SWAP_SHELL_TIMEOUT_MS)||8e3,oR=250,sR=400,Lg={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 Hg(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 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 h=f.input||{};o.set(f.id,{id:f.id,kind:"agent",name:String(h.description||"").trim()||null,detail:String(h.subagent_type||"").trim()||null,ts:d,proven:!1})}else if(f.name==="Bash"&&f.input?.run_in_background===!0){let h=String(f.input.command||"").trim();o.set(f.id,{id:f.id,kind:"command",name:String(f.input.description||"").trim()||(h?co(h):null),detail:h?co(h):null,ts:d,proven:!0})}}else f.type==="tool_result"&&f.tool_use_id&&cR.test(lR(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 cR,lR,Wg=M(()=>{ye();lo();cR=/^Async (?:agent|task) launched/i,lR=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 uR(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 qg(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 ${ho(r)}`:`Read ${ho(r)}`}}case"Grep":{let r=e?.pattern;if(!r)return null;let o=e?.path?Nn(e.path,n):null,s=e?.glob?` --glob ${ed(e.glob)}`:"",a=ke(String(r),40);return{command:ke(`grep ${ed(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 ${ed(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 ${ho(e.path)}`}:null;case"Write":return e?.path?{command:ke(`write ${Nn(e.path,n)}`,140),description:`Write ${ho(e.path)}`}:null;case"Delete":return e?.path?{command:ke(`delete ${Nn(e.path,n)}`,140),description:`Delete ${ho(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=uR(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 ${ho(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 Hi,ke,ho,ed,Kg=M(()=>{Hi=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,ho=t=>String(t).replace(/\/+$/,"").split("/").pop()||String(t);ed=t=>`"${String(t).replace(/"/g,'\\"')}"`});import js from"node:fs";import dR from"node:fs/promises";import gr from"node:path";import fR from"node:os";import pR from"node:crypto";import mR from"node:zlib";function zg(t){let e=pR.createHash("md5").update(String(t)).digest("hex");return gr.join(hR,e)}function Jg(t){try{let e=JSON.parse(js.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 wR(t){let e=zg(t),n;try{n=js.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(!js.existsSync(a))continue;let i=Jg(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 Wi(t,e){if(!t)return null;if(e){let n=gr.join(zg(t),e),r=gr.join(n,"store.db");if(js.existsSync(r))return{id:e,dir:n,store:r,...Jg(n)||{createdAtMs:null,updatedAtMs:null}}}return wR(t)}function Gg(t,e){let n=t.prepare("SELECT data FROM blobs WHERE id = ?").get(e);return n?Buffer.from(n.data):null}function gR(t){if(!t)return null;let e=t;if(e.length>1&&e[0]===31&&e[1]===139)try{e=mR.gunzipSync(e)}catch{}try{return JSON.parse(e.toString("utf8"))}catch{return null}}function yR(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 bR(t,e){if(!Array.isArray(t))return[];let n=[];for(let r of t){if(!r||r.type!=="tool-call"||!Hi.has(r.toolName))continue;let o=qg(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 nd(t,e){if(!Vg)return wo;let{DatabaseSync:n}=Vg,r;try{r=new n(t,{readOnly:!0})}catch{return wo}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 wo;let s;try{s=JSON.parse(Buffer.from(String(o.value),"hex").toString("utf8"))}catch{return wo}let a=s.lastUsedModel||null,i=s.latestRootBlobId?Gg(r,s.latestRootBlobId):null;if(!i)return{...wo,model:a};let c=[],l=[],u=[],d=null,f=[];for(let h of yR(i)){let p=gR(Gg(r,h));if(!p)continue;let w=p.providerOptions?.cursor;if(w?.requestId&&f.push(w.requestId),w?.modelProviderMessageId&&f.push(w.modelProviderMessageId),p.role!=="assistant")continue;if(Array.isArray(p.content))for(let x of p.content){let E=x?.providerOptions?.cursor?.modelName;E&&(d=E)}l.push(...bR(p.content,e).map((x,E)=>({...x,id:x.id||`${h}:${E}`}))),u.push(...xR(p.content));let y=kR(p.content);if(!y)continue;let k=[...new Set(u)];u=[],c.push({id:h,text:y,tools:k.length?k:void 0,commands:l,model:d}),l=[]}return{turns:c,trailingCommands:l,model:a,requestIds:f}}catch{return wo}finally{try{r.close()}catch{}}}function Yg(t,e){let n=t.updatedAtMs;if(!n)try{n=Math.round(js.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 Xg(t,e,{limit:n=80}={}){let r=Wi(t,e);if(!r)return[];let{turns:o,model:s}=await nd(r.store,t);if(!o.length)return[];let a=o.slice(-n),{tsAt:i}=Yg(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 Zg(t,e){let n=Wi(t,e);if(!n)return null;let{turns:r,requestIds:o,model:s}=await nd(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 Qg(t,e,{limit:n=80}={}){let r=Wi(t,e);if(!r)return[];let{turns:o,trailingCommands:s}=await nd(r.store,t);if(!o.length&&!s.length)return[];let a=o.slice(-n),{end:i,tsAt:c}=Yg(r,a.length||1),l=[];a.forEach((u,d)=>{for(let f of u.commands)l.push({...f,summary:Rn(f.command,f.description),ts:c(d)})});for(let u of s)l.push({...u,summary:Rn(u.command,u.description),ts:i+1});return l}async function ty(t,e){let n=Wi(t,e);if(!n)return null;if(n.updatedAtMs)return n.updatedAtMs;try{return Math.round((await dR.stat(n.store)).mtimeMs)}catch{return null}}var hR,kR,xR,Vg,wo,rd=M(()=>{lo();Kg();hR=process.env.BOSTRAT_CURSOR_CHATS||gr.join(fR.homedir(),".cursor","chats");kR=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():"",xR=t=>Array.isArray(t)?t.filter(e=>e&&e.type==="tool-call"&&e.toolName).map(e=>e.toolName):[],Vg=process.getBuiltinModule?.("node:sqlite"),wo={turns:[],trailingCommands:[],model:null,requestIds:[]}});import SR from"node:fs/promises";function id(t){return ey.set(t.agent,t),t}function Ls(t){return ey.get(t)||vR}async function ld(t,e={}){return(await Ls(t.agent).readMessages(t,e)).map(cd(t))}async function ny(t,e={}){return(await Ls(t.agent).readCommands(t,e)).map(cd(t))}async function ry(t,e={}){return(await Ls(t.agent).readJobs(t,e)).map(cd(t))}var go,od,sd,ad,vR,ey,cd,oy=M(()=>{ye();Ai();lo();Wg();rd();uo();go=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}},od=class extends go{transcript(e){return!e?.cwd||!e?.sessionId?null:Ge(e.cwd,e.sessionId)}async readMessages(e,n){let r=this.transcript(e);return r?lu(r,n):[]}async readCommands(e,n){let r=this.transcript(e);return r?Cw(r,n):[]}async readJobs(e,n){let r=this.transcript(e);return r?Hg(r,n):[]}async updatedAt(e){let n=this.transcript(e);if(!n)return null;try{return Math.round((await SR.stat(n)).mtimeMs)}catch{return null}}},sd=class extends go{async readMessages(e,n){return Xg(e.cwd,e.sessionId,n)}async readCommands(e,n){return Qg(e.cwd,e.sessionId,n)}async updatedAt(e){return ty(e.cwd,e.sessionId)}},ad=class extends go{sessionId(e){return e?.pinned?e.sessionId:null}async readMessages(e,n){return Bw(e.cwd,this.sessionId(e),n)}async readCommands(e,n){return Dw(e.cwd,this.sessionId(e),n)}async updatedAt(e){return jw(e.cwd,this.sessionId(e))}},vR=new go("unknown"),ey=new Map;id(new od("claude",_u));id(new sd("cursor",Hi));id(new ad("codex",Ms));cd=t=>e=>({...e,box:t.name,agent:t.agent,boxRole:t.role})});function kr(t){let e=t.search(pd);return(e>=0?t.slice(0,e):t).trim()}function TR(t){if(!t)return"";let e=t.replace(/[│┌└├─┘┤┬┴┼─✂].*$/,"").trim();return!e||/hidden|\d+\s+lines?/i.test(e)?"":e}function AR(t){let e=String(t).trim();return!!(!e||br.test(t)||pd.test(e)||/hidden|\d+\s+lines?/i.test(e)||/notespress|press n to add/i.test(e)||/^\s*notes?\s*$/i.test(e))}function ER(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=_R(n,e);return n.forEach((a,i)=>{a.current=i===s}),{tabs:n,questionIndex:s,questionTotal:n.length,currentTabLabel:n[s].label}}function _R(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 ay(t){return t.replace(/[←→✔☐☒●▶]/g," ").replace(/\bSubmit\b/g," ").replace(/\s+/g," ").trim()}function IR(t,e=""){let n=String(t);if(!cy.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(yr);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&&!br.test(r[u])&&a.push(f)}}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||!ly.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&&!(RR.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 OR(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 MR(t,e=""){let n=String(t);if(!ud.test(n))return null;let r=n.replace(/\r/g,"").split(`
117
- `),o=-1;for(let u=r.length-1;u>=0;u--)if(CR.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(yr);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&&!br.test(r[u])&&a.push(f)}}if(s.length<2||!s.some(u=>ud.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 md(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 NR(t,e=""){let n=String(t);if(!uy.test(n)||!dy.test(n)||xr.test(n))return null;let r=n.replace(/\r/g,"").split(`
118
- `),o=md(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 PR(t,e=""){let n=String(t);if(!fy.test(n)||xr.test(n))return null;let r=n.replace(/\r/g,"").split(`
119
- `),o=md(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 DR(t,e){let n=t[e].trim();for(let r=e+1;r<t.length;r++){let o=t[r].trim();if(!o||!BR.test(o)||hd.test(t[r]))break;n+=o}return n}function jR(t,e=""){let n=String(t);if(!hd.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=DR(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 FR(t,e=""){let n=String(t);if(!dd.test(n)||!LR.test(n)||xr.test(n))return null;let s=([...n.replace(/\r/g,"").split(`
121
- `)].reverse().find(a=>dd.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 UR(t,e=""){let n=String(t);if(!py.test(n)||xr.test(n))return null;let r=n.replace(/\r/g,"").split(`
122
- `),o=md(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 HR(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(my);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])||pd.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 WR(t){let e=-1;for(let r=t.length-1;r>=0;r--)if(fd.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 qR(t,e=""){let n=String(t);if(!iy.test(n)||!fd.test(n))return null;let r=n.replace(/\r/g,"").split(`
124
- `),o=WR(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 B=r[T].match(yr);B&&(u<0&&(u=T),l.push({line:T,cursor:!!B[1],checked:B[3]!=null&&B[3]!==" ",hasCheckbox:B[3]!=null,label:B[4].trim(),desc:""}))}if(!l.length)return null;for(let T of l)for(let B=T.line+1;B<Math.min(r.length,T.line+4)&&!(yr.test(r[B])||br.test(r[B]));B++){let j=r[B].trim();if(!(!j||AR(r[B])||sy.test(j))){T.desc=TR(j);break}}let d=l.filter(T=>!sy.test(T.label));if(!d.length)return null;let f=d.some(T=>T.hasCheckbox),h=Math.max(0,d.findIndex(T=>T.cursor)),p=s>=0?s+1:0,w=[];for(let T=p;T<u;T++){let B=r[T].trim();B&&!br.test(r[T])&&!/[☐☒]/.test(r[T])&&w.push(B)}let y=w.join(" ")||(s>=0?ay(r[s]):"")||"The agent is asking a question",k=s>=0?ER(r[s],y):null,x=k?.currentTabLabel||(s>=0?ay(r[s]):""),E=d.map(T=>({label:kr(T.label),description:T.desc})),$=E.map(T=>T.label).join("|"),C=`claude:${k?`q${k.questionIndex+1}/${k.questionTotal}`:"q1/1"}:${x}:${y}:${$}`.slice(0,240),N=k?`claude:ask:${k.tabs.map(T=>T.label).join("|")}`.slice(0,240):C;return{provider:"claude",box:e,multiSelect:f,cursorIndex:h,promptId:C,groupId:N,...k?{questionIndex:k.questionIndex,questionTotal:k.questionTotal,currentTabLabel:k.currentTabLabel,tabs:k.tabs}:{},questions:[{question:y,header:x,multiSelect:f,options:E}]}}function yo(t,e){let n=String(e||"");return n?t==="claude"?iy.test(n)&&fd.test(n)||cy.test(n)||ud.test(n)||ly.test(n.trimEnd().split(`
125
- `).pop()||"")?!0:xr.test(n)?!1:uy.test(n)&&dy.test(n)||fy.test(n)||hd.test(n)||dd.test(n)||py.test(n)||my.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"?OR(e,t.name)||qR(e,t.name)||IR(e,t.name)||MR(e,t.name)||FR(e,t.name)||jR(e,t.name)||PR(e,t.name)||NR(e,t.name)||UR(e,t.name)||HR(e,t.name)||$R(e,t.name):t.agent==="cursor"||t.agent==="codex"?uw(t.agent,e,t.name):null}async function wd(t){if(!t)return null;let e=await En(t.name).catch(()=>"");return Sr(t,e)}function hy(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 wy(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 iy,fd,yr,sy,br,pd,cy,ly,RR,ud,CR,xr,uy,dy,fy,hd,BR,dd,LR,py,my,gd=M(()=>{Kt();Ei();iy=/to navigate\b.*\bEsc to cancel|Enter to select\b/,fd=/Chat about this/i,yr=/^\s*(❯)?\s*(\d+)\.\s+(?:\[([ xX✔])\]\s+)?(.+?)\s*$/,sy=/^(type something|chat about this|submit)\b/i,br=/^[─—-]{6,}\s*$/,pd=/[\u2500-\u257F\u2550-\u256F┌┐└┘├┤│┬┴┼─✂]/;cy=/^\s*Switch model\?\s*$/m;ly=/^\s*Enter to confirm\s*·\s*Esc to cancel\s*$/,RR=/^\s*[─—▔-]{6,}\s*$/;ud=/Resume from summary/i,CR=/^\s*This session is\b/;xr=/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/;uy=/Choose the text style that looks best with your terminal/,dy=/Let's get started\./;fy=/Select login method:/;hd=/Paste code here if prompted/,BR=/^[A-Za-z0-9%&=+._~#?/:\-]+$/;dd=/OAuth error:/,LR=/Press Enter to retry\./;py=/Quick safety check: Is this a project you created or one you trust/;my=/^(.{0,60}?)Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/});function qi(t,e,n){if(!t||!e)return null;for(let r of KR)if(r.provider===t.agent)try{if(r.match(e,n))return r}catch{}return null}function VR(t){let e=yd.get(t);return e||(e={sentAt:[],last:0,emitted:new Set},yd.set(t,e)),e}function by(t,e,n=Date.now()){let r=VR(t);if(r.sentAt=r.sentAt.filter(s=>n-s<yy),r.sentAt.length>=gy)return{action:"give-up"};if(n-r.last<GR)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 ky(t,e=Date.now()){let n=yd.get(t);return n?n.sentAt.filter(r=>e-r<yy).length>=gy:!1}var KR,GR,gy,yy,yd,bd=M(()=>{KR=[{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"]}];GR=5e3,gy=5,yy=3600*1e3,yd=new Map});function bo(t){return typeof t=="string"?t.trim():""}var xy=M(()=>{});import{execFile as zR}from"node:child_process";import{promisify as JR}from"node:util";async function _t(t,e,{input:n}={}){let r=xd("git",["-C",t,...e],{maxBuffer:Sy});return n!==void 0&&r.child.stdin&&(r.child.stdin.on("error",()=>{}),r.child.stdin.end(n)),r}async function Ki(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 vy(t){let{stdout:e}=await _t(t,["rev-parse","--show-toplevel"]);return e.trim()}async function YR(t){try{return await _t(t,["rev-parse","--verify","HEAD"]),!0}catch{return!1}}async function ko(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)=>xd("git",["-C",t,...a],{maxBuffer:Sy,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 xd("rm",["-f",r])}catch{}}}async function Sd(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 vd(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 Td(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 xo(t,e,n,r){return await _t(t,["worktree","add","--no-track","-b",n,e,r]),e}async function Ty(t,e){try{return await _t(t,["rev-parse","--verify","--quiet",`refs/heads/${e}`]),!0}catch{return!1}}async function Gi(t,e,n){return await _t(t,["worktree","add",e,n]),e}async function So(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 Ad(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 XR(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 Ed(t,e){return!e||!e.length?t:[...t,"--",".",...e.map(n=>`:(exclude)${n}`)]}async function _d(t,e,n,r){let{stdout:o}=await _t(t,Ed(["diff","--shortstat",e,n],r));return XR(o)}async function Id(t,e,n,r){let{stdout:o}=await _t(t,Ed(["diff","--name-only",e,n],r));return o.split(`
129
- `).map(s=>s.trim()).filter(Boolean)}async function Rd(t,e,n,r){let{stdout:o}=await _t(t,Ed(["diff","--binary",e,n],r));if(!o.trim())return{applied:!0,empty:!0,conflicts:[]};if((await kd(t,o,["--whitespace=nowarn"])).ok)return{applied:!0,empty:!1,conflicts:[]};let s=await kd(t,o,["--3way","--whitespace=nowarn"]),a=await ZR(t);return a.length>0?{applied:!1,empty:!1,conflicts:a}:s.ok?{applied:!0,empty:!1,conflicts:[]}:(await kd(t,o,["--reject","--whitespace=nowarn"]),{applied:!1,empty:!1,conflicts:[`patch did not apply cleanly: ${s.err}`]})}async function kd(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 ZR(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 xd,Sy,$d=M(()=>{xd=JR(zR),Sy=64*1024*1024});import Od from"node:fs/promises";import Ey from"node:path";import QR from"node:os";function $y(t){let e=new Date(t);return e.setHours(0,0,0,0),e.setDate(e.getDate()-(e.getDay()+6)%7),e.getTime()}function Oy(t){let e=new Date(t);return e.setHours(0,0,0,0),e.setDate(1),e.getTime()}function Cy(t){let e=new Date($y(t));return e.setDate(e.getDate()+7),e.getTime()}function My(t){let e=new Date(Oy(t));return e.setMonth(e.getMonth()+1),e.getTime()}function zi(t=Date.now()){for(let[e,n]of Object.entries(vo)){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 To)o.includes(`:${e}:`)&&!o.endsWith(`:${r}`)&&To.delete(o)}}}function Ny(t,e){let n=xe?.caps?.[t]?.[vo[e].capKey];return Number.isFinite(n)&&n>0?n:null}function Tr(t,e=Date.now()){if(!t||!Md||!xe?.caps)return null;zi(e);let n=vr.get(t);for(let r of Object.keys(vo)){let o=Ny(t,r);if(o==null)continue;let s=n?.[r]||0;if(s>=o)return{provider:t,window:r,limitUsd:o,spentUsd:Vi(s),resetsAt:vo[r].nextStart(e)}}return null}function Py(t,e){let n=`hit:${t}:${e.provider}:${e.window}:${ze[e.window]}`;return To.has(n)?!1:(To.add(n),!0)}function Ay(t,e,n,r=Date.now()){if(!t||!e)return;zi(r);let o=t$(t);for(let[s,a]of Object.entries(vo))n>=ze[s]&&n<a.nextStart(r)&&(o[s]+=e)}async function e$(t,e,n=Date.now()){if(!xe?.caps||!Cd)return;let r=vr.get(t);if(r)for(let[o,s]of Object.entries(vo)){let a=Ny(t,o);if(a==null)continue;let i=r[o]||0;if(i<a*Ry||i>=a)continue;let c=`warn:${t}:${o}:${ze[o]}`;if(!To.has(c)){To.add(c);try{let l=await Cd(e);if(!l)continue;await I(l,{type:"usage.cap.warning",actor:"system",provider:t,payload:{provider:t,window:o,limitUsd:a,spentUsd:Vi(i),pct:Math.round(i/a*100),resetsAt:s.nextStart(n)}})}catch{}}}}function By(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 Ji(t,{source:e="local",updatedAt:n=Date.now()}={}){xe={caps:By(t),updatedAt:n,source:e};try{await Od.mkdir(_y,{recursive:!0}),await Od.writeFile(Iy(),JSON.stringify(xe,null,2))}catch{}return Fs()}function Fs(t=Date.now()){zi(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:Vi(o?.weekly||0),monthlyUsd:Vi(o?.monthly||0)}}return{caps:xe?.caps||{},configured:!!xe,seeded:Md,updatedAt:xe?.updatedAt??null,spent:n,windows:{weekly:{start:ze.weekly,resetsAt:Cy(t)},monthly:{start:ze.monthly,resetsAt:My(t)}},warnPct:Ry}}async function Dy({listTracks:t,getTrack:e}={}){Cd=e||null,zi();try{let o=JSON.parse(await Od.readFile(Iy(),"utf8"));xe={caps:By(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);Ay(o.provider||"unknown",s,o.ts??Date.now()),e$(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||Ay(a.provider||"unknown",Ve(a).usd,i,n)}}return Md=!0,Fs()}var _y,Iy,Ry,vo,xe,Md,ze,vr,To,Cd,t$,Vi,Yi=M(()=>{ot();wr();_y=process.env.BOSTRAT_STATE_DIR||Ey.join(process.env.HOME||QR.tmpdir(),".bostrat"),Iy=()=>Ey.join(_y,"usage-caps.json"),Ry=.8;vo={weekly:{startOf:$y,nextStart:Cy,capKey:"weeklyUsd"},monthly:{startOf:Oy,nextStart:My,capKey:"monthlyUsd"}},xe=null,Md=!1,ze={weekly:0,monthly:0},vr=new Map,To=new Set,Cd=null,t$=t=>{let e=vr.get(t);return e||(e={weekly:0,monthly:0},vr.set(t,e)),e};Vi=t=>Math.round(t*1e4)/1e4});import n$ from"node:fs/promises";import r$ from"node:os";import jy from"node:path";function Ky(t){return t==="codex"?i$:t==="cursor"?qy:Hy}function Ly(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 Fy(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 c$(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 Uy(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 Gy(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&&!Wy.has(o))throw new Error(`unknown codex effort "${o}" (low | medium | high | xhigh)`);return{model:r,effort:o||null}}if(t==="cursor"){let r=qy.find(o=>o.alias===n);return{model:n,filter:r?r.label:n}}if(!a$.has(n))throw new Error(`unknown model "${n}"`);return{model:n}}async function Us(t,e,{timeoutMs:n=o$}={}){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 Xi(s$)}}async function l$(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 u$(t,e){await xi(t),await Pt(t,"/model",{enter:!1}),await Xi(250),await It(t,["Enter"],{kind:"model-switch"});let n=await Us(t,Ly);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=c$(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 Us(t,i=>Fy(i)||!Ly(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?Wy.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 Us(t,i=>!Fy(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 d$(){let t=jy.join(process.env.CURSOR_CONFIG_DIR||jy.join(r$.homedir(),".cursor"),"cli-config.json");try{return JSON.parse(await n$.readFile(t,"utf8"))?.model||null}catch{return null}}async function f$(t,e){await xi(t),await vi(t,`/model ${e.filter}`,{kind:"model-switch"});let n=await Us(t,Uy),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 Us(t,Uy,{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 Xi(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 Xi(800);let a=await d$();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 Vy(t,e,n){return t==="codex"?u$(e,n):t==="cursor"?f$(e,n):l$(e,n)}var Xi,o$,s$,Hy,a$,i$,Wy,qy,zy=M(()=>{Kt();Is();Xi=t=>new Promise(e=>setTimeout(e,t)),o$=Number(process.env.BOSTRAT_MODEL_PICKER_TIMEOUT_MS)||8e3,s$=300,Hy=[{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"}],a$=new Set([...Hy.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"]),i$=[{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"}],Wy=new Map([["low","Low"],["medium","Medium"],["high","High"],["xhigh","Extra high"]]),qy=[{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 Qi(t){let e=t||{},n=p$(e);return n&&(n.payload={ts:e.at,...n.payload}),n}function p$(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 Xy(t,e){let n=Qi(e);if(!n)return;let r=e?.type==="track-deleted"?{id:t.id}:t;Pd(()=>I(r,n))}async function Zy(t){if(!(!t?.id||Jy.has(t.id))){Jy.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=Qi(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 Qy(t,e,n){!n?.promptId||Nd.get(t.id)===n.promptId||(Nd.set(t.id,n.promptId),Pd(()=>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 Bd(t,e,n,r={}){Nd.delete(t.id),Pd(()=>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,Zi,Pd,Yy,Jy,Nd,Dd=M(()=>{ot();Qt=t=>t||null;Zi=Promise.resolve(),Pd=t=>(Zi=Zi.then(t).catch(()=>{}),Zi),Yy=()=>Zi;Jy=new Set;Nd=new Map});function y$(t){return String(t).split(/(?<=[.?!])\s+|\n+/).map(e=>e.trim()).filter(Boolean)}function sb(t){let e=String(t||"").trim();if(!e)return null;let n=e.slice(-600);for(let r of y$(n).reverse()){if(!m$.test(r))continue;let o=r.endsWith("?")&&r.length<=g$&&w$.test(r);if(h$.test(r)||o)return r.length>200?r.slice(0,197)+"\u2026":r}return null}function ab(t){let e=String(t||""),n=[];b$.test(e)&&n.push("commit"),k$.test(e)&&n.push("rebase"),x$.test(e)&&n.push("push");let r=v$.test(e);!r&&S$.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 Ao(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(h=>`${h.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 h=a.has("commit")?"the branch":`this branch${e?` (${e})`:""}`;u.push(i?`rebase ${h} in each changed checkout (${c}) onto its own base branch (fetch origin first), resolving any conflicts so both sides' intent is preserved`:`rebase ${h} 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 h=r&&!a.has("pr")?` (the open PR${r.number?` #${r.number}`:""} picks it up)`:"",p=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${p}${h}`:`push this branch${e?` (${e})`:""} from each changed checkout (${c}) to its remote${h}`):u.push(a.has("commit")||a.has("rebase")?`push it to the remote${p}${h}`:`push this branch${l} to the remote${h}`)}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(/^./,h=>h.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 ib(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 cb(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<=T$&&n.push({box:r.box,from:r.from,to:e+1e12}),n}function lb(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+A$||(!o||s.ts>=o.ts)&&(o=s);o&&n.add(o)}return n}function ub(t){let e=(Array.isArray(t)?t:[]).filter(r=>tb[r]).map(r=>tb[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 eb,nb,rb,ob,m$,h$,w$,g$,tc,b$,k$,x$,S$,v$,T$,A$,tb,Eo=M(()=>{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|amend(?:ed)?|squash|merge|follow[\s-]?up|clean[\s-]?up)\s)commit(?!s\b)(?!\s+(?:history|log|message|hash|sha)s?\b)/.source,nb=/(?<!\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,rb=/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,ob=/(?<!\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,m$=new RegExp(`\\b(?:${eb}|${nb}|${rb}|${ob})\\b`,"i"),h$=/\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,w$=/^(?:commit|push|open|create|raise|rebase|ready|ok(?:ay)?\s+to|good\s+to)\b/i,g$=90;tc=["commit","rebase","push","pr"],b$=new RegExp(`\\b(?:${eb})\\b`,"i"),k$=new RegExp(`\\b(?:${ob})\\b`,"i"),x$=new RegExp(`\\b(?:${nb})\\b`,"i"),S$=new RegExp(`\\b(?:${rb})\\b`,"i"),v$=/\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;T$=3e4;A$=2500;tb={commit:"commit",rebase:"rebase",push:"push",pr:"open a PR"}});import E$ from"node:fs";import jd from"node:fs/promises";import mb from"node:path";import _$ from"node:os";function gb(t,e=!1){if(!e&&t-fb<I$)return;fb=t;let n=JSON.stringify({windowStart:_o,byCaller:Object.fromEntries(Je),lastHour:Pn});pb=pb.then(()=>jd.mkdir(hb,{recursive:!0})).then(()=>jd.writeFile(`${ec}.tmp`,n)).then(()=>jd.rename(`${ec}.tmp`,ec)).catch(()=>{})}function yb(t){t-_o<wb||(Pn={start:_o,total:nc(Je),byCaller:Object.fromEntries(Je)},Pn.total&&console.log(`[github] ${Pn.total} calls last hour`,Pn.byCaller),_o=t,Je=new Map,gb(t,!0))}function Ye(t="other",e=Date.now()){yb(e),Je.set(t,(Je.get(t)||0)+1),gb(e)}function bb(t=Date.now()){return yb(t),{windowStart:_o,total:nc(Je),byCaller:Object.fromEntries(Je),lastHour:Pn,backoffUntil:Er>t?Er:null}}function Bn(t){return R$.test(String(t?.message||t||""))}function Dn(t,e=Date.now()){return Er<=e&&console.warn(`[github] rate limited \u2014 backing off ${db/6e4} min:`,String(t?.message||t||"").slice(0,200)),Er=Math.max(Er,e+db),Er}function rc(t=Date.now()){return Math.max(0,Er-t)}var hb,ec,wb,db,I$,_o,Je,Pn,Er,fb,nc,pb,R$,Hs=M(()=>{hb=process.env.BOSTRAT_STATE_DIR||mb.join(process.env.HOME||_$.tmpdir(),".bostrat"),ec=mb.join(hb,"github-metrics.json"),wb=60*6e4,db=5*6e4,I$=6e4,_o=Date.now(),Je=new Map,Pn=null,Er=0,fb=0,nc=t=>[...t.values()].reduce((e,n)=>e+n,0);try{let t=JSON.parse(E$.readFileSync(ec,"utf8"));t?.windowStart&&(Date.now()-t.windowStart<wb?(_o=t.windowStart,Je=new Map(Object.entries(t.byCaller||{})),Pn=t.lastHour||null):nc(new Map(Object.entries(t.byCaller||{})))&&(Pn={start:t.windowStart,total:nc(new Map(Object.entries(t.byCaller||{}))),byCaller:t.byCaller||{}}))}catch{}pb=Promise.resolve();R$=/rate limit|too quickly|abuse detection|HTTP 429/i});import $$ from"node:crypto";import oc from"node:fs/promises";import kb from"node:path";import O$ from"node:os";async function Rt(){return jn||(Ld??=oc.readFile(Ud,"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[z(i.repo,i.number)]=i}Object.keys(jn).length&&await Hd().catch(()=>{})}}return jn}).finally(()=>Ld=null),Ld)}async function Hd(){let t=JSON.stringify({links:jn},null,2),e=`${Ud}.${process.pid}.tmp`;await oc.mkdir(xb,{recursive:!0}),await oc.writeFile(e,t),await oc.rename(e,Ud)}async function Bt(t){Fd=Fd.then(Hd,Hd),await Fd.catch(()=>{});let e=jn?.[t];e&&qt("prlinks",{id:Sb(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=z(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:C$.has(a),firstSeen:Date.now()},await Bt(z(t,e)),{link:i[c],created:!0})}async function Ws(t,e){if(!t||e==null)return null;let n=(await Rt())[z(t,e)];return!n||n.announced?null:(n.announced=!0,await Bt(z(t,e)),n)}async function Gt(t,e){return!t||e==null?null:(await Rt())[z(t,e)]??null}async function Ln(t,e,n){if(!t||e==null)return null;let r=(await Rt())[z(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 Bt(z(t,e)),r):null}async function vb(t,e,{headSha:n=null,trackId:r=null}={}){if(!t||e==null)return null;let o=(await Rt())[z(t,e)];return o?(o.ciFix={delegatedAt:Date.now(),headSha:n,trackId:r},await Bt(z(t,e)),o):null}async function Tb(t,e,{headSha:n=null,trackId:r=null}={}){if(!t||e==null)return null;let o=(await Rt())[z(t,e)];return o?(o.reconcile={delegatedAt:Date.now(),headSha:n,trackId:r},await Bt(z(t,e)),o):null}async function sc(t,e,{headSha:n=null}={}){if(!t||e==null)return null;let r=(await Rt())[z(t,e)];return!r||!r.ciFix?null:(r.ciFixAwait={since:Date.now(),trackId:r.ciFix.trackId??null,headSha:n},delete r.ciFix,await Bt(z(t,e)),r)}async function ac(t,e){if(!t||e==null)return null;let n=(await Rt())[z(t,e)];return!n||!n.ciFixAwait?null:(delete n.ciFixAwait,await Bt(z(t,e)),n)}async function ic(t,e,{headSha:n=null}={}){if(!t||e==null)return null;let r=(await Rt())[z(t,e)];return!r||!r.reconcile?null:(r.reconcileAwait={since:Date.now(),trackId:r.reconcile.trackId??null,headSha:n},delete r.reconcile,await Bt(z(t,e)),r)}async function cc(t,e){if(!t||e==null)return null;let n=(await Rt())[z(t,e)];return!n||!n.reconcileAwait?null:(delete n.reconcileAwait,await Bt(z(t,e)),n)}async function Ab(t,e,{at:n=Date.now()}={}){if(!t||e==null)return null;let r=(await Rt())[z(t,e)];return r?(r.baseFoldAt=n,await Bt(z(t,e)),r):null}async function Eb(t,e){if(!t||e==null)return null;let n=(await Rt())[z(t,e)];return!n||!n.baseFoldAt?null:(delete n.baseFoldAt,await Bt(z(t,e)),n)}async function _b(t,e,n){if(!t||e==null||!n)return null;let r=(await Rt())[z(t,e)];return r?(r.lastHeadSha=n,await Bt(z(t,e)),r):null}async function qs(t,e,{merge:n=null}={}){if(!t||e==null)return null;let r=(await Rt())[z(t,e)];return r?(r.armedAt=Date.now(),n&&(r.autoMerge={method:n.method||"merge",armedAt:r.armedAt}),await Bt(z(t,e)),r):null}async function _r(t,e,n=!0){if(!t||e==null)return null;let r=(await Rt())[z(t,e)];return r?(n?r.archiveOnMerge=!0:delete r.archiveOnMerge,await Bt(z(t,e)),r):null}async function Ks(t,e,n=!0){if(!t||e==null)return null;let r=(await Rt())[z(t,e)];return r?(n?r.notifyOnMerge=!0:delete r.notifyOnMerge,await Bt(z(t,e)),r):null}async function Ib(t,e,n){if(!t||e==null)return null;let r=(await Rt())[z(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 Bt(z(t,e)),r}async function Gs(t,e){if(!t||e==null)return null;let n=(await Rt())[z(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 Bt(z(t,e)),n)}async function Rb(){return Object.values(await Rt()).filter(t=>!M$.has(t.state))}async function Ir(){return Object.values(await Rt()).sort((t,e)=>e.firstSeen-t.firstSeen)}async function $b(){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 qt("prlinks",{id:Sb(o),updatedAt:Date.now(),...s},{trackId:s.trackId??null}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}var xb,Ud,z,Sb,jn,Ld,Fd,C$,M$,Fn=M(()=>{Sn();xb=process.env.BOSTRAT_STATE_DIR||kb.join(process.env.HOME||O$.tmpdir(),".bostrat"),Ud=kb.join(xb,"pr-links.json"),z=(t,e)=>`${t}#${Number(e)}`,Sb=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,Ld=null,Fd=Promise.resolve();C$=new Set(["api","observed","reconciled"]);M$=new Set(["merged","closed","lost"])});function lc(t,e,n){let{state:r,reason:o}=hu(e,n);if(r!=="unknown"){if(t){let a=Date.now();for(let[i,c]of Vs)a-c.at>=Ob()&&Vs.delete(i);Vs.set(t,{busy:r==="busy",at:a})}return r==="busy"}if(o!=="narrow"||!t)return!1;let s=Vs.get(t);return s?Date.now()-s.at>=Ob()?(Vs.delete(t),!1):s.busy:!1}async function Wd(t,e){let n={working:!1,prompted:!1};if(!t)return n;let r=await Tt(t,{lines:Nt}).catch(()=>"");if(!lc(t,e,r))return mw(e,r)?{working:!0,prompted:!1}:n;if(yo(e,r)){let o=await En(t).catch(()=>r),s=Sr({name:t,agent:e},o);if(s)return!qi({name:t,agent:e},s,o)||ky(t)?{working:!1,prompted:!0}:{working:!1,prompted:!1}}return{working:!0,prompted:!1}}async function uc(t,e){return(await Wd(t,e)).working}var Ob,Vs,dc=M(()=>{Kt();$i();gd();bd();Ob=()=>Number(process.env.BOSTRAT_NARROW_CARRY_MS)||9e4,Vs=new Map});import{execFile as N$}from"node:child_process";import{promisify as P$}from"node:util";async function qd(t,e,{midTurn:n=uc,pollMs:r=B$,capMs:o=D$}={}){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 G$(t,e){let n=String(t||"").match(K$);return!!n&&n[1]!==e}function Kd(t,e){return t.slice(e).replace(/^[\s;&|)]+/,"").replace(/"[^"]*"|'[^']*'/g,'""').split(/[;&|]/)[0]}function Pb(t){let e=String(t||""),n=e.match(U$);if(!n)return null;let r=Kd(e,n.index);return W$.test(r)?null:{repo:r.match(Nb)?.[1]??null,head:r.match(q$)?.[1]??null}}function Bb(t){let e=String(t||""),n=e.match(H$);if(!n)return null;let r=Kd(e,n.index),o=Kd(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("-")){V$.has(c)&&i++;continue}s=c.replace(/^["']+|["']+$/g,"")||null;break}return{repo:r.match(Nb)?.[1]??null,selector:s,auto:/\s--auto\b/.test(r)}}async function J$(t,e,{exclude:n=()=>!1}={}){let r=async i=>{Ye("observer");let{stdout:c}=await Cb("gh",["pr","list","--repo",t,"--author","@me","--state","all","--limit","10","--json",z$],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...i}}).catch(l=>{throw Bn(l)&&Dn(l),l});return JSON.parse(c||"[]")},o=i=>(i||[]).filter(c=>Date.parse(c.createdAt)>=e-j$&&!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 Y$(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 X$(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)||G$(c.headRefName,t.id),i=[];for(let c of await Y$(t,e?.repo??null)){let l;try{l=await J$(c,n,{exclude:a})}catch{continue}for(let u of l){let d=await Gt(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 jb(t,e,{delays:n=Mb,turnEnd:r}={}){let o=Pb(e.command);if(!o)return null;let s=!!Bb(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 X$(t,o,i).catch(()=>null);if(u?.settled)return null;if(!u)continue;let{slug:d,pr:f}=u,{link:h,created:p}=await oe({repo:d,number:f.number,trackId:t.id,url:f.url,headRef:f.headRefName,title:f.title,source:"observed"});return!p&&!(h?.trackId===t.id&&await Ws(d,f.number))?null:(await qd(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{Un.delete(a)}})();return c.catch(()=>Un.delete(a)),c}function Lb(t,e,{delays:n=Mb,turnEnd:r,openedWait:o}={}){let s=Bb(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 d=[];if(c)d=[c];else{let p=Db(t);if(p.length>1&&/^\d+$/.test(String(s.selector??"")))return null;for(let w of p){let y=await lt(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(p,w)=>{let y=await Gt(c,p.number);return y&&y.trackId!==t.id?null:(y||await oe({repo:c,number:p.number,trackId:t.id,url:p.url,headRef:p.headRefName,title:p.title,source:"merge-observed"}),await qs(c,p.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===p.number)||(await qd(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:p.number,url:p.url,title:p.title,branch:p.headRefName,repo:c}}))),p)},h=null;for(let p of n){await new Promise(C=>setTimeout(C,p));let w=[];for(let C of d)try{Ye("observer");let{stdout:N}=await Cb("gh",["pr","view",String(l),"--repo",C,"--json",Z$],{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){Bn(N)&&Dn(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(h=k,s.auto)return f(k,!0);continue}let x=await Gt(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 qd(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 $=C=>C.some(N=>N.type==="pr.state.changed"&&N.payload?.change==="opened"&&N.payload?.number===k.number),G=0;if(!$(E)){if(Pb(e.command)&&await Ws(c,k.number)){let C=Date.now();G=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 Gt(c,k.number))?.announced){let C=o?.capMs??L$,N=o?.pollMs??F$,T=Date.now()+C;for(;Date.now()<T&&(await new Promise(B=>setTimeout(B,N)),!$(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(),G),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 h?f(h,!1):null}finally{Un.delete(a)}})();return i.catch(()=>Un.delete(a)),i}var Cb,Mb,B$,D$,j$,L$,F$,U$,H$,W$,Nb,q$,K$,V$,z$,Un,Z$,Fb=M(()=>{ot();ar();Wt();Hs();Fn();Rr();dc();Cb=P$(N$),Mb=[4e3,15e3,45e3],B$=2500,D$=5*6e4;j$=15e3,L$=9e4,F$=2e3,U$=/(?:^|[;&|]\s*|\)\s*)gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+create\b/,H$=/(?:^|[;&|]\s*|\)\s*)gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+merge\b/,W$=/\s--web\b/,Nb=/(?:--repo|-R)[\s=]+([\w.-]+\/[\w.-]+)/,q$=/(?:--head|-H)[\s=]+([^\s"'`;&|]+)/,K$=/^track\/.+-([0-9a-f]{8})$/;V$=new Set(["--subject","-t","--body","-b","--body-file","-F","--match-head-commit","--author-email","-A","--repo","-R"]);z$="number,url,title,headRefName,createdAt";Un=new Set;Z$="number,url,title,headRefName,state"});import Q$ from"node:fs/promises";import Vd from"node:path";import tO from"node:os";function Gd(t,e){let n=new RegExp(`\\b${e}="([^"]*)"`).exec(t);return n?n[1]:null}function fc(t){let e=eO.exec(String(t||""));if(!e)return null;let[,n,r]=e,o=Gd(n,"from"),s=o?o.replace(/^uds:/,""):null,a=Ub(s);return{socket:s,pid:a,name:Gd(n,"from-name"),mode:Gd(n,"from-mode"),text:r.trim()}}function Ub(t){let e=/(\d+)\.sock$/.exec(String(t||""));return e?Number(e[1]):null}function nO(){return process.env.CLAUDE_CONFIG_DIR?Vd.join(process.env.CLAUDE_CONFIG_DIR,"sessions"):Vd.join(tO.homedir(),".claude","sessions")}async function rO(t){let e=Ub(t);if(!e)return null;try{let n=await Q$.readFile(Vd.join(nO(),`${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 Hb(t,e){let n=await rO(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 eO,zd=M(()=>{eO=/<cross-session-message\b([^>]*)>([\s\S]*?)<\/cross-session-message>/});import{randomUUID as oO}from"node:crypto";function zs(t){return t.sourceId?`${t.role}|id:${t.sourceId}`:`${t.role}|${t.ts??"?"}|${String(t.text||"").slice(0,40)}`}function Wb(t){return t.id?`cmd|${t.box}|id:${t.id}`:`cmd|${t.box}|${t.ts??"?"}|${String(t.command||"").slice(0,40)}`}function qb(t){return`job|${t.box}|id:${t.id}`}async function Yd(t){return Jd.has(t.id)?Jd.get(t.id):(pc.has(t.id)||pc.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(zs({role:o,sourceId:r.payload.sourceId})),n.keys.add(zs({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(zs({role:"user",sourceId:r.payload.sourceId})),n.keys.add(zs({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(Wb({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(qb({id:r.payload.id,box:r.boxId}));return Jd.set(t.id,n),n}).finally(()=>pc.delete(t.id))),pc.get(t.id))}async function Kb(t,e){try{let n=(await Yd(t)).keys;for(let r of e||[]){if(!r||r.ts==null||!String(r.text||"").trim()&&!r.images?.length)continue;let o=zs(r);if(n.has(o))continue;n.add(o);let s=r.role==="user"?fc(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 Hb(s,Js),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=sb(r.text);if(a){let{offered:i,toPr:c}=ab(a),l;if(t.workspace?.kind==="multi"){let u=await Io(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:oO(),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 Gb(t,e){try{let n=await Yd(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=Wb(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}}),jb(t,o),Lb(t,o))}}catch{}}async function Vb(t,e){try{let n=await Yd(t),r=[...e||[]].filter(o=>o&&o.id).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=qb(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 Jd,pc,zb=M(()=>{ot();Eo();Fb();zd();Rr();Jd=new Map,pc=new Map});function sO(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 aO(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?.codexTs!=null&&o.add(s.payload.codexTs);Xd.set(n,o)}return Xd.get(n)}async function Jb(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 aO(t,e),o=sO(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 Xd,Yb=M(()=>{ot();uo();ye();Ds();Xd=new Map});import mc from"node:fs";import Qd from"node:path";import iO from"node:os";async function uO({sinceMs:t,cookie:e,fetchImpl:n=fetch}){let r=[];for(let o=1;o<=20;o++){let s=await n(lO,{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:Xb})});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<Xb)break}return r}function dO(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 Qb(){try{return JSON.parse(mc.readFileSync(hc(),"utf8"))}catch{return{sinceMs:0,seen:[]}}}function pO(t){try{mc.mkdirSync(Qd.dirname(hc()),{recursive:!0});let e=hc()+".tmp";mc.writeFileSync(e,JSON.stringify(t)),mc.renameSync(e,hc())}catch{}}async function hO({fetchImpl:t,now:e=Date.now()}={}){if(Hn.rows&&e-Hn.at<fO)return Hn.rows;let n=process.env.BOSTRAT_CURSOR_USAGE_COOKIE;if(!n)return null;let r=Qb(),o=Math.max(r.sinceMs-6e4,e-24*36e5);try{let s=await uO({sinceMs:o,cookie:n,fetchImpl:t});Hn={at:e,rows:s.map(dO).filter(Boolean),error:null}}catch(s){Hn={at:e,rows:null,error:String(s?.message||s)}}return Hn.rows}async function wO(t,e){let n=`${t.id}:${e.name}`;if(!Zd.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);Zd.set(n,o)}return Zd.get(n)}async function tk(t,e,{fetchImpl:n}={}){try{if(e?.agent!=="cursor"||!e.cwd||!Zb())return;let r=await hO({fetchImpl:n});if(!r||!r.length)return;let o=await Zg(e.cwd,e.pinned?e.sessionId:null);if(!o?.chatId)return;let s=await wO(t,e),a=Qb(),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=Cn(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}})}pO({sinceMs:c,seen:[...i].slice(-mO)})}catch{}}var cO,Zb,lO,Xb,fO,Hn,hc,mO,tf,Zd,ef=M(()=>{ot();rd();Ds();cO=process.env.BOSTRAT_STATE_DIR||Qd.join(process.env.HOME||iO.tmpdir(),".bostrat"),Zb=(t=process.env)=>!!t.BOSTRAT_CURSOR_USAGE_COOKIE,lO="https://cursor.com/api/dashboard/get-filtered-usage-events",Xb=100;fO=5*6e4,Hn={at:0,rows:null,error:null},hc=()=>Qd.join(cO,"cursor-usage.json");mO=5e3;tf=()=>({enabled:Zb(),lastPollAt:Hn.at||null,error:Hn.error}),Zd=new Map});import Zs from"node:fs/promises";import te from"node:path";import gO from"node:os";import yO from"node:net";import{randomUUID as bO}from"node:crypto";import{execFile as kO}from"node:child_process";import{promisify as xO}from"node:util";function IO(t){for(let e of lf(t))if(!ak.test(e))return e;return null}function ik(t){let e=lf(t),n=e.indexOf("--");return n===-1?e:e.slice(0,n)}function RO(t,e){let n=ik(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 OO(t){let e=!1,n=!1;for(let r of lf(t)){if(!e){if(ak.test(r))continue;e=!0;continue}if(r.startsWith("-")){let o=r.indexOf("="),s=o===-1?null:r.slice(o+1);if(s&&nf(s))return`serves the filesystem root ("${s}")`;n=o===-1;continue}if(n){if(n=!1,nf(r))return`serves the filesystem root ("${r}")`;continue}if(nf(r))return`serves the filesystem root ("${r}")`;if($O(r))return`serves a path that escapes the workspace ("${r}")`}return null}async function MO(t,e){if(te.resolve(t)===te.resolve(e))return!0;let[n,r]=await Promise.all([wc(t),wc(e)]);return n===r}async function NO(t){let n=(await Zs.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 ck(te.join(t,o.name,sf))?`./${o.name}`:null))).filter(Boolean)}async function PO(t,e){let[n,r]=await Promise.all([wc(t),wc(e)]),o=te.relative(n,r);if(o&&(o.startsWith("..")||te.isAbsolute(o)))throw Ys(`serve directory escapes the Track workspace: ${e}`)}async function BO(t,e){let n=OO(e);if(n)throw Ys(`refusing this view: the command ${n} \u2014 serve a build dir, not the filesystem root`);if(!await CO(t))throw Ys(`serve directory does not exist: ${t}`);let r=IO(e);if(!r)return;if(!r.includes("/")&&!await Fh(r,{loginShell:!0,failOpen:!0}))throw Ys(`\`${r}\` is not on the box's PATH \u2014 install it in the box first`);if(AO.test(e)||EO.has(r)||!TO.has(r)||!ik(e).includes("run")||_O.test(e))return;let o=RO(t,e);if(await ck(te.join(o,sf)))return;let s=await NO(o),a=s.length?` \u2014 found one in ${s.join(", ")}; run bostrat-view from there`:"";throw Ys(`no ${sf} in ${o}${a}`)}async function en(){return Oe||(rf||=(async()=>{try{Oe=JSON.parse(await Zs.readFile(sk,"utf8"))}catch{Oe={views:[],adoptWatermarks:{}}}finally{rf=null}return Oe.views||=[],Oe.adoptWatermarks||={},Oe})(),rf)}async function Me(){await Yt(sk,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 df(t){return Xs.get(t)||null}function uk(t,{name:e,box:n}={}){let r=Xs.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 Xs.set(t,o),o}function af(t,e){let n=Xs.get(t);n&&!n.finishedAt&&!n.viewId&&(n.viewId=e,n.step="booting")}function gc(t,{error:e=null}={}){let n=Xs.get(t);return!n||n.finishedAt?null:(n.finishedAt=Date.now(),e&&(n.error=e),n)}function dk(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 cf(t){return String(t||"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40).replace(/-+$/g,"")||"view"}function DO(t,e){let n=cf(e),r=new Set(t.views.map(o=>o.slug));if(!r.has(n)&&!rk.has(n))return n;for(let o=2;;o++){let s=`${n}-${o}`;if(!r.has(s)&&!rk.has(s))return s}}function Qs(t,{timeoutMs:e=1200}={}){return new Promise(n=>{let r=yO.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 ff(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 fk(t=process.env){return new Set([Number(t.PORT)||3362,Number(t.BOSTRAT_TLS_PORT)||3443])}async function jO(t,e){let n=new Set(t.views.map(o=>o.port)),r=fk();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=ek;o<=nk;o++)if(!(n.has(o)||r.has(o))&&!await Qs(o,{timeoutMs:250}))return o;throw new Error(`no free view port in ${ek}-${nk}`)}async function LO(t){try{let{stdout:e}=await Ce(L,U("list-sessions","-F","#{session_name}"));return e.split(`
136
- `).some(n=>n.trim()===Ro(t))}catch{return!1}}async function ta(t){try{await Ce(L,U("kill-session","-t",Ro(t)))}catch{}}async function pf(t){if(!await xs())throw new Error("host tmux server not running and auto-start failed \u2014 cannot spawn a view server");let e=Ro(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 ok(t,e=12){try{let{stdout:n}=await Ce(L,U("capture-pane","-t",Ro(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 LI(t,e,n){let r=hg(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 br(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 m=String(g.payload?.command||"");if(/\bbostrat-mock\s+(?:add|update)\b/.test(m))for(let S of m.matchAll(/[\w./~-]+\.(?:png|jpe?g|gif|webp|bmp|svg)\b/gi)){let $=S[0].split("/").pop().toLowerCase();d.has($)||d.set($,[]),d.get($).push(g.payload?.ts??g.ts)}}let f=3*6e4,p=20*6e4,h=(g,m)=>!!(g?.name&&d.get(String(g.name).toLowerCase()))?.some($=>$>=m-f&&$<=m+p);for(let g of t||[])if(g.type==="turn.retracted"){r.add(`${g.boxId}|${g.payload?.saidTs}`);let m=$t(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=$t(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,S={status:m.status||null,summary:m.summary||null,resultHead:m.resultHead??null,ts:rt(g)};m.toolUseId&&i.set(m.toolUseId,S);let $=String(m.summary||"").match(u);$&&l.set($[1],S)}let w=new Map,y=new Map,k=null,x=new Map,A=new Map,R=new Map,V=new Map,M=new Map,N=new Map,T=new Map,D=new Map,F=new Map,ct=new Map,Q=new Map,_=new Map,U=new Map,j=()=>{for(let g of U.values())g.questions.length&&e.push(g);U.clear()},at=null,Et=6e4,Lt=new Map,it=(g,m)=>{let S=o.get(g);if(!S?.length)return!1;let $=$t(m),lt=s.get(g);return S.some(ht=>{if(!$.startsWith(ht))return!1;let vt=$t($.slice(ht.length));return!!vt&&!!lt?.has(vt)})};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 S=m.note||qi(m.text);if(S){if(S.kind==="task"){if(S.toolUseId&&a.has(S.toolUseId))break;let $=String(S.summary||"").match(u);if(!S.toolUseId&&$&&c.has($[1]))break}if(S.kind==="command"&&cg(S.command))break;if(S.kind==="resume-summary"){e.push({id:g.id,kind:"resume-summary",title:S.title||"Context resumed from summary",bullets:S.bullets||[],sections:S.sections||[],rawChars:S.rawChars??null,ts:rt(g),box:g.boxId,agent:g.provider});break}S.kind!=="suppress"&&e.push({id:g.id,kind:"event",type:ug(S),name:S.name??null,command:S.command??null,summary:S.summary??null,status:S.status??null,ts:rt(g),box:g.boxId,agent:g.provider});break}}if(r.has(`${g.boxId}|${rt(g)}`)||g.source==="transcript"&&it(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:rt(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"&&(at=null);break}for(let S of x.values())S.status="stale";x.clear();for(let S of R.values())S.status="stale";R.clear(),at&&at.box===g.boxId&&(e.push(DI(at)),at=null),e.push({id:g.id,kind:"message",role:"user",text:m.text,ts:rt(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 S=m.from||{};e.push({id:g.id,kind:"event",type:"peer-message",text:m.text,from:S.trackName||S.boxId||S.name||null,fromTrackId:S.trackId||null,ts:rt(g),box:g.boxId,agent:g.provider});break}case"turn.agent":{if(m.model==="<synthetic>"&&/^No response requested\.$/.test(String(m.text||"").trim()))break;let S=Aw(m,{codexFailedText:hr});if(S){e.push({id:g.id,kind:"event",type:"provider-error",cls:S.cls,status:S.status??void 0,text:S.text,provider:g.provider,legacy:!0,at:rt(g),ts:rt(g),box:g.boxId,agent:g.provider});break}j();let $=(m.images||[]).filter(Ct=>!h(Ct,rt(g)));if(!String(m.text||"").trim()&&!$.length)break;if(g.provider==="cursor"){let Ct=`${g.boxId}|${m.text}`;if(n.has(Ct))break;n.add(Ct)}(!at||at.box===g.boxId)&&(at=null);let lt=g.provider==="codex"?(m.tools||[]).filter(Ct=>!Eu.has(Ct)&&!Ps.has(Ct)):m.tools||[],ht=m.text,vt=null;if(zu.has(g.provider)){let Ct=Ju(String(m.text||""));Ct&&(ht=Ct.text,vt={questions:Ct.questions})}e.push({id:g.id,kind:"message",role:"assistant",text:ht,ts:rt(g),box:g.boxId,agent:g.provider,boxRole:m.boxRole,...vt?{ask:vt}:{},...lt.length?{tools:lt}:{},...m.model?{model:m.model}:{},...m.sourceId?{sourceId:m.sourceId}:{},...$.length?{images:$}:{}}),vt&&(at={id:g.id,groupId:Yu(g.provider,m.sourceId||g.id,vt.questions),provider:g.provider,box:g.boxId,questions:vt.questions,ts:rt(g)});break}case"job.started":{if(!m.id)break;let S=rt(g),$=i.get(m.id);if(!$&&(m.kind||"agent")==="agent"&&m.name){let b=l.get(m.name);b&&b.ts>=S&&($=b)}let lt={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:S,finishedTs:$?.ts??null,summary:$?.summary??null,resultHead:$?.resultHead??null},ht=Lt.get(g.boxId),vt=ht?.jobs[ht.jobs.length-1]?.startedTs;if(ht&&vt!=null&&S-vt<=Et)ht.jobs.push(lt);else{let b={id:g.id,kind:"job-dock",dockId:m.id,ts:S,box:g.boxId,agent:g.provider,jobs:[lt]};Lt.set(g.boxId,b),e.push(b)}break}case"handoff.done":e.push(de(g,"lead-handoff"));break;case"subtask.delegated":e.push({...de(g,"subtask-delegated"),to:g.boxId,toAgent:g.provider});break;case"subtask.merged":e.push(de(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 R.values())$.status="stale";R.clear()}let S=de(g,`pr-${m.change}`);if(S.box=g.boxId??null,jI.has(m.change)&&m.number!=null){let $=LI(w,y,m);if(w.size>=2){for(let ht of y.values())for(let vt of ht)vt.grouped=!0;S.groupPrs=[...w.values()];let lt=[S];for(let ht of w.keys())y.set(ht,lt)}else{let lt=y.get($)??[];lt.push(S),y.set($,lt)}}else if(m.change==="merged"||m.change==="closed"||m.change==="lost"){let $=hg(m),lt=k&&!k.complete||w.size>=2;if(w.has($))w.delete($),y.delete($);else if(m.number!=null)for(let ht of[...w.keys()])ht.endsWith(`#${m.number}`)&&(w.delete(ht),y.delete(ht));if(lt&&m.number!=null){(!k||k.complete)&&(k={id:g.id,kind:"event",type:"pr-group-settled",prs:[],remaining:[],complete:!1,at:rt(g),ts:rt(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:rt(g)}),k.remaining=[...w.values()],k.complete=w.size===0;break}}e.push(S);break}case"pr.offered":{if(!m.offerId)break;for(let $ of x.values())$.status="stale";x.clear();for(let $ of R.values())$.status="stale";R.clear();let S={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:rt(g),box:g.boxId,agent:g.provider};x.set(m.offerId,S),A.set(m.offerId,S),e.push(S);break}case"pr.offer.answered":{let S=A.get(m.offerId);S&&(S.status=m.action||"dismiss",S.actions=Array.isArray(m.actions)?m.actions:null,S.notify=m.notify===!0,m.existingPr&&typeof m.existingPr=="object"&&(S.existingPr={number:m.existingPr.number??null}),x.delete(m.offerId));break}case"pr.exists.offered":{if(!m.offerId)break;for(let $ of R.values())$.status="stale";R.clear();let S={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:rt(g),box:g.boxId,agent:g.provider};R.set(m.offerId,S),V.set(m.offerId,S),e.push(S);break}case"pr.exists.answered":{let S=V.get(m.offerId);S&&(S.status=m.choice||"dismiss",R.delete(m.offerId));break}case"box.state.changed":{let S=m.change==="model"?"model-change":m.change;if(!S)break;let $=de(g,S);S==="model-change"&&($.to=m.model),e.push($);break}case"track.transferred":case"track.recovered":e.push(de(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:rt(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:rt(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:rt(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:rt(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:rt(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:rt(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:rt(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 S={id:g.id,kind:"fullscreen-offer",offerId:m.offerId,status:"open",ts:rt(g),box:m.box||g.boxId,agent:m.agent||g.provider};T.set(m.offerId,S),D.set(m.offerId,S),e.push(S);break}case"box.fullscreen.answered":{let S=D.get(m.offerId);S&&(S.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 M.values())$.key===m.key&&($.status="stale",M.delete($.offerId));let S={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:rt(g),box:g.boxId,agent:g.provider};M.set(m.offerId,S),N.set(m.offerId,S),e.push(S);break}case"ticket.move.answered":{let S=N.get(m.offerId);S&&(S.status=m.action==="moved"?"moved":"dismiss",M.delete(m.offerId));break}case"ticket.state.changed":{for(let S of M.values())S.key===m.key&&S.to===m.to&&(S.status="stale",M.delete(S.offerId));if(m.mode==="offer")break;e.push(de(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:rt(g),box:g.boxId,agent:g.provider});break}case"ticket.flow.changed":e.push(de(g,"ticket-flow"));break;case"ticket.create.offered":{if(!m.proposalId)break;for(let $ of F.values())$.status="stale";F.clear();let S={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:rt(g),box:g.boxId,agent:g.provider};F.set(m.proposalId,S),ct.set(m.proposalId,S),e.push(S);break}case"ticket.create.answered":{let S=ct.get(m.proposalId);S&&(S.status=m.action==="created"?"created":"dismiss",S.createdCount=m.createdCount??null,S.failedCount=m.failedCount??null,F.delete(m.proposalId));break}case"loop.create.offered":{if(!m.proposalId)break;for(let $ of Q.values())$.status="stale";Q.clear();let S={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:rt(g),box:g.boxId,agent:g.provider};Q.set(m.proposalId,S),_.set(m.proposalId,S),e.push(S);break}case"loop.create.answered":{let S=_.get(m.proposalId);S&&(S.status=m.action==="created"?"created":"dismiss",Q.delete(m.proposalId));break}case"loop.created":{let S=m.proposalId?_.get(m.proposalId):null;S&&(S.created={loopId:m.loopId??null,nextFireAt:Number.isFinite(Number(m.nextFireAt))?Number(m.nextFireAt):null});break}case"ticket.created":{let S={items:Array.isArray(m.items)?m.items:[],failed:Array.isArray(m.failed)?m.failed:[],team:m.team??null},$=m.proposalId?ct.get(m.proposalId):null;if($){$.created=S;break}e.push({id:g.id,kind:"ticket-created",...S,ts:rt(g),box:g.boxId,agent:g.provider});break}case"error":{if(!m.kind)break;e.push(de(g,m.kind));break}case"provider.error":e.push({...de(g,"provider-error"),provider:g.provider,box:g.boxId,agent:g.provider});break;case"usage.cap.hit":e.push(de(g,"usage-cap-hit"));break;case"usage.cap.warning":e.push(de(g,"usage-cap-warning"));break;case"provider.connected":{e.push({id:g.id,kind:"event",type:"provider-connected",provider:m.provider||g.provider,ts:rt(g),at:rt(g),box:g.boxId,agent:g.provider});break}case"prompt.answered":{if(at=null,m.control||!m.question)break;let S=m.groupId||m.promptId;if(!S)break;let $=U.get(S);$||($={id:g.id,kind:"prompt",groupId:S,provider:g.provider,box:g.boxId,agent:g.provider,questionTotal:m.questionTotal??1,questions:[],ts:rt(g)},U.set(S,$));let lt=m.questionIndex??0,ht={index:lt,header:m.header||"",question:m.question,multiSelect:!!m.multiSelect,chosen:Array.isArray(m.chosen)?m.chosen:[]},vt=$.questions.findIndex(b=>b.index===lt&&$t(b.question)===$t(ht.question));vt>=0?$.questions[vt]=ht:$.questions.push(ht),$.questions.sort((b,E)=>b.index-E.index),$.questionTotal=Math.max($.questionTotal,m.questionTotal??1),$.questions.length>=$.questionTotal&&(e.push($),U.delete(S));break}default:break}}return UI(e.sort((g,m)=>(g.ts??0)-(m.ts??0)))}function UI(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<=FI){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 Qu(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:HI(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??br(t)).filter(o=>o.kind==="message");return gw(n,r)}function HI(t){let e=String(t.summary||"").trim();return e&&e!==t.command&&e!==fo(t.command)?e:Rn(t.command,t.description||"")}function de(t,e){let{ts:n,change:r,...o}=t.payload||{};return{id:t.id,kind:"event",type:e,...o,at:rt(t),ts:rt(t)}}function wg(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)+WI,s=n;for(;s+1<e.length;){let a=e[s+1];if((a?.ts??0)>o||a?.kind==="event"&&qI.has(a.type))break;s++}s>n&&e.splice(s,0,...e.splice(n,1)),n=s}return e}function gg(t){let e=[...t];for(let n=0;n<e.length;n++){let r=e[n];if(r?.kind!=="event"||!GI.has(r.type)||!r.box)continue;let o=(r.ts??0)+KI,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 rt,jI,hg,FI,WI,qI,KI,GI,td=C(()=>{po();wr();Ci();Hu();Vu();Zu();rt=t=>t.payload?.ts??t.ts;jI=new Set(["opened","ci-fixed","reconciled","pushed"]),hg=t=>`${t.repo??""}#${t.number}`;FI=2*6e4;WI=12e4,qI=new Set(["archived","unarchived","opened"]);KI=2500,GI=new Set(["pr-opened","pr-merged","pr-auto-armed"])});function XI(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 QI(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 tR(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<JI&&(o.add(c.path),n.push(c.path)),c.head&&!s.has(c.head)&&r.length<YI&&(s.add(c.head),r.push(c.head))}return{files:n,heads:r}}function xg(t,{trackName:e="this Track",now:n=null,mode:r="failover"}={}){let o=XI(t),s=QI(t),a=s?.payload?.content??null,i=s?s.payload?.ts??s.ts??null:null,c=br(t??[]).filter(f=>f?.kind==="message"&&typeof f.text=="string"&&f.text.trim()).slice(-VI);if(!a&&!c.length)return null;let l=[];if(l.push(`# Reconstructed resume brief \u2014 ${e}`),l.push(""),l.push(kg[r]??kg.failover),l.push(""),o.lastPush?.sha){let f=bg(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=bg(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=tR(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"}:** ${ZI(f.text,zI)}`),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<=yg?d:`${d.slice(0,yg)}
108
+
109
+ [\u2026 brief truncated]`}var VI,zI,yg,JI,YI,ZI,bg,kg,vg=C(()=>{td();VI=12,zI=2e3,yg=48e3,JI=30,YI=10;ZI=(t,e)=>{let n=String(t??"").trim();return n.length<=e?n:`${n.slice(0,e-1)}\u2026`},bg=(t,e)=>t&&e?Math.max(1,Math.round((t-e)/6e4)):null;kg={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 eR from"node:fs";import Cn from"node:fs/promises";import Mn from"node:path";function Rg(t){let e=dr(String(t??"")),n=Buffer.byteLength(e,"utf8");return n<=Sg?{content:e,bytes:n,truncated:!1}:{content:`${Buffer.from(e,"utf8").subarray(0,Sg).toString("utf8").replace(/�+$/,"")}
110
+
111
+ [\u2026 truncated by bostrat at 32 KiB \u2014 full artifact in the workspace]`,bytes:n,truncated:!0}}function uR(t){let e=String(t||"").split(/\r?\n/).map(s=>s.trim()).filter(Boolean),n=[],r=[];for(let s of e)if(Ag.test(s)){if(r.length>=Pg)continue;let a=lR(s.replace(Ag,"").replace(/[.;,:]+$/,""),Bg,iR);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>Tg&&(o=`${o.slice(0,Tg-1).trimEnd()}\u2026`),{text:o,items:r.length>1?r:[]}}async function Dg(t,e,{timeoutMs:n=9e4}={}){let r=Mn.join(e,sR),o=Mn.join(r,aR);await Cn.mkdir(r,{recursive:!0});let s=await Ki(o),a=await nt(t);if(!a)throw new Error(`session "${t}" not found`);return await Gi(t,a,cR(o)),await qg(o,s,n),uR(await Cn.readFile(o,"utf8"))}function jg(t,e){let n=(e||"").trim();if(!n)return!1;if(t==="assistant")return n===Og||n===Ng;let r=n.replace(/^\/[a-z0-9:_-]+\s+/i,"");return r.startsWith($g)||n===nR||r.startsWith(Cg)||r.startsWith(Mg)}function Lg(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-dR;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 Fg(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 Ug(t,{windows:e=[]}={}){if(jg(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 Vi(t){return ed.get(t)||null}async function Hg(t){let e=ed.get(t);if(e&&!e.finishedAt)throw new Error("a handoff is already running for this session");let n=await nt(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:Mn.join(n.cwd,_g,Ig)};return ed.set(t,r),mR(r,n.cwd).catch(o=>{r.error=o?.message||String(o),r.finishedAt=Date.now()}),r}async function mR(t,e){t.step="summarize",await Wg(t.name,e),t.step="clear";let n=await nt(t.name);await Gi(t.name,n,"/clear"),await od(fR),t.step="resume",await Gi(t.name,n,oR),t.step="done",t.finishedAt=Date.now()}async function Wg(t,e,{timeoutMs:n=pR}={}){let r=Mn.join(e,_g),o=Mn.join(r,Ig);await Cn.mkdir(r,{recursive:!0});let s=await Ki(o),a=await nt(t);await z({flow:"checkpoint",phase:"summarize-start",sessionName:t,cwd:e,file:o,beforeMtime:s}),await Gi(t,a,rR(o)),await qg(o,s,n),await z({flow:"checkpoint",phase:"summarize-done",sessionName:t,file:o,afterMtime:await Ki(o)});let i=await Yw(e,o,{exclude:u=>jg(u.role,u.text)});await z({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 Cn.readFile(o,"utf8");await I({id:c,cwd:e},{type:"handoff.artifact",actor:"orchestrator",payload:{...Rg(u),ts:Date.now()}})}catch{}}await Nh(e);let l=await hR(r,o);return c&&await Kh(c,l||o,{box:t,agent:a?.agent??null}),o}async function nd(t,{timeoutMs:e}={}){let n=await nt(t);if(!n)throw new Error(`session "${t}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${t}"`);return Wg(t,n.cwd,e?{timeoutMs:e}:void 0)}async function rd(t,e,{trackName:n="this Track"}={}){let r=await B({id:t,cwd:e}),o=xg(r,{trackName:n,now:Date.now(),mode:"in-place"});if(!o)return null;let s=Mn.join(e,Eg);return await Cn.mkdir(Mn.dirname(s),{recursive:!0}),await Cn.writeFile(s,o,"utf8"),await I({id:t,cwd:e},{type:"handoff.artifact",actor:"orchestrator",payload:{...Rg(o),reconstructed:!0,ts:Date.now()}}).catch(()=>{}),Eg}async function Ki(t){try{return(await Cn.stat(t)).mtimeMs}catch{return 0}}async function qg(t,e,n){let r=Date.now()+n;for(;;){if(await Ki(t)>e)return;if(Date.now()>r)throw new Error(`timed out waiting for the handoff file to be written (${t})`);await od(2e3)}}async function hR(t,e){try{if(!eR.existsSync(e))return null;let n=new Date().toISOString().replace(/[:.]/g,"-"),r=Mn.join(t,`${n}.md`);return await Cn.copyFile(e,r),r}catch{return null}}function od(t){return new Promise(e=>setTimeout(e,t))}async function Gi(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 On({cwd:e.cwd,sessionId:e.sessionId,sessionName:t,agent:e.agent,agentCmd:o})}let r=await nt(t);if(!r)throw new Error(`session "${t}" disappeared before the orchestration prompt could be sent`);await _t(t,["Escape"],{kind:"drive-wipe"}),await od(150),await io(t,Ri,{kind:"drive-wipe"}),await Pt(t,n,{kind:"orchestration-drive",...Oe(r.agent)})}var _g,Ig,Sg,$g,Og,Cg,nR,rR,oR,Mg,Ng,sR,aR,Tg,Pg,Bg,iR,cR,Ag,lR,dR,fR,pR,ed,Eg,sd=C(()=>{Gt();ji();Ge();Us();Xw();wi();st();xi();vg();_g=".bostrat/handoff",Ig="latest.md",Sg=32*1024;$g="Checkpoint: write a work-in-progress handoff",Og="HANDOFF WRITTEN",Cg="Resume from .bostrat/handoff/latest.md",nR="/clear",rR=t=>`${$g} 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 ${Og} and take no further action.`,oR=`${Cg}: read it, restate the Objective and the single next step in one line, then continue the work from 'Next steps'.`,Mg="Beat: write a",Ng="BEAT WRITTEN",sR=".bostrat/arc",aR="beat.txt",Tg=200,Pg=4,Bg=5,iR=36,cR=t=>`${Mg} 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 ${Pg} further lines, each starting with "- " and naming ONE piece in at most ${Bg} 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 ${Ng} and take no further action.`,Ag=/^(?:[-–—*•·]|\d+[.)])\s+/,lR=(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};dR=6e5;fR=3500,pR=3e5,ed=new Map;Eg=".bostrat/handoff/status-latest.md"});function Gg(t,e,n){if(t==null)return e==="from"?-1/0:1/0;if(!wR.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 gR(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:Gg(o.from,"from",n),toMs:Gg(o.to,"to",n)}))}return e}function bR(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 kR(t){if(!t)return null;let e=String(t).trim();return ad[e]?e:Kg[e]?Kg[e]:Object.keys(ad).find(r=>e.startsWith(r))||null}function Vg(t,e){let n=kR(t);if(!n)return null;let r=bR(e);return r===null?null:yR[n].find(o=>r>=o.fromMs&&r<=o.toMs)||null}function Nn(t,e={},n){let r=Vg(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 ad,Kg,wR,yR,zg,Vs=C(()=>{ad={"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)."}]},Kg={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"},wR=/^\d{4}-\d{2}-\d{2}$/;yR=gR(ad);zg=(t,e)=>Vg(t,e)!==null});function xR(t){return t?{input:t.input||0,output:t.output||0,cacheRead:t.cacheRead||0,cacheWrite:t.cacheWrite??t.cacheCreation??0}:null}function Yg(t,e){e&&(t.input+=e.input,t.output+=e.output,t.cacheRead+=e.cacheRead,t.cacheCreation+=e.cacheWrite)}function Je(t){let e=t.payload?.model||"unknown",n=xR(t.payload?.tokens),r=Number(t.payload?.usd)||0,o=t.source==="vendor",s=r,a=!1;if(n&&!o){let l=Nn(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&&!zg(e,t.ts);return{usd:s,model:e,tokens:n,repriced:a,unpriced:c,asRecorded:r}}function Pn(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=Jg();for(let f of n){let{usd:p,model:h,tokens:w,repriced:y,unpriced:k,asRecorded:x}=Je(f);i+=x;let A=f.provider||"unknown",R=f.boxId||"unattributed";if(y&&c++,k&&(l++,u.add(h)),a+=p,Yg(d,w),r[h]||={usd:0,tokens:Jg(),events:0},r[h].usd+=p,r[h].events+=1,Yg(r[h].tokens,w),o[A]||={usd:0,events:0},o[A].usd+=p,o[A].events+=1,s[R]||={usd:0,events:0,provider:A,models:new Set,label:e[R]||R},s[R].usd+=p,s[R].events+=1,h!=="unknown"&&s[R].models.add(h),f.epoch!=null){let V=(s[R].epochs||={})[f.epoch]||={usd:0,events:0,provider:A,models:new Set};V.usd+=p,V.events+=1,V.provider=A,h!=="unknown"&&V.models.add(h)}}return{totalUsd:go(a),asRecordedUsd:go(i),totalTokens:d,turns:n.length,repricedTurns:c,unpricedTurns:l,unpricedModels:[...u],byModel:zi(r,f=>({...f,usd:go(f.usd)})),byProvider:zi(o,f=>({...f,usd:go(f.usd)})),byBox:zi(s,f=>({usd:go(f.usd),events:f.events,provider:f.provider,label:f.label,models:[...f.models],...f.epochs?{epochs:zi(f.epochs,p=>({usd:go(p.usd),events:p.events,provider:p.provider,models:[...p.models]}))}:{}}))}}var Jg,go,zi,kr=C(()=>{Vs();Jg=()=>({input:0,output:0,cacheRead:0,cacheCreation:0});go=t=>Math.round(t*1e4)/1e4,zi=(t,e)=>Object.fromEntries(Object.entries(t).map(([n,r])=>[n,e(r)]))});function vR(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 Xg(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(id(s,"PR")+" opened");let a=Object.keys(t?.subtasks||{}).length||r.filter(u=>u.type==="subtask-delegated").length;a&&n.push(id(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(`${id(i.length,"handoff")} ${u}${i.length>3?"\u2026":""}`)}let c=Pn(e);c.totalUsd>=.01&&n.push(`$${c.totalUsd.toFixed(2)}`);let l=Number.isFinite(t?.archivedAt)&&Number.isFinite(t?.createdAt)?vR(t.archivedAt-t.createdAt):null;return n.length&&l&&n.push(l),n.length?n.join(" \xB7 "):null}var id,Zg=C(()=>{kr();id=(t,e)=>`${t} ${e}${t===1?"":"s"}`});import{execFile as SR}from"node:child_process";import{promisify as TR}from"node:util";import{randomUUID as AR}from"node:crypto";async function cd(t,e){let n=Date.now()+e;for(;;){if(await ao(t))return!0;if(Date.now()>n)return!1;await Ji(_R)}}async function RR(t,e){let n=ty[e]||ty.default;n.escape&&(await _t(t,["Escape"],{kind:"swap-exit"}),await Ji(150)),n.wipe&&await io(t,Ri,{kind:"swap-exit"}),await $i(t,n.text,{perCharDelayMs:90,kind:"swap-exit"});let r=Oe(e).submitDelayMs||0;await Ji(Math.max(r,250)),await _t(t,["Enter"],{kind:"swap-exit"})}async function $R(t,e){try{let{stdout:n}=await yo(L,H("show-environment","-t",t,e));return!String(n||"").trimStart().startsWith("-")}catch{return!1}}async function ey(t){await yo(L,H("respawn-pane","-k","-t",t))}async function ld(t,e={}){if(!St(t))throw new Error("invalid session name");let n=String(e.agentCmd||"").trim();if(!n)throw new Error("agentCmd is required");let r=await nt(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||En(n),a=Number(e.exitTimeoutMs)||ER;await z({flow:"swap",phase:"start",sessionName:t,from:o,to:s,cwd:r.cwd});let i=!1;if(!await ao(t)&&(await RR(t,o),!await cd(t,a)&&(i=!0,await z({flow:"swap",phase:"respawn-forced",sessionName:t,from:o}),await ey(t),!await cd(t,Qg))))throw new Error(`pane shell did not come back after respawn-pane in "${t}"`);let c=s==="claude"&&fr(n),l=c?ai():null,u=await $R(t,"ANTHROPIC_API_KEY"),d=!1;try{l?(await yo(L,H("set-environment","-t",t,"ANTHROPIC_API_KEY",l)),d=!0):u&&(await yo(L,H("set-environment","-u","-t",t,"ANTHROPIC_API_KEY")),d=!0)}catch(y){throw l?Si(y,l):y}if(d&&!i&&(await ey(t),!await cd(t,Qg)))throw new Error(`pane shell did not come back after env respawn in "${t}"`);let f=!!e.resumeSessionId,p=e.resumeSessionId||AR(),h=f?n:fu(n,p,t),w=f?e.pinned===!0:/(^|\s)--session-id(\s|=)/.test(h);return c&&await kn(r.cwd),s==="codex"&&await Yr(r.cwd),s==="cursor"&&await Xr(r.cwd),await pr(t),await yo(L,H("set-option","-t",t,"@bostrat-sid",p)),await yo(L,H("set-option","-t",t,"@bostrat-agent",s)),await Ji(IR),await Pt(t,h,{kind:"swap-launch"}),await z({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 yo,Ji,ER,Qg,_R,IR,ty,ny=C(()=>{Gt();bs();ci();li();Us();Ge();yo=TR(SR),Ji=t=>new Promise(e=>setTimeout(e,t)),ER=Number(process.env.BOSTRAT_SWAP_EXIT_TIMEOUT_MS)||15e3,Qg=Number(process.env.BOSTRAT_SWAP_SHELL_TIMEOUT_MS)||8e3,_R=250,IR=400,ty={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 ry(t,{maxBytes:e=2097152,limit:n=100}={}){let r;try{r=await Zt(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?fo(p):null),detail:p?fo(p):null,ts:d,proven:!0})}}else f.type==="tool_result"&&f.tool_use_id&&OR.test(CR(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 OR,CR,oy=C(()=>{ke();po();OR=/^Async (?:agent|task) launched/i,CR=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 Bn(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 MR(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 sy(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:xe(`read ${Bn(r,n)}${o?` (lines ${o}\u2013${s??"end"})`:""}`,140),description:o?`Read lines ${o}\u2013${s??"end"} of ${bo(r)}`:`Read ${bo(r)}`}}case"Grep":{let r=e?.pattern;if(!r)return null;let o=e?.path?Bn(e.path,n):null,s=e?.glob?` --glob ${ud(e.glob)}`:"",a=xe(String(r),40);return{command:xe(`grep ${ud(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?Bn(e.target_directory,n):null;return{command:xe(`glob ${ud(r)}${o&&o!=="."?` ${o}`:""}`,140),description:`Find files matching \u201C${xe(String(r),40)}\u201D`}}case"StrReplace":return e?.path?{command:xe(`edit ${Bn(e.path,n)}`,140),description:`Edit ${bo(e.path)}`}:null;case"Write":return e?.path?{command:xe(`write ${Bn(e.path,n)}`,140),description:`Write ${bo(e.path)}`}:null;case"Delete":return e?.path?{command:xe(`delete ${Bn(e.path,n)}`,140),description:`Delete ${bo(e.path)}`}:null;case"ReadLints":{let o=(Array.isArray(e?.paths)?e.paths:[]).map(s=>Bn(s,n)).filter(Boolean);return{command:xe(o.length?`lints ${o.join(" ")}`:"lints",140),description:"Check lints"}}case"ApplyPatch":{let r=MR(e);if(!r.length)return null;let o=r.length>1?` (+${r.length-1} more)`:"";return{command:xe(`apply_patch ${Bn(r[0],n)}${o}`,140),description:r.length>1?`Patch ${r.length} files`:`Patch ${bo(r[0])}`}}case"Await":{let r=e?.shell_id??e?.task_id;return{command:xe(`await ${r??"background output"}`,140),description:"Wait for a background command"}}default:return null}}var Yi,xe,bo,ud,ay=C(()=>{Yi=new Set(["Shell","Read","Grep","Glob","StrReplace","Write","ReadLints","Delete","ApplyPatch","Await"]),xe=(t,e=88)=>t.length>e?`${t.slice(0,e).trimEnd()}\u2026`:t,bo=t=>String(t).replace(/\/+$/,"").split("/").pop()||String(t);ud=t=>`"${String(t).replace(/"/g,'\\"')}"`});import zs from"node:fs";import NR from"node:fs/promises";import xr from"node:path";import PR from"node:os";import BR from"node:crypto";import DR from"node:zlib";function ly(t){let e=BR.createHash("md5").update(String(t)).digest("hex");return xr.join(jR,e)}function uy(t){try{let e=JSON.parse(zs.readFileSync(xr.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 LR(t){let e=ly(t),n;try{n=zs.readdirSync(e,{withFileTypes:!0}).filter(o=>o.isDirectory())}catch{return null}let r=null;for(let o of n){let s=xr.join(e,o.name),a=xr.join(s,"store.db");if(!zs.existsSync(a))continue;let i=uy(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 Xi(t,e){if(!t)return null;if(e){let n=xr.join(ly(t),e),r=xr.join(n,"store.db");if(zs.existsSync(r))return{id:e,dir:n,store:r,...uy(n)||{createdAtMs:null,updatedAtMs:null}}}return LR(t)}function iy(t,e){let n=t.prepare("SELECT data FROM blobs WHERE id = ?").get(e);return n?Buffer.from(n.data):null}function FR(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 UR(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 HR(t,e){if(!Array.isArray(t))return[];let n=[];for(let r of t){if(!r||r.type!=="tool-call"||!Yi.has(r.toolName))continue;let o=sy(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 dd(t,e){if(!cy)return ko;let{DatabaseSync:n}=cy,r;try{r=new n(t,{readOnly:!0})}catch{return ko}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 ko;let s;try{s=JSON.parse(Buffer.from(String(o.value),"hex").toString("utf8"))}catch{return ko}let a=s.lastUsedModel||null,i=s.latestRootBlobId?iy(r,s.latestRootBlobId):null;if(!i)return{...ko,model:a};let c=[],l=[],u=[],d=null,f=[];for(let p of UR(i)){let h=FR(iy(r,p));if(!h)continue;let w=h.providerOptions?.cursor;if(w?.requestId&&f.push(w.requestId),w?.modelProviderMessageId&&f.push(w.modelProviderMessageId),h.role!=="assistant")continue;if(Array.isArray(h.content))for(let x of h.content){let A=x?.providerOptions?.cursor?.modelName;A&&(d=A)}l.push(...HR(h.content,e).map((x,A)=>({...x,id:x.id||`${p}:${A}`}))),u.push(...qR(h.content));let y=WR(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:d}),l=[]}return{turns:c,trailingCommands:l,model:a,requestIds:f}}catch{return ko}finally{try{r.close()}catch{}}}function dy(t,e){let n=t.updatedAtMs;if(!n)try{n=Math.round(zs.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 fy(t,e,{limit:n=80}={}){let r=Xi(t,e);if(!r)return[];let{turns:o,model:s}=await dd(r.store,t);if(!o.length)return[];let a=o.slice(-n),{tsAt:i}=dy(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 py(t,e){let n=Xi(t,e);if(!n)return null;let{turns:r,requestIds:o,model:s}=await dd(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 my(t,e,{limit:n=80}={}){let r=Xi(t,e);if(!r)return[];let{turns:o,trailingCommands:s}=await dd(r.store,t);if(!o.length&&!s.length)return[];let a=o.slice(-n),{end:i,tsAt:c}=dy(r,a.length||1),l=[];a.forEach((u,d)=>{for(let f of u.commands)l.push({...f,summary:Rn(f.command,f.description),ts:c(d)})});for(let u of s)l.push({...u,summary:Rn(u.command,u.description),ts:i+1});return l}async function hy(t,e){let n=Xi(t,e);if(!n)return null;if(n.updatedAtMs)return n.updatedAtMs;try{return Math.round((await NR.stat(n.store)).mtimeMs)}catch{return null}}var jR,WR,qR,cy,ko,fd=C(()=>{po();ay();jR=process.env.BOSTRAT_CURSOR_CHATS||xr.join(PR.homedir(),".cursor","chats");WR=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():"",qR=t=>Array.isArray(t)?t.filter(e=>e&&e.type==="tool-call"&&e.toolName).map(e=>e.toolName):[],cy=process.getBuiltinModule?.("node:sqlite"),ko={turns:[],trailingCommands:[],model:null,requestIds:[]}});import KR from"node:fs/promises";function wd(t){return wy.set(t.agent,t),t}function Js(t){return wy.get(t)||GR}async function yd(t,e={}){return(await Js(t.agent).readMessages(t,e)).map(gd(t))}async function gy(t,e={}){return(await Js(t.agent).readCommands(t,e)).map(gd(t))}async function yy(t,e={}){return(await Js(t.agent).readJobs(t,e)).map(gd(t))}var xo,pd,md,hd,GR,wy,gd,by=C(()=>{ke();Mi();po();oy();fd();wr();xo=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}},pd=class extends xo{transcript(e){return!e?.cwd||!e?.sessionId?null:ze(e.cwd,e.sessionId)}async readMessages(e,n){let r=this.transcript(e);return r?Iu(r,n):[]}async readCommands(e,n){let r=this.transcript(e);return r?ww(r,n):[]}async readJobs(e,n){let r=this.transcript(e);return r?ry(r,n):[]}async updatedAt(e){let n=this.transcript(e);if(!n)return null;try{return Math.round((await KR.stat(n)).mtimeMs)}catch{return null}}},md=class extends xo{async readMessages(e,n){return fy(e.cwd,e.sessionId,n)}async readCommands(e,n){return my(e.cwd,e.sessionId,n)}async updatedAt(e){return hy(e.cwd,e.sessionId)}},hd=class extends xo{sessionId(e){return e?.pinned?e.sessionId:null}async readMessages(e,n){return kw(e.cwd,this.sessionId(e),n)}async readCommands(e,n){return xw(e.cwd,this.sessionId(e),n)}async updatedAt(e){return vw(e.cwd,this.sessionId(e))}},GR=new xo("unknown"),wy=new Map;wd(new pd("claude",Su));wd(new md("cursor",Yi));wd(new hd("codex",Ps));gd=t=>e=>({...e,box:t.name,agent:t.agent,boxRole:t.role})});function Tr(t){let e=t.search(vd);return(e>=0?t.slice(0,e):t).trim()}function VR(t){if(!t)return"";let e=t.replace(/[│┌└├─┘┤┬┴┼─✂].*$/,"").trim();return!e||/hidden|\d+\s+lines?/i.test(e)?"":e}function zR(t){let e=String(t).trim();return!!(!e||Sr.test(t)||vd.test(e)||/hidden|\d+\s+lines?/i.test(e)||/notespress|press n to add/i.test(e)||/^\s*notes?\s*$/i.test(e))}function JR(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=YR(n,e);return n.forEach((a,i)=>{a.current=i===s}),{tabs:n,questionIndex:s,questionTotal:n.length,currentTabLabel:n[s].label}}function YR(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 xy(t){return t.replace(/[←→✔☐☒●▶]/g," ").replace(/\bSubmit\b/g," ").replace(/\s+/g," ").trim()}function XR(t,e=""){let n=String(t);if(!Sy.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(vr);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&&!Sr.test(r[u])&&a.push(f)}}if(s.length<2)return null;let i=s.map(u=>({label:Tr(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 QR(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||!Ty.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(vr);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&&!(ZR.test(n[c])||Sr.test(n[c]));c--){let l=n[c].trim();l&&a.unshift(l)}let i=s.map(c=>({label:Tr(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 t$(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(vr);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 n$(t,e=""){let n=String(t);if(!bd.test(n))return null;let r=n.replace(/\r/g,"").split(`
117
+ `),o=-1;for(let u=r.length-1;u>=0;u--)if(e$.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(vr);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&&!Sr.test(r[u])&&a.push(f)}}if(s.length<2||!s.some(u=>bd.test(u.label)))return null;let i=s.map(u=>({label:Tr(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 Sd(t){let e=[];for(let r=0;r<t.length;r++){let o=t[r].match(vr);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 r$(t,e=""){let n=String(t);if(!Ay.test(n)||!Ey.test(n)||Ar.test(n))return null;let r=n.replace(/\r/g,"").split(`
118
+ `),o=Sd(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:Tr(s.label),description:""}))}]}:null}function o$(t,e=""){let n=String(t);if(!_y.test(n)||Ar.test(n))return null;let r=n.replace(/\r/g,"").split(`
119
+ `),o=Sd(r);if(!o)return null;let s=o.map(a=>{let[i,...c]=a.label.split("\xB7");return{label:Tr(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 a$(t,e){let n=t[e].trim();for(let r=e+1;r<t.length;r++){let o=t[r].trim();if(!o||!s$.test(o)||Td.test(t[r]))break;n+=o}return n}function i$(t,e=""){let n=String(t);if(!Td.test(n)||Ar.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=a$(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 l$(t,e=""){let n=String(t);if(!kd.test(n)||!c$.test(n)||Ar.test(n))return null;let s=([...n.replace(/\r/g,"").split(`
121
+ `)].reverse().find(a=>kd.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 u$(t,e=""){let n=String(t);if(!Iy.test(n)||Ar.test(n))return null;let r=n.replace(/\r/g,"").split(`
122
+ `),o=Sd(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:Tr(s.label),description:""}))}]}:null}function d$(t,e=""){let n=String(t);if(Ar.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(Ry);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(Sr.test(r[l])||vd.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 f$(t){let e=-1;for(let r=t.length-1;r>=0;r--)if(xd.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 p$(t,e=""){let n=String(t);if(!vy.test(n)||!xd.test(n))return null;let r=n.replace(/\r/g,"").split(`
124
+ `),o=f$(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(vr);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)&&!(vr.test(r[D])||Sr.test(r[D]));D++){let F=r[D].trim();if(!(!F||zR(r[D])||ky.test(F))){T.desc=VR(F);break}}let d=l.filter(T=>!ky.test(T.label));if(!d.length)return null;let f=d.some(T=>T.hasCheckbox),p=Math.max(0,d.findIndex(T=>T.cursor)),h=s>=0?s+1:0,w=[];for(let T=h;T<u;T++){let D=r[T].trim();D&&!Sr.test(r[T])&&!/[☐☒]/.test(r[T])&&w.push(D)}let y=w.join(" ")||(s>=0?xy(r[s]):"")||"The agent is asking a question",k=s>=0?JR(r[s],y):null,x=k?.currentTabLabel||(s>=0?xy(r[s]):""),A=d.map(T=>({label:Tr(T.label),description:T.desc})),R=A.map(T=>T.label).join("|"),M=`claude:${k?`q${k.questionIndex+1}/${k.questionTotal}`:"q1/1"}:${x}:${y}:${R}`.slice(0,240),N=k?`claude:ask:${k.tabs.map(T=>T.label).join("|")}`.slice(0,240):M;return{provider:"claude",box:e,multiSelect:f,cursorIndex:p,promptId:M,groupId:N,...k?{questionIndex:k.questionIndex,questionTotal:k.questionTotal,currentTabLabel:k.currentTabLabel,tabs:k.tabs}:{},questions:[{question:y,header:x,multiSelect:f,options:A}]}}function Er(t,e){let n=String(e||"");return n?t==="claude"?vy.test(n)&&xd.test(n)||Sy.test(n)||bd.test(n)||Ty.test(n.trimEnd().split(`
125
+ `).pop()||"")?!0:Ar.test(n)?!1:Ay.test(n)&&Ey.test(n)||_y.test(n)||Td.test(n)||kd.test(n)||Iy.test(n)||Ry.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 Dn(t,e){return!t||!e?null:t.agent==="claude"?t$(e,t.name)||p$(e,t.name)||XR(e,t.name)||n$(e,t.name)||l$(e,t.name)||i$(e,t.name)||o$(e,t.name)||r$(e,t.name)||u$(e,t.name)||d$(e,t.name)||QR(e,t.name):t.agent==="cursor"||t.agent==="codex"?Dw(t.agent,e,t.name):null}async function Ad(t){if(!t)return null;let e=await Ve(t.name).catch(()=>"");return Dn(t,e)}function $y(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 Oy(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 vy,xd,vr,ky,Sr,vd,Sy,Ty,ZR,bd,e$,Ar,Ay,Ey,_y,Td,s$,kd,c$,Iy,Ry,Ed=C(()=>{Gt();Ni();vy=/to navigate\b.*\bEsc to cancel|Enter to select\b/,xd=/Chat about this/i,vr=/^\s*(❯)?\s*(\d+)\.\s+(?:\[([ xX✔])\]\s+)?(.+?)\s*$/,ky=/^(type something|chat about this|submit)\b/i,Sr=/^[─—-]{6,}\s*$/,vd=/[\u2500-\u257F\u2550-\u256F┌┐└┘├┤│┬┴┼─✂]/;Sy=/^\s*Switch model\?\s*$/m;Ty=/^\s*Enter to confirm\s*·\s*Esc to cancel\s*$/,ZR=/^\s*[─—▔-]{6,}\s*$/;bd=/Resume from summary/i,e$=/^\s*This session is\b/;Ar=/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/;Ay=/Choose the text style that looks best with your terminal/,Ey=/Let's get started\./;_y=/Select login method:/;Td=/Paste code here if prompted/,s$=/^[A-Za-z0-9%&=+._~#?/:\-]+$/;kd=/OAuth error:/,c$=/Press Enter to retry\./;Iy=/Quick safety check: Is this a project you created or one you trust/;Ry=/^(.{0,60}?)Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/});function Zi(t,e,n){if(!t||!e)return null;for(let r of m$)if(r.provider===t.agent)try{if(r.match(e,n))return r}catch{}return null}function w$(t){let e=_d.get(t);return e||(e={sentAt:[],last:0,emitted:new Set},_d.set(t,e)),e}function Ny(t,e,n=Date.now()){let r=w$(t);if(r.sentAt=r.sentAt.filter(s=>n-s<My),r.sentAt.length>=Cy)return{action:"give-up"};if(n-r.last<h$)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 Py(t,e=Date.now()){let n=_d.get(t);return n?n.sentAt.filter(r=>e-r<My).length>=Cy:!1}var m$,h$,Cy,My,_d,Id=C(()=>{m$=[{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"]}];h$=5e3,Cy=5,My=3600*1e3,_d=new Map});function vo(t){return typeof t=="string"?t.trim():""}var By=C(()=>{});import{execFile as g$}from"node:child_process";import{promisify as y$}from"node:util";async function At(t,e,{input:n}={}){let r=$d("git",["-C",t,...e],{maxBuffer:Dy});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 At(t,["rev-parse","--is-inside-work-tree"]);return e.trim()==="true"}catch{return!1}}async function jy(t){let{stdout:e}=await At(t,["rev-parse","--show-toplevel"]);return e.trim()}async function b$(t){try{return await At(t,["rev-parse","--verify","HEAD"]),!0}catch{return!1}}async function So(t,e="bostrat: subtask snapshot"){let{stdout:n}=await At(t,["rev-parse","--absolute-git-dir"]),r=`${n.trim()}/bostrat-snapshot-index`,o={...process.env,GIT_INDEX_FILE:r},s=(a,i)=>$d("git",["-C",t,...a],{maxBuffer:Dy,env:o,...i});try{let a=await b$(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 $d("rm",["-f",r])}catch{}}}async function Od(t,e){let{stdout:n}=await At(t,["status","--porcelain"]);return n.trim()?(await At(t,["add","-A"]),await At(t,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","-m",e]),!0):!1}async function Cd(t,{ignorePlumbing:e=!1}={}){let{stdout:n}=await At(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 Md(t,e){if(!e)return 0;try{let{stdout:n}=await At(t,["rev-list","--count",`${e}..HEAD`]);return Number(n.trim())||0}catch{return 0}}async function To(t,e,n,r){return await At(t,["worktree","add","--no-track","-b",n,e,r]),e}async function Ly(t,e){try{return await At(t,["rev-parse","--verify","--quiet",`refs/heads/${e}`]),!0}catch{return!1}}async function tc(t,e,n){return await At(t,["worktree","add",e,n]),e}async function Ao(t){if(process.env.BOSTRAT_TRACK_BASE_REF)return process.env.BOSTRAT_TRACK_BASE_REF;try{let{stdout:e}=await At(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 At(t,["rev-parse","--verify","--quiet",e]),n}catch{}return"HEAD"}async function Nd(t){await At(t,["init","-q"]),await At(t,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","--allow-empty","-qm","bostrat: track workspace"])}async function oe(t,e){try{await At(t,["worktree","remove","--force",e])}catch{try{await At(t,["worktree","prune"])}catch{}}}function k$(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 Pd(t,e){return!e||!e.length?t:[...t,"--",".",...e.map(n=>`:(exclude)${n}`)]}async function Bd(t,e,n,r){let{stdout:o}=await At(t,Pd(["diff","--shortstat",e,n],r));return k$(o)}async function Dd(t,e,n,r){let{stdout:o}=await At(t,Pd(["diff","--name-only",e,n],r));return o.split(`
129
+ `).map(s=>s.trim()).filter(Boolean)}async function jd(t,e,n,r){let{stdout:o}=await At(t,Pd(["diff","--binary",e,n],r));if(!o.trim())return{applied:!0,empty:!0,conflicts:[]};if((await Rd(t,o,["--whitespace=nowarn"])).ok)return{applied:!0,empty:!1,conflicts:[]};let s=await Rd(t,o,["--3way","--whitespace=nowarn"]),a=await x$(t);return a.length>0?{applied:!1,empty:!1,conflicts:a}:s.ok?{applied:!0,empty:!1,conflicts:[]}:(await Rd(t,o,["--reject","--whitespace=nowarn"]),{applied:!1,empty:!1,conflicts:[`patch did not apply cleanly: ${s.err}`]})}async function Rd(t,e,n){try{return await At(t,["apply",...n,"-"],{input:e}),{ok:!0}}catch(r){return{ok:!1,err:r?.stderr?.trim()||r?.message||String(r)}}}async function x$(t){try{let{stdout:e}=await At(t,["diff","--name-only","--diff-filter=U"]);return e.split(`
130
+ `).map(n=>n.trim()).filter(Boolean)}catch{return[]}}var $d,Dy,Ld=C(()=>{$d=y$(g$),Dy=64*1024*1024});import Fd from"node:fs/promises";import Uy from"node:path";import v$ from"node:os";function Ky(t){let e=new Date(t);return e.setHours(0,0,0,0),e.setDate(e.getDate()-(e.getDay()+6)%7),e.getTime()}function Gy(t){let e=new Date(t);return e.setHours(0,0,0,0),e.setDate(1),e.getTime()}function Vy(t){let e=new Date(Ky(t));return e.setDate(e.getDate()+7),e.getTime()}function zy(t){let e=new Date(Gy(t));return e.setMonth(e.getMonth()+1),e.getTime()}function nc(t=Date.now()){for(let[e,n]of Object.entries(Eo)){let r=n.startOf(t);if(r!==Ye[e]){Ye[e]=r;for(let o of _r.values())o[e]=0;for(let o of _o)o.includes(`:${e}:`)&&!o.endsWith(`:${r}`)&&_o.delete(o)}}}function Jy(t,e){let n=ve?.caps?.[t]?.[Eo[e].capKey];return Number.isFinite(n)&&n>0?n:null}function Ir(t,e=Date.now()){if(!t||!Hd||!ve?.caps)return null;nc(e);let n=_r.get(t);for(let r of Object.keys(Eo)){let o=Jy(t,r);if(o==null)continue;let s=n?.[r]||0;if(s>=o)return{provider:t,window:r,limitUsd:o,spentUsd:ec(s),resetsAt:Eo[r].nextStart(e)}}return null}function Yy(t,e){let n=`hit:${t}:${e.provider}:${e.window}:${Ye[e.window]}`;return _o.has(n)?!1:(_o.add(n),!0)}function Fy(t,e,n,r=Date.now()){if(!t||!e)return;nc(r);let o=S$(t);for(let[s,a]of Object.entries(Eo))n>=Ye[s]&&n<a.nextStart(r)&&(o[s]+=e)}async function T$(t,e,n=Date.now()){if(!ve?.caps||!Ud)return;let r=_r.get(t);if(r)for(let[o,s]of Object.entries(Eo)){let a=Jy(t,o);if(a==null)continue;let i=r[o]||0;if(i<a*qy||i>=a)continue;let c=`warn:${t}:${o}:${Ye[o]}`;if(!_o.has(c)){_o.add(c);try{let l=await Ud(e);if(!l)continue;await I(l,{type:"usage.cap.warning",actor:"system",provider:t,payload:{provider:t,window:o,limitUsd:a,spentUsd:ec(i),pct:Math.round(i/a*100),resetsAt:s.nextStart(n)}})}catch{}}}}function Xy(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 rc(t,{source:e="local",updatedAt:n=Date.now()}={}){ve={caps:Xy(t),updatedAt:n,source:e};try{await Fd.mkdir(Hy,{recursive:!0}),await Fd.writeFile(Wy(),JSON.stringify(ve,null,2))}catch{}return Ys()}function Ys(t=Date.now()){nc(t);let e=new Set([..._r.keys(),...Object.keys(ve?.caps||{})]),n={};for(let r of e){let o=_r.get(r);n[r]={weeklyUsd:ec(o?.weekly||0),monthlyUsd:ec(o?.monthly||0)}}return{caps:ve?.caps||{},configured:!!ve,seeded:Hd,updatedAt:ve?.updatedAt??null,spent:n,windows:{weekly:{start:Ye.weekly,resetsAt:Vy(t)},monthly:{start:Ye.monthly,resetsAt:zy(t)}},warnPct:qy}}async function Zy({listTracks:t,getTrack:e}={}){Ud=e||null,nc();try{let o=JSON.parse(await Fd.readFile(Wy(),"utf8"));ve={caps:Xy(o?.caps),updatedAt:o?.updatedAt??null,source:o?.source??"file"}}catch{ve=null}let n=Date.now();Qt.on("event",o=>{if(o?.type!=="cost.recorded")return;let{usd:s}=Je(o);Fy(o.provider||"unknown",s,o.ts??Date.now()),T$(o.provider||"unknown",o.trackId).catch(()=>{})});let r=Math.min(Ye.weekly,Ye.monthly);for(let o of await t?.()||[]){let s;try{s=await B(o)}catch{continue}for(let a of s){if(a.type!=="cost.recorded")continue;let i=a.ts??0;i<r||i>=n||Fy(a.provider||"unknown",Je(a).usd,i,n)}}return Hd=!0,Ys()}var Hy,Wy,qy,Eo,ve,Hd,Ye,_r,_o,Ud,S$,ec,oc=C(()=>{st();kr();Hy=process.env.BOSTRAT_STATE_DIR||Uy.join(process.env.HOME||v$.tmpdir(),".bostrat"),Wy=()=>Uy.join(Hy,"usage-caps.json"),qy=.8;Eo={weekly:{startOf:Ky,nextStart:Vy,capKey:"weeklyUsd"},monthly:{startOf:Gy,nextStart:zy,capKey:"monthlyUsd"}},ve=null,Hd=!1,Ye={weekly:0,monthly:0},_r=new Map,_o=new Set,Ud=null,S$=t=>{let e=_r.get(t);return e||(e={weekly:0,monthly:0},_r.set(t,e)),e};ec=t=>Math.round(t*1e4)/1e4});import A$ from"node:fs/promises";import E$ from"node:os";import Qy from"node:path";function ab(t){return t==="codex"?$$:t==="cursor"?sb:rb}function tb(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 eb(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 O$(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 nb(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 ib(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&&!ob.has(o))throw new Error(`unknown codex effort "${o}" (low | medium | high | xhigh)`);return{model:r,effort:o||null}}if(t==="cursor"){let r=sb.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 Xs(t,e,{timeoutMs:n=_$}={}){let r=Date.now()+n;for(;;){let o=await xt(t,{lines:80}).catch(()=>""),s=e(o);if(s)return s;if(Date.now()>r)return null;await sc(I$)}}async function C$(t,e){return await Pt(t,`/model ${e.model}`,Oe("claude")),{verified:!1,note:"confirmed when the next turn's transcript model flips"}}async function M$(t,e){await Ii(t),await Pt(t,"/model",{enter:!1}),await sc(250),await _t(t,["Enter"],{kind:"model-switch"});let n=await Xs(t,tb);if(!n)throw new Error("codex model picker didn't open");let r=n.find(i=>i.id===e.model);if(!r)throw await _t(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=O$(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 Xs(t,i=>eb(i)||!tb(i)&&o(i)&&{done:o(i)});if(!s)throw await _t(t,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error("codex reasoning-level picker didn't open");if(!s.done){let i=e.effort?ob.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 _t(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 Xs(t,i=>!eb(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 N$(){let t=Qy.join(process.env.CURSOR_CONFIG_DIR||Qy.join(E$.homedir(),".cursor"),"cli-config.json");try{return JSON.parse(await A$.readFile(t,"utf8"))?.model||null}catch{return null}}async function P$(t,e){await Ii(t),await $i(t,`/model ${e.filter}`,{kind:"model-switch"});let n=await Xs(t,nb),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 Xs(t,nb,{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 _t(t,["Down"],{kind:"model-switch"}),await sc(250)}if(!n||!s||!o(s)){await _t(t,["Escape"],{kind:"model-switch"}).catch(()=>{});let c=Array(`/model ${e.filter}`.length).fill("BSpace");throw await _t(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 _t(t,["Enter"],{kind:"model-switch"}),await sc(800);let a=await N$();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 cb(t,e,n){return t==="codex"?M$(e,n):t==="cursor"?P$(e,n):C$(e,n)}var sc,_$,I$,rb,R$,$$,ob,sb,lb=C(()=>{Gt();Us();sc=t=>new Promise(e=>setTimeout(e,t)),_$=Number(process.env.BOSTRAT_MODEL_PICKER_TIMEOUT_MS)||8e3,I$=300,rb=[{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([...rb.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"]),$$=[{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"}],ob=new Map([["low","Low"],["medium","Medium"],["high","High"],["xhigh","Extra high"]]),sb=[{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 ic(t){let e=t||{},n=B$(e);return n&&(n.payload={ts:e.at,...n.payload}),n}function B$(t){switch(t.type){case"said":return{type:"turn.user",actor:"user",source:"orchestrator",boxId:t.box,provider:te(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:te(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:te(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:te(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:te(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:te(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:te(t.agent),payload:{...Rr(t)}};case"subtask-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:t.box||t.to,provider:te(t.agent||t.toAgent),payload:{kind:"subtask-failed",...Rr(t)}};case"subtask-resumed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:t.box,provider:te(t.agent),payload:{change:"subtask-resumed",...Rr(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",...Rr(t)}};case"archived":case"unarchived":case"track-deleted":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:t.type,...Rr(t)}};case"rehydrated":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:t.box,provider:te(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:te(t.agent),payload:{...Rr(t)}};case"transferred-out":return null;case"retagged":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:"retagged",...Rr(t)}};case"rehydrate-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:t.box,provider:te(t.agent),payload:{kind:"rehydrate-failed",reason:t.reason}};default:return null}}function fb(t,e){let n=ic(e);if(!n)return;let r=e?.type==="track-deleted"?{id:t.id}:t;qd(()=>I(r,n))}async function pb(t){if(!(!t?.id||ub.has(t.id))){ub.add(t.id);try{let e=await B(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=ic(r);!o||n.has(`${o.type}|${o.payload?.ts??"?"}`)||await I(t,o)}}catch{}}}function Rr(t){let{type:e,at:n,...r}=t;return r}function mb(t,e,n){!n?.promptId||Wd.get(t.id)===n.promptId||(Wd.set(t.id,n.promptId),qd(()=>I(t,{type:"prompt.raised",actor:"agent",source:"pane",boxId:e?.name,provider:te(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 Kd(t,e,n,r={}){Wd.delete(t.id),qd(()=>I(t,{type:"prompt.answered",actor:"user",source:"orchestrator",boxId:e?.name,provider:te(n?.provider||e?.agent),payload:{promptId:n?.promptId,...r}}))}var te,ac,qd,db,ub,Wd,Gd=C(()=>{st();te=t=>t||null;ac=Promise.resolve(),qd=t=>(ac=ac.then(t).catch(()=>{}),ac),db=()=>ac;ub=new Set;Wd=new Map});function U$(t){return String(t).split(/(?<=[.?!])\s+|\n+/).map(e=>e.trim()).filter(Boolean)}function kb(t){let e=String(t||"").trim();if(!e)return null;let n=e.slice(-600);for(let r of U$(n).reverse()){if(!D$.test(r))continue;let o=r.endsWith("?")&&r.length<=F$&&L$.test(r);if(j$.test(r)||o)return r.length>200?r.slice(0,197)+"\u2026":r}return null}function xb(t){let e=String(t||""),n=[];H$.test(e)&&n.push("commit"),W$.test(e)&&n.push("rebase"),q$.test(e)&&n.push("push");let r=G$.test(e);!r&&K$.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 Io(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 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 vb(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 Sb(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<=V$&&n.push({box:r.box,from:r.from,to:e+1e12}),n}function Tb(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+z$||(!o||s.ts>=o.ts)&&(o=s);o&&n.add(o)}return n}function Ab(t){let e=(Array.isArray(t)?t:[]).filter(r=>hb[r]).map(r=>hb[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 wb,gb,yb,bb,D$,j$,L$,F$,cc,H$,W$,q$,K$,G$,V$,z$,hb,Ro=C(()=>{wb=/(?<!\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,gb=/(?<!\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,yb=/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,bb=/(?<!\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(?:${wb}|${gb}|${yb}|${bb})\\b`,"i"),j$=/\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,L$=/^(?:commit|push|open|create|raise|rebase|ready|ok(?:ay)?\s+to|good\s+to)\b/i,F$=90;cc=["commit","rebase","push","pr"],H$=new RegExp(`\\b(?:${wb})\\b`,"i"),W$=new RegExp(`\\b(?:${bb})\\b`,"i"),q$=new RegExp(`\\b(?:${gb})\\b`,"i"),K$=new RegExp(`\\b(?:${yb})\\b`,"i"),G$=/\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;V$=3e4;z$=2500;hb={commit:"commit",rebase:"rebase",push:"push",pr:"open a PR"}});import J$ from"node:fs";import Vd from"node:fs/promises";import Rb from"node:path";import Y$ from"node:os";function Cb(t,e=!1){if(!e&&t-_b<X$)return;_b=t;let n=JSON.stringify({windowStart:$o,byCaller:Object.fromEntries(Xe),lastHour:jn});Ib=Ib.then(()=>Vd.mkdir($b,{recursive:!0})).then(()=>Vd.writeFile(`${lc}.tmp`,n)).then(()=>Vd.rename(`${lc}.tmp`,lc)).catch(()=>{})}function Mb(t){t-$o<Ob||(jn={start:$o,total:uc(Xe),byCaller:Object.fromEntries(Xe)},jn.total&&console.log(`[github] ${jn.total} calls last hour`,jn.byCaller),$o=t,Xe=new Map,Cb(t,!0))}function Ze(t="other",e=Date.now()){Mb(e),Xe.set(t,(Xe.get(t)||0)+1),Cb(e)}function Nb(t=Date.now()){return Mb(t),{windowStart:$o,total:uc(Xe),byCaller:Object.fromEntries(Xe),lastHour:jn,backoffUntil:$r>t?$r:null}}function Ln(t){return Z$.test(String(t?.message||t||""))}function Fn(t,e=Date.now()){return $r<=e&&console.warn(`[github] rate limited \u2014 backing off ${Eb/6e4} min:`,String(t?.message||t||"").slice(0,200)),$r=Math.max($r,e+Eb),$r}function dc(t=Date.now()){return Math.max(0,$r-t)}var $b,lc,Ob,Eb,X$,$o,Xe,jn,$r,_b,uc,Ib,Z$,Zs=C(()=>{$b=process.env.BOSTRAT_STATE_DIR||Rb.join(process.env.HOME||Y$.tmpdir(),".bostrat"),lc=Rb.join($b,"github-metrics.json"),Ob=60*6e4,Eb=5*6e4,X$=6e4,$o=Date.now(),Xe=new Map,jn=null,$r=0,_b=0,uc=t=>[...t.values()].reduce((e,n)=>e+n,0);try{let t=JSON.parse(J$.readFileSync(lc,"utf8"));t?.windowStart&&(Date.now()-t.windowStart<Ob?($o=t.windowStart,Xe=new Map(Object.entries(t.byCaller||{})),jn=t.lastHour||null):uc(new Map(Object.entries(t.byCaller||{})))&&(jn={start:t.windowStart,total:uc(new Map(Object.entries(t.byCaller||{}))),byCaller:t.byCaller||{}}))}catch{}Ib=Promise.resolve();Z$=/rate limit|too quickly|abuse detection|HTTP 429/i});import Q$ from"node:crypto";import fc from"node:fs/promises";import Pb from"node:path";import tO from"node:os";async function It(){return Un||(zd??=fc.readFile(Yd,"utf8").then(t=>({links:JSON.parse(t)?.links??{},existed:!0})).catch(()=>({links:{},existed:!1})).then(async({links:t,existed:e})=>{if(Un=t,!e&&kt()){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;Un[J(i.repo,i.number)]=i}Object.keys(Un).length&&await Xd().catch(()=>{})}}return Un}).finally(()=>zd=null),zd)}async function Xd(){let t=JSON.stringify({links:Un},null,2),e=`${Yd}.${process.pid}.tmp`;await fc.mkdir(Bb,{recursive:!0}),await fc.writeFile(e,t),await fc.rename(e,Yd)}async function Dt(t){Jd=Jd.then(Xd,Xd),await Jd.catch(()=>{});let e=Un?.[t];e&&Kt("prlinks",{id:Db(t),updatedAt:Date.now(),...e},{trackId:e.trackId??null}).catch(()=>{})}async function se({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 It(),c=J(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:eO.has(a),firstSeen:Date.now()},await Dt(J(t,e)),{link:i[c],created:!0})}async function Qe(t,e){if(!t||e==null)return null;let n=(await It())[J(t,e)];return!n||n.announced?null:(n.announced=!0,await Dt(J(t,e)),n)}async function Vt(t,e){return!t||e==null?null:(await It())[J(t,e)]??null}async function Hn(t,e,n){if(!t||e==null)return null;let r=(await It())[J(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(J(t,e)),r):null}async function jb(t,e,{headSha:n=null,trackId:r=null}={}){if(!t||e==null)return null;let o=(await It())[J(t,e)];return o?(o.ciFix={delegatedAt:Date.now(),headSha:n,trackId:r},await Dt(J(t,e)),o):null}async function Lb(t,e,{headSha:n=null,trackId:r=null}={}){if(!t||e==null)return null;let o=(await It())[J(t,e)];return o?(o.reconcile={delegatedAt:Date.now(),headSha:n,trackId:r},await Dt(J(t,e)),o):null}async function pc(t,e,{headSha:n=null}={}){if(!t||e==null)return null;let r=(await It())[J(t,e)];return!r||!r.ciFix?null:(r.ciFixAwait={since:Date.now(),trackId:r.ciFix.trackId??null,headSha:n},delete r.ciFix,await Dt(J(t,e)),r)}async function mc(t,e){if(!t||e==null)return null;let n=(await It())[J(t,e)];return!n||!n.ciFixAwait?null:(delete n.ciFixAwait,await Dt(J(t,e)),n)}async function hc(t,e,{headSha:n=null}={}){if(!t||e==null)return null;let r=(await It())[J(t,e)];return!r||!r.reconcile?null:(r.reconcileAwait={since:Date.now(),trackId:r.reconcile.trackId??null,headSha:n},delete r.reconcile,await Dt(J(t,e)),r)}async function wc(t,e){if(!t||e==null)return null;let n=(await It())[J(t,e)];return!n||!n.reconcileAwait?null:(delete n.reconcileAwait,await Dt(J(t,e)),n)}async function Fb(t,e,{at:n=Date.now()}={}){if(!t||e==null)return null;let r=(await It())[J(t,e)];return r?(r.baseFoldAt=n,await Dt(J(t,e)),r):null}async function Ub(t,e){if(!t||e==null)return null;let n=(await It())[J(t,e)];return!n||!n.baseFoldAt?null:(delete n.baseFoldAt,await Dt(J(t,e)),n)}async function Hb(t,e,n){if(!t||e==null||!n)return null;let r=(await It())[J(t,e)];return r?(r.lastHeadSha=n,await Dt(J(t,e)),r):null}async function Qs(t,e,{merge:n=null}={}){if(!t||e==null)return null;let r=(await It())[J(t,e)];return r?(r.armedAt=Date.now(),n&&(r.autoMerge={method:n.method||"merge",armedAt:r.armedAt}),await Dt(J(t,e)),r):null}async function Or(t,e,n=!0){if(!t||e==null)return null;let r=(await It())[J(t,e)];return r?(n?r.archiveOnMerge=!0:delete r.archiveOnMerge,await Dt(J(t,e)),r):null}async function ta(t,e,n=!0){if(!t||e==null)return null;let r=(await It())[J(t,e)];return r?(n?r.notifyOnMerge=!0:delete r.notifyOnMerge,await Dt(J(t,e)),r):null}async function Wb(t,e,n){if(!t||e==null)return null;let r=(await It())[J(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(J(t,e)),r}async function ea(t,e){if(!t||e==null)return null;let n=(await It())[J(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(J(t,e)),n)}async function qb(){return Object.values(await It()).filter(t=>!nO.has(t.state))}async function Cr(){return Object.values(await It()).sort((t,e)=>e.firstSeen-t.firstSeen)}async function Kb(){if(!kt())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 It(),r=0;for(let[o,s]of Object.entries(n))await Kt("prlinks",{id:Db(o),updatedAt:Date.now(),...s},{trackId:s.trackId??null}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}var Bb,Yd,J,Db,Un,zd,Jd,eO,nO,Wn=C(()=>{An();Bb=process.env.BOSTRAT_STATE_DIR||Pb.join(process.env.HOME||tO.tmpdir(),".bostrat"),Yd=Pb.join(Bb,"pr-links.json"),J=(t,e)=>`${t}#${Number(e)}`,Db=t=>{let e=t.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^[^A-Za-z0-9]+/,"").slice(0,55),n=Q$.createHash("sha256").update(t).digest("hex").slice(0,8);return`${e||"pr"}-${n}`},Un=null,zd=null,Jd=Promise.resolve();eO=new Set(["api","observed","reconciled"]);nO=new Set(["merged","closed","lost"])});function gc(t,e,n){let{state:r,reason:o}=Nu(e,n);if(r!=="unknown"){if(t){let a=Date.now();for(let[i,c]of na)a-c.at>=Gb()&&na.delete(i);na.set(t,{busy:r==="busy",at:a})}return r==="busy"}if(o!=="narrow"||!t)return!1;let s=na.get(t);return s?Date.now()-s.at>=Gb()?(na.delete(t),!1):s.busy:!1}async function Zd(t,e){let n={working:!1,prompted:!1};if(!t)return n;let r=await xt(t,{lines:Nt}).catch(()=>"");if(!gc(t,e,r))return Uw(e,r)?{working:!0,prompted:!1}:n;if(Er(e,r)){let o=await Ve(t).catch(()=>r),s=Dn({name:t,agent:e},o);if(s)return!Zi({name:t,agent:e},s,o)||Py(t)?{working:!1,prompted:!0}:{working:!1,prompted:!1}}return{working:!0,prompted:!1}}async function Mr(t,e){return(await Zd(t,e)).working}var Gb,na,ra=C(()=>{Gt();ji();Ed();Id();Gb=()=>Number(process.env.BOSTRAT_NARROW_CARRY_MS)||9e4,na=new Map});import{execFile as rO}from"node:child_process";import{promisify as oO}from"node:util";async function Oo(t){if(!t)return null;let e=Vb.get(t);if(e&&Date.now()-e.at<aO)return e.branch;let n=null;try{let{stdout:r}=await sO("git",["-C",t,"symbolic-ref","--short","-q","HEAD"],{timeout:5e3});n=r.trim()||null}catch{n=null}return Vb.set(t,{at:Date.now(),branch:n}),n}function zb(t){return String(t||"").match(iO)?.[1]??null}function cO(t,e){let n=zb(t);return!!n&&!!e&&n===e}function Jb(t,e){let n=zb(t);return!!n&&n!==e}function lO(t){let e=t?.workspace;return e?.kind==="multi"?(e.repos??[]).map(n=>n?.dir).filter(Boolean):[e?.dir||t?.cwd].filter(Boolean)}async function Co(t){let e=[],n=r=>{r&&!e.includes(r)&&e.push(r)};n(t?.workspace?.branch??null);for(let r of lO(t))n(await Oo(r));return e}async function yc(t,e,n=()=>!0){if(!e)return null;let r=(t??[]).filter(a=>a&&n(a)),o=r.find(a=>a.workspace?.branch===e);if(o)return o;let s=r.find(a=>cO(e,a.id));if(s)return s;for(let a of r)if(!(a.archivedAt||a.transferredTo)&&(await Co(a)).includes(e))return a;return null}var sO,aO,Vb,iO,Mo=C(()=>{sO=oO(rO),aO=5e3,Vb=new Map;iO=/^track\/.+-([0-9a-f]{8})$/});import{execFile as uO}from"node:child_process";import{promisify as dO}from"node:util";async function Qd(t,e,{midTurn:n=Mr,pollMs:r=fO,capMs:o=pO}={}){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 ek(t){let e=String(t||""),n=0;for(let r=0;r<64;r++){Yb.lastIndex=n;let o=Yb.exec(e);if(!o)break;n=o.index+o[0].length;let s=o[1]==="-",a=o[2]??o[3]??o[4],i=e.indexOf(`
135
+ `,o.index);if(i<0)break;let l=new RegExp("^"+(s?"\\t*":"")+kO(a)+"[ \\t]*$","m").exec(e.slice(i+1));if(!l)continue;let u=i+1+l.index+l[0].length;e=e.slice(0,i)+e.slice(u)}return e}function tf(t,e){return t.slice(e).replace(/^[\s;&|)]+/,"").replace(/"[^"]*"|'[^']*'/g,'""').split(/[;&|\n]/)[0]}function rk(t){let e=ek(t),n=e.match(gO);if(!n)return null;let r=tf(e,n.index);return bO.test(r)?null:{repo:r.match(nk)?.[1]??null,head:r.match(xO)?.[1]??null}}function ok(t){let e=ek(t),n=e.match(yO);if(!n)return null;let r=tf(e,n.index),o=tf(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("-")){SO.has(c)&&i++;continue}s=c.replace(/^["']+|["']+$/g,"")||null;break}return{repo:r.match(nk)?.[1]??null,selector:s,auto:/\s--auto\b/.test(r)}}async function AO(t,e,{exclude:n=()=>!1}={}){let r=async i=>{Ze("observer");let{stdout:c}=await Xb("gh",["pr","list","--repo",t,"--author","@me","--state","all","--limit","10","--json",TO],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...i}}).catch(l=>{throw Ln(l)&&Fn(l),l});return JSON.parse(c||"[]")},o=i=>(i||[]).filter(c=>Date.parse(c.createdAt)>=e-mO&&!n(c)),s=await Ie({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 EO(t,e){if(e)return[e];let n=[];for(let r of sk(t)){let o=await ut(r).catch(()=>null);o&&!n.includes(o)&&n.push(o)}for(let r of await qe().catch(()=>[])){let o=await ut(r.path).catch(()=>null);o&&!n.includes(o)&&n.push(o)}return n}function sk(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 _O(t,e,n){let r=await Co(t).catch(()=>[t.workspace?.branch].filter(Boolean)),o=e?.head??null,s=c=>r.includes(c)||o&&c===o,a=c=>o!=null&&!s(c.headRefName)||vO(c.headRefName,t.id),i=[];for(let c of await EO(t,e?.repo??null)){let l;try{l=await AO(c,n,{exclude:a})}catch{continue}for(let u of l){let d=await Vt(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 ak(t,e,{delays:n=Zb,turnEnd:r}={}){let o=rk(e.command);if(!o)return null;let s=!!ok(e.command),a=`${t.id}|${e.id??e.ts??e.command}`;if(qn.has(a))return null;qn.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 _O(t,o,i).catch(()=>null);if(u?.settled)return null;if(!u)continue;let{slug:d,pr:f}=u,{link:p,created:h}=await se({repo:d,number:f.number,trackId:t.id,url:f.url,headRef:f.headRefName,title:f.title,source:"observed"});return!h&&!(p?.trackId===t.id&&await Qe(d,f.number))?null:(await Qd(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{qn.delete(a)}})();return c.catch(()=>qn.delete(a)),c}function ik(t,e,{delays:n=Zb,turnEnd:r,openedWait:o}={}){let s=ok(e.command);if(!s)return null;let a=`merge|${t.id}|${e.id??e.ts??e.command}`;if(qn.has(a))return null;qn.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 h=sk(t);if(h.length>1&&/^\d+$/.test(String(s.selector??"")))return null;for(let w of h){let y=await ut(w).catch(()=>null);y&&!d.includes(y)&&d.push(y)}}if(l||=(await Co(t).catch(()=>[])).filter(h=>h!==t.workspace?.branch)[0]||t.workspace?.branch,!d.length||!l)return null;c=d[0];let f=async(h,w)=>{let y=await Vt(c,h.number);return y&&y.trackId!==t.id?null:(y||await se({repo:c,number:h.number,trackId:t.id,url:h.url,headRef:h.headRefName,title:h.title,source:"merge-observed"}),await Qs(c,h.number),w&&((await B(t).catch(()=>[])).some(A=>A.type==="pr.state.changed"&&(A.payload?.change==="auto-armed"||A.payload?.change==="merged")&&A.payload?.number===h.number)||(await Qd(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(M=>setTimeout(M,h));let w=[];for(let M of d)try{Ze("observer");let{stdout:N}=await Xb("gh",["pr","view",String(l),"--repo",M,"--json",IO],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...await Ie({slug:M})}}),T=JSON.parse(N||"null");T?.number&&w.push({slug:M,pr:T})}catch(N){Ln(N)&&Fn(N)}let y=w.find(M=>M.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 x=await Vt(c,k.number);if(x&&x.trackId!==t.id)return null;x||await se({repo:c,number:k.number,trackId:t.id,url:k.url,headRef:k.headRefName,title:k.title,source:"merge-observed"}),await Qd(e.box,e.agent,r);let A=await B(t).catch(()=>[]);if(A.some(M=>M.type==="pr.state.changed"&&M.payload?.change==="merged"&&M.payload?.number===k.number))return null;let R=M=>M.some(N=>N.type==="pr.state.changed"&&N.payload?.change==="opened"&&N.payload?.number===k.number),V=0;if(!R(A)){if(rk(e.command)&&await Qe(c,k.number)){let M=Date.now();V=M+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:M,change:"opened",number:k.number,url:k.url,title:k.title,branch:k.headRefName,repo:c,selfMerge:!0}})}else if((await Vt(c,k.number))?.announced){let M=o?.capMs??hO,N=o?.pollMs??wO,T=Date.now()+M;for(;Date.now()<T&&(await new Promise(D=>setTimeout(D,N)),!R(await B(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(),V),change:"merged",number:k.number,url:k.url,title:k.title,branch:k.headRefName,repo:c}}),await en(c,k.number).catch(()=>{}),await tn(c,k.number).catch(()=>{}),await Hn(c,k.number,"merged"),k}return p?f(p,!1):null}finally{qn.delete(a)}})();return i.catch(()=>qn.delete(a)),i}var Xb,Zb,fO,pO,mO,hO,wO,Qb,tk,gO,yO,bO,Yb,kO,nk,xO,vO,SO,TO,qn,IO,ck=C(()=>{st();cr();qt();Zs();Wn();Nr();ra();Mo();Xb=dO(uO),Zb=[4e3,15e3,45e3],fO=2500,pO=5*6e4;mO=15e3,hO=9e4,wO=2e3,Qb=/(?:^|[;&|\n({`]\s*|\)\s*)(?:(?:then|do|else|elif|if|while|until|time)\s+)?/.source,tk=/gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+/.source,gO=new RegExp(`${Qb}${tk}create\\b`),yO=new RegExp(`${Qb}${tk}merge\\b`),bO=/\s--web\b/,Yb=/<<(-?)\s*(?:'([^'\n]+)'|"([^"\n]+)"|\\?([A-Za-z_][\w-]*))/g,kO=t=>t.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");nk=/(?:--repo|-R)[\s=]+([\w.-]+\/[\w.-]+)/,xO=/(?:--head|-H)[\s=]+([^\s"'`;&|]+)/,vO=Jb;SO=new Set(["--subject","-t","--body","-b","--body-file","-F","--match-head-commit","--author-email","-A","--repo","-R"]);TO="number,url,title,headRefName,createdAt";qn=new Set;IO="number,url,title,headRefName,state"});import RO from"node:fs/promises";import nf from"node:path";import $O from"node:os";function ef(t,e){let n=new RegExp(`\\b${e}="([^"]*)"`).exec(t);return n?n[1]:null}function bc(t){let e=OO.exec(String(t||""));if(!e)return null;let[,n,r]=e,o=ef(n,"from"),s=o?o.replace(/^uds:/,""):null,a=lk(s);return{socket:s,pid:a,name:ef(n,"from-name"),mode:ef(n,"from-mode"),text:r.trim()}}function lk(t){let e=/(\d+)\.sock$/.exec(String(t||""));return e?Number(e[1]):null}function CO(){return process.env.CLAUDE_CONFIG_DIR?nf.join(process.env.CLAUDE_CONFIG_DIR,"sessions"):nf.join($O.homedir(),".claude","sessions")}async function MO(t){let e=lk(t);if(!e)return null;try{let n=await RO.readFile(nf.join(CO(),`${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 uk(t,e){let n=await MO(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 OO,rf=C(()=>{OO=/<cross-session-message\b([^>]*)>([\s\S]*?)<\/cross-session-message>/});function of(t=process.env){return!!(gt(t)&&t.BOSTRAT_PLANE_TOKEN)}async function sf({loopId:t,outcome:e,note:n=null,env:r=process.env}={}){if(!of(r))return{ok:!1,source:"unconfigured"};let o=new AbortController,s=setTimeout(()=>o.abort(),dk);try{let a=await fk(`${gt(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 pk(t,{provider:e=null,cls:n="other",status:r=null,text:o=""}={},{env:s=process.env,now:a=Date.now}={}){if(!t?.id||!String(t.name||"").startsWith("\u21BB"))return{ok:!1,source:"not-a-loop-track"};if(!of(s))return{ok:!1,source:"unconfigured"};let i=kc.get(t.id)||0;if(a()-i<NO)return{ok:!1,source:"debounced"};kc.set(t.id,a());let c=await xc({env:s}),l=c.loops.find(f=>f.trackId===t.id);if(!l)return kc.delete(t.id),{ok:!1,source:c.source==="plane"?"no-loop":c.source};let u=`${e||"provider"} ${r?r+" ":""}${n}: ${String(o||"").replace(/\s+/g," ").trim()}`.slice(0,500),d=await sf({loopId:l.id,outcome:"errored",note:u,env:s});return d.ok||kc.delete(t.id),{...d,loop:{id:l.id,name:l.name}}}async function xc({env:t=process.env}={}){if(!of(t))return{loops:[],source:"unconfigured"};let e=new AbortController,n=setTimeout(()=>e.abort(),dk);try{let r=await fk(`${gt(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)}}var dk,fk,NO,kc,af=C(()=>{qt();dk=1e4,fk=(...t)=>fetch(...t);NO=10*6e4,kc=new Map});import{randomUUID as PO}from"node:crypto";function oa(t){return t.sourceId?`${t.role}|id:${t.sourceId}`:`${t.role}|${t.ts??"?"}|${String(t.text||"").slice(0,40)}`}function mk(t){return t.id?`cmd|${t.box}|id:${t.id}`:`cmd|${t.box}|${t.ts??"?"}|${String(t.command||"").slice(0,40)}`}function hk(t){return`job|${t.box}|id:${t.id}`}async function lf(t){return cf.has(t.id)?cf.get(t.id):(vc.has(t.id)||vc.set(t.id,B(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.type==="provider.error")&&r.payload?.text!=null){let o=r.type==="turn.user"?"user":"assistant";r.payload.sourceId&&n.keys.add(oa({role:o,sourceId:r.payload.sourceId})),n.keys.add(oa({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(oa({role:"user",sourceId:r.payload.sourceId})),n.keys.add(oa({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(mk({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(hk({id:r.payload.id,box:r.boxId}));return cf.set(t.id,n),n}).finally(()=>vc.delete(t.id))),vc.get(t.id))}async function wk(t,e){try{let n=(await lf(t)).keys;for(let r of e||[]){if(!r||r.ts==null||!String(r.text||"").trim()&&!r.images?.length)continue;let o=oa(r);if(n.has(o))continue;n.add(o);let s=r.role==="user"?bc(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 uk(s,sa),boxRole:r.boxRole,sourceId:r.sourceId||void 0}});continue}let a=Tw(r);if(a){await I(t,{type:"provider.error",actor:"system",source:"transcript",boxId:r.box,provider:r.agent||null,payload:{cls:a.cls,code:a.code||void 0,status:a.status||void 0,requestId:a.requestId||void 0,text:r.text,ts:r.ts,model:r.model||null,boxRole:r.boxRole,sourceId:r.sourceId||void 0}}),pk(t,{provider:r.agent||null,cls:a.cls,status:a.status,text:r.text}).catch(()=>{});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 i=kb(r.text);if(i){let{offered:c,toPr:l}=xb(i),u;if(t.workspace?.kind==="multi"){let f=await No(t).catch(()=>[]);u=f.length?f.map(p=>({name:p.name,slug:p.repo??null})):void 0}let d=(t.workspace?.kind==="multi"?null:await Oo(t.cwd).catch(()=>null))||t.workspace.branch;await I(t,{type:"pr.offered",actor:"agent",source:"transcript",boxId:r.box,provider:r.agent||null,payload:{offerId:PO(),ts:r.ts,excerpt:i,branch:d,base:t.workspace.baseRef?.replace(/^origin\//,"")||null,boxRole:r.boxRole,offered:c||void 0,toPr:l||void 0,repos:u}})}}}}catch{}}async function gk(t,e){try{let n=await lf(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=mk(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}}),ak(t,o),ik(t,o))}}catch{}}async function yk(t,e){try{let n=await lf(t),r=[...e||[]].filter(o=>o&&o.id).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=hk(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 cf,vc,bk=C(()=>{st();Ro();ck();Mo();rf();Nr();Ci();af();cf=new Map,vc=new Map});function BO(t){let e=[],n=null;for(let r of String(t||"").split(`
136
+ `)){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 DO(t,e){let n=`${t.id}:${e.name}`;if(!uf.has(n)){let r=await B(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);uf.set(n,o)}return uf.get(n)}async function kk(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 DO(t,e),o=BO(await Zt(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:Nn(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 uf,xk=C(()=>{st();wr();ke();Vs();uf=new Map});import Sc from"node:fs";import ff from"node:path";import jO from"node:os";async function UO({sinceMs:t,cookie:e,fetchImpl:n=fetch}){let r=[];for(let o=1;o<=20;o++){let s=await n(FO,{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:vk})});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<vk)break}return r}function HO(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 Tk(){try{return JSON.parse(Sc.readFileSync(Tc(),"utf8"))}catch{return{sinceMs:0,seen:[]}}}function qO(t){try{Sc.mkdirSync(ff.dirname(Tc()),{recursive:!0});let e=Tc()+".tmp";Sc.writeFileSync(e,JSON.stringify(t)),Sc.renameSync(e,Tc())}catch{}}async function GO({fetchImpl:t,now:e=Date.now()}={}){if(Kn.rows&&e-Kn.at<WO)return Kn.rows;let n=process.env.BOSTRAT_CURSOR_USAGE_COOKIE;if(!n)return null;let r=Tk(),o=Math.max(r.sinceMs-6e4,e-24*36e5);try{let s=await UO({sinceMs:o,cookie:n,fetchImpl:t});Kn={at:e,rows:s.map(HO).filter(Boolean),error:null}}catch(s){Kn={at:e,rows:null,error:String(s?.message||s)}}return Kn.rows}async function VO(t,e){let n=`${t.id}:${e.name}`;if(!df.has(n)){let r=await B(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);df.set(n,o)}return df.get(n)}async function Ak(t,e,{fetchImpl:n}={}){try{if(e?.agent!=="cursor"||!e.cwd||!Sk())return;let r=await GO({fetchImpl:n});if(!r||!r.length)return;let o=await py(e.cwd,e.pinned?e.sessionId:null);if(!o?.chatId)return;let s=await VO(t,e),a=Tk(),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=Nn(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}})}qO({sinceMs:c,seen:[...i].slice(-KO)})}catch{}}var LO,Sk,FO,vk,WO,Kn,Tc,KO,pf,df,mf=C(()=>{st();fd();Vs();LO=process.env.BOSTRAT_STATE_DIR||ff.join(process.env.HOME||jO.tmpdir(),".bostrat"),Sk=(t=process.env)=>!!t.BOSTRAT_CURSOR_USAGE_COOKIE,FO="https://cursor.com/api/dashboard/get-filtered-usage-events",vk=100;WO=5*6e4,Kn={at:0,rows:null,error:null},Tc=()=>ff.join(LO,"cursor-usage.json");KO=5e3;pf=()=>({enabled:Sk(),lastPollAt:Kn.at||null,error:Kn.error}),df=new Map});import ca from"node:fs/promises";import ee from"node:path";import zO from"node:os";import JO from"node:net";import{randomUUID as YO}from"node:crypto";import{execFile as XO}from"node:child_process";import{promisify as ZO}from"node:util";function sC(t){for(let e of xf(t))if(!Ok.test(e))return e;return null}function Ck(t){let e=xf(t),n=e.indexOf("--");return n===-1?e:e.slice(0,n)}function aC(t,e){let n=Ck(e);for(let r=0;r<n.length;r++){let o=/^--prefix=(.+)$/.exec(n[r]);if(o)return ee.resolve(t,o[1]);if(n[r]==="--prefix"&&n[r+1])return ee.resolve(t,n[r+1])}return t}function cC(t){let e=!1,n=!1;for(let r of xf(t)){if(!e){if(Ok.test(r))continue;e=!0;continue}if(r.startsWith("-")){let o=r.indexOf("="),s=o===-1?null:r.slice(o+1);if(s&&hf(s))return`serves the filesystem root ("${s}")`;n=o===-1;continue}if(n){if(n=!1,hf(r))return`serves the filesystem root ("${r}")`;continue}if(hf(r))return`serves the filesystem root ("${r}")`;if(iC(r))return`serves a path that escapes the workspace ("${r}")`}return null}async function uC(t,e){if(ee.resolve(t)===ee.resolve(e))return!0;let[n,r]=await Promise.all([Ac(t),Ac(e)]);return n===r}async function dC(t){let n=(await ca.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 Mk(ee.join(t,o.name,yf))?`./${o.name}`:null))).filter(Boolean)}async function fC(t,e){let[n,r]=await Promise.all([Ac(t),Ac(e)]),o=ee.relative(n,r);if(o&&(o.startsWith("..")||ee.isAbsolute(o)))throw aa(`serve directory escapes the Track workspace: ${e}`)}async function pC(t,e){let n=cC(e);if(n)throw aa(`refusing this view: the command ${n} \u2014 serve a build dir, not the filesystem root`);if(!await lC(t))throw aa(`serve directory does not exist: ${t}`);let r=sC(e);if(!r)return;if(!r.includes("/")&&!await Zh(r,{loginShell:!0,failOpen:!0}))throw aa(`\`${r}\` is not on the box's PATH \u2014 install it in the box first`);if(nC.test(e)||rC.has(r)||!eC.has(r)||!Ck(e).includes("run")||oC.test(e))return;let o=aC(t,e);if(await Mk(ee.join(o,yf)))return;let s=await dC(o),a=s.length?` \u2014 found one in ${s.join(", ")}; run bostrat-view from there`:"";throw aa(`no ${yf} in ${o}${a}`)}async function on(){return Ce||(wf||=(async()=>{try{Ce=JSON.parse(await ca.readFile($k,"utf8"))}catch{Ce={views:[],adoptWatermarks:{}}}finally{wf=null}return Ce.views||=[],Ce.adoptWatermarks||={},Ce})(),wf)}async function Ne(){await Xt($k,Ce)}function rn(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 Sf(t){return ia.get(t)||null}function Pk(t,{name:e,box:n}={}){let r=ia.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 ia.set(t,o),o}function bf(t,e){let n=ia.get(t);n&&!n.finishedAt&&!n.viewId&&(n.viewId=e,n.step="booting")}function Ec(t,{error:e=null}={}){let n=ia.get(t);return!n||n.finishedAt?null:(n.finishedAt=Date.now(),e&&(n.error=e),n)}function Bk(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 kf(t){return String(t||"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40).replace(/-+$/g,"")||"view"}function mC(t,e){let n=kf(e),r=new Set(t.views.map(o=>o.slug));if(!r.has(n)&&!Ik.has(n))return n;for(let o=2;;o++){let s=`${n}-${o}`;if(!r.has(s)&&!Ik.has(s))return s}}function la(t,{timeoutMs:e=1200}={}){return new Promise(n=>{let r=JO.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 Tf(t){if(process.platform!=="darwin"){await Me("fuser",["-k",`${t}/tcp`]).catch(()=>{});return}let e="";try{({stdout:e}=await Me("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 hC(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=Ek;o<=_k;o++)if(!(n.has(o)||r.has(o))&&!await la(o,{timeoutMs:250}))return o;throw new Error(`no free view port in ${Ek}-${_k}`)}async function wC(t){try{let{stdout:e}=await Me(L,H("list-sessions","-F","#{session_name}"));return e.split(`
137
+ `).some(n=>n.trim()===Po(t))}catch{return!1}}async function ua(t){try{await Me(L,H("kill-session","-t",Po(t)))}catch{}}async function Af(t){if(!await $s())throw new Error("host tmux server not running and auto-start failed \u2014 cannot spawn a view server");let e=Po(t.slug),n=t.serveCwd??t.cwd,r=ee.dirname(process.execPath);await Me(L,H("new-session","-d","-s",e,"-c",n)),await Me(L,H("send-keys","-t",e,"-l",`export PORT=${t.port} PATH="${r}:$PATH"`)),await Me(L,H("send-keys","-t",e,"Enter")),await Me(L,H("send-keys","-t",e,"-l",t.cmd)),await Me(L,H("send-keys","-t",e,"Enter"))}async function Rk(t,e=12){try{let{stdout:n}=await Me(L,H("capture-pane","-t",Po(t),"-p"));return String(n||"").trimEnd().split(`
137
138
  `).filter(Boolean).slice(-e).join(`
138
- `)}catch{return""}}async function UO(t){if(t.state==="stopped"||t.state==="error")return!1;let e=t.origin!=="detected",n=e?await LO(t.slug):!0;if(e&&!n){let s=t.state==="starting";return t.state=s?"error":"stopped",s&&(t.error=await ok(t.slug)||"server exited before listening"),Qe.delete(t.id),await tn(t,t.state,t.error?{error:t.error}:{}),!0}if(await Qs(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>FO?(t.state="error",t.error=await ok(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 yc(){if(!of){of=!0;try{let t=await en(),e=!1;for(let n of t.views)await UO(n)&&(e=!0);e&&await Me()}finally{of=!1}}}async function mf({trackId:t}={}){await yc();let e=await en();return(t?e.views.filter(r=>r.trackId===t):e.views).map(r=>({...r}))}async function pk(t){let n=(await en()).views.find(r=>r.id===t);return n?{...n}:null}function hf(t){return Oe&&Oe.views.find(e=>e.slug===t)||null}async function wf({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??"."),d=i==="detected"?null:async()=>{await PO(r,u),await BO(u,n)},f=await en();if(i!=="detected"){let w=cf(e),y=String(n).trim(),k=f.views.find(x=>x.trackId===t&&(x.slug===w||cf(x.name)===w||x.cmd===y&&te.resolve(x.serveCwd??x.cwd)===u));if(k)return HO(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>=Wn)throw new Error(`view cap reached (${Wn} live) \u2014 stop one first`);let p={id:bO().slice(0,8),trackId:t,box:a||null,name:e.trim(),slug:DO(f,e),cmd:n?String(n).trim():null,cwd:r,serveCwd:u,branch:c,port:await jO(f,s),origin:i,state:"starting",error:null,createdAt:Date.now(),lastHealthyAt:null};return i!=="detected"&&await pf(p),f.views.push(p),await Me(),await tn(p,"created",{origin:i}),af(t,p.id),i==="detected"&&await Qs(p.port)&&(p.state="live",p.lastHealthyAt=Date.now(),await Me(),await tn(p,"live")),{...p}}async function HO(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 MO(e.serveCwd??e.cwd,s);if((e.state==="live"||e.state==="starting")&&!i&&!c&&await Qs(e.port))return await Me(),af(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>=Wn)throw new Error(`view cap reached (${Wn} live) \u2014 stop one first`);return e.origin==="detected"?(await ff(e.port),e.origin="agent"):await ta(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 pf(e),await Me(),await tn(e,"created",{restarted:!0,reused:!0}),af(e.trackId,e.id),{...e,reused:!0}}async function mk(t){let n=(await en()).views.find(r=>r.id===t);if(!n)throw new Error("view not found");return n.origin==="detected"?await ff(n.port):await ta(n.slug),n.state!=="stopped"&&(n.state="stopped",Qe.delete(n.id),await Me(),await tn(n,"stopped")),{...n}}async function hk(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 ta(n.slug),n.state="starting",n.error=null,n.createdAt=Date.now(),Qe.delete(n.id),await pf(n),await Me(),await tn(n,"created",{restarted:!0}),{...n}}async function wk(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 ff(r.port):await ta(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 gk(t){let e=await en(),n=e.views.filter(r=>r.trackId===t);for(let r of n)r.origin!=="detected"&&await ta(r.slug),Qe.delete(r.id);return n.length&&(e.views=e.views.filter(r=>r.trackId!==t),await Me()),n.length}async function yk(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(WO)){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(!fk().has(c)&&!n.views.some(l=>l.port===c)&&await Qs(c))try{i.push(await wf({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,SO,sk,ek,nk,Wn,vO,Ro,rk,Ys,TO,sf,AO,EO,_O,lf,ak,nf,$O,CO,ck,wc,Oe,rf,Xs,uf,lk,Qe,FO,of,WO,bc=M(()=>{Kt();ot();kn();Ce=xO(kO),SO=process.env.BOSTRAT_STATE_DIR||te.join(process.env.HOME||gO.tmpdir(),".bostrat"),sk=te.join(SO,"views.json"),[ek,nk]=(process.env.BOSTRAT_VIEW_PORTS||"4300-4349").split("-").map(t=>Number(t)||0),Wn=Number(process.env.BOSTRAT_VIEW_MAX)||3,vO="bostrat-view-",Ro=t=>`${vO}${t}`,rk=new Set(["bostrat","www","api","views","app"]),Ys=t=>Object.assign(new Error(t),{status:400}),TO=new Set(["npm","pnpm","yarn","bun"]),sf="package.json",AO=/[|;&`]|\$\(/,EO=new Set(["sh","bash","zsh","dash","env","exec","nohup","time"]),_O=/(^|\s)(-C|--cwd|--manifest-path|--dir)(=|\s)/,lf=t=>String(t).trim().split(/\s+/).filter(Boolean),ak=/^[A-Za-z_][A-Za-z0-9_]*=/;nf=t=>t==="/",$O=t=>t===".."||t.startsWith("../")||t.includes("/../")||t.endsWith("/..");CO=t=>Zs.stat(t).then(e=>e.isDirectory(),()=>!1),ck=t=>Zs.stat(t).then(e=>e.isFile(),()=>!1),wc=t=>Zs.realpath(t).catch(()=>te.resolve(t));Oe=null,rf=null;Xs=new Map,uf=Number(process.env.BOSTRAT_VIEW_JOB_TIMEOUT)||3e5,lk=12e3;Qe=new Map,FO=12e4;of=!1;WO=/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::(\d{2,5}))?(?:\/|\b)/g});import bk from"node:fs/promises";import kk from"node:path";import qO from"node:os";function xc({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};kc.push(l),kc.length>GO&&kc.shift();let u=gf.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)),gf.set(t,u),VO(l),l}async function VO(t){try{await bk.mkdir(xk,{recursive:!0}),await bk.appendFile(KO,JSON.stringify(t)+`
139
- `)}catch{}}function Sk(){let t={};for(let[e,n]of gf)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:kc.slice(-20)}}var xk,KO,GO,kc,gf,Sc=M(()=>{xk=process.env.BOSTRAT_STATE_DIR||kk.join(process.env.HOME||qO.tmpdir(),".bostrat"),KO=kk.join(xk,"github-latency.ndjson"),GO=100,kc=[],gf=new Map});import{execFile as zO}from"node:child_process";import{promisify as JO}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([Oo("git",["-C",t,"rev-parse","HEAD"]),Oo("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 Oo("gh",e,{cwd:t,...XO,...o,env:{...process.env,...s,...o.env||{}}});return String(a||"")}catch(a){throw Bn(a)&&Dn(a),a}}async function kf(){if(vc&&Date.now()-vc.at<6e4)return vc.data;let t;try{Ye("auth");let e=await Oo("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 ps();e.configured&&(t={installed:!0,authenticated:!0,login:e.username,via:"broker"})}catch{}return vc={at:Date.now(),data:t},t}async function ZO(t){try{let{stdout:e}=await Oo("git",["-C",t,"config","--get","remote.origin.url"],{timeout:5e3});return/github\.com/.test(e)}catch{return!1}}function Tk(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 yf(t){let e=(t||[]).map(Tk),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 Sf(t){return/Resource not accessible by personal access token/.test(String(t?.stderr||t?.message||""))}async function Ek(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 _k(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 Ek(t,e);return n===null?{...yf([]),unavailable:!0}:yf(_k(n))}function Tc(t,e=yf(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 tC(t,e,n){let r=new Set;for(let o of e){let s=`${t}#${o.number}`;if(o.mergeable!=="UNKNOWN"&&o.mergeStateStatus!=="UNKNOWN"){$o.delete(s);continue}r.add(s),$o.has(s)||$o.set(s,n),o.mergeabilityPending=n-$o.get(s)<QO}for(let o of $o.keys())o.startsWith(`${t}#`)&&!r.has(o)&&$o.delete(o);return e}async function Co(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",xf]);return Tc(JSON.parse(o))}catch(o){if(!Sf(o))throw o;let s=await ue(n.path,["pr","view",String(r),"--json",Ak]),a=JSON.parse(s);return Tc(a,await Ik(n.path,a.headRefOid))}}async function $r(t,{caller:e="prs"}={}){try{let n=await ue(t,["pr","list","--json",xf,"--limit","50"],{caller:e});return JSON.parse(n||"[]").map(r=>Tc(r)).sort(vk)}catch(n){if(!Sf(n))throw n;let r=await ue(t,["pr","list","--json",Ak,"--limit","50"],{caller:e});return(await Promise.all(JSON.parse(r||"[]").map(async o=>Tc(o,await Ik(t,o.headRefOid))))).sort(vk)}}function Pe(){ea.clear()}async function rC(t,e){if(!t)return e;for(let n of e){let r=await Gt(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 sc(t,n.number,{headSha:n.headSha}).catch(()=>{}):n.ciFix={delegatedAt:r.ciFix.delegatedAt,trackId:r.ciFix.trackId??null}),r.reconcile&&(o(r.reconcile)?await ic(t,n.number,{headSha:n.headSha}).catch(()=>{}):n.reconcile={delegatedAt:r.reconcile.delegatedAt,trackId:r.reconcile.trackId??null})}return e}async function Rk(){let t=await kf();if(!t.authenticated)return{auth:t,repos:[]};let e=[];for(let a of await We())await ZO(a.path)&&e.push(a);let n=Date.now(),r=rc(n)>0,o=await Promise.all(e.map(async a=>{let i=ea.get(a.path),c=i?.pending?nC:eC;if(i&&(r||n-i.at<c))return i.entry;try{let l=await lt(a.path).catch(()=>null),u=tC(a.path,await $r(a.path,{caller:"tab"}),n);if(await rC(l,u),i?.entry?.prs)for(let h of u)i.entry.prs.find(w=>w.number===h.number)?.checks?.pending>0&&h.checks.total>0&&h.checks.pending===0&&xc({change:h.checks.failed>0?"checks-failed":"checks-green",repo:l||a.name,number:h.number,githubAt:h.checks.settledAt,source:"tab"});let d={name:a.name,path:a.path,prs:u},f=u.some(h=>h.mergeabilityPending||h.checks.pending>0||h.autoMergeArmed);return ea.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:Ne(l)}}})),s=new Set(e.map(a=>a.path));for(let a of ea.keys())s.has(a)||ea.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 Vr(t)}async function Mo(t,e,{method:n="squash"}={}){let r=await nn(t);if(!na.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 jl().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 ra(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 Ab(o,r).catch(()=>{}),{ok:!0,number:r}}async function vf(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 Tf(t){return t.green&&!t.isDraft}function iC(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 $k(t,{update:e=!0}={}){return t.isDraft?{action:"skip",reason:"draft"}:Tf(t)?{action:"merge"}:e&&t.mergeStateStatus==="BEHIND"&&t.mergeable!=="CONFLICTING"&&t.checks.failed===0?{action:"update-arm"}:{action:"arm"}}function Ok(t){return[...t.filter(e=>e.plan.action!=="merge"),...t.filter(e=>e.plan.action==="merge")]}function Ck(){let t={};for(let[e,n]of bf)t[e]={...n};return t}async function Mk(t,{method:e="merge",onMerged:n=null}={}){let r=await nn(t);if(!na.has(e))throw new Error(`invalid merge method: ${e}`);if(bf.get(r.path)?.running)throw new Error("a merge-all is already running for this repo");let o=(await $r(r.path)).filter(Tf).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 bf.set(r.path,s),lC(s,o,{listPrs:()=>$r(r.path),merge:a=>Mo(r.path,a,{method:e}),sleep:aC,onMerged:n}).catch(()=>{}),{ok:!0,repo:r.path,total:s.total,queue:o.map(a=>a.number)}}async function cC(t,e){let n=Date.now()+(e.settleMaxMs??sC),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(oC)}}async function lC(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 cC(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(!Tf(a)){t.skipped.push({number:a.number,title:a.title,reason:iC(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 Af(t,{title:e,body:n="",base:r=null}={}){if(typeof e!="string"||!e.trim())throw new Error("title required");try{await Oo("git",["-C",t,"push","-u","origin","HEAD"],{timeout:12e4,maxBuffer:4*1024*1024})}catch(l){throw new Error(`push failed: ${Ne(l)}`)}await YO(t);let o=n||"";if((await _e({cwd:t})).GH_TOKEN){let l=await jl().catch(()=>null);l&&(o=`${o?`${o}
139
+ `)}catch{return""}}async function yC(t){if(t.state==="stopped"||t.state==="error")return!1;let e=t.origin!=="detected",n=e?await wC(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"),nn.delete(t.id),await rn(t,t.state,t.error?{error:t.error}:{}),!0}if(await la(t.port))return nn.delete(t.id),t.lastHealthyAt=Date.now(),t.state!=="live"?(t.state="live",t.error=null,await rn(t,"live"),!0):!1;if(t.state==="starting")return Date.now()-t.createdAt>gC?(t.state="error",t.error=await Rk(t.slug)||"never started listening",await rn(t,"error",{error:t.error}),!0):!1;let o=(nn.get(t.id)||0)+1;return nn.set(t.id,o),o>=3&&t.state==="live"?(t.state="unhealthy",!0):!1}async function _c(){if(!gf){gf=!0;try{let t=await on(),e=!1;for(let n of t.views)await yC(n)&&(e=!0);e&&await Ne()}finally{gf=!1}}}async function Ef({trackId:t}={}){await _c();let e=await on();return(t?e.views.filter(r=>r.trackId===t):e.views).map(r=>({...r}))}async function jk(t){let n=(await on()).views.find(r=>r.id===t);return n?{...n}:null}function _f(t){return Ce&&Ce.views.find(e=>e.slug===t)||null}async function If({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=ee.resolve(r,o??"."),d=i==="detected"?null:async()=>{await fC(r,u),await pC(u,n)},f=await on();if(i!=="detected"){let w=kf(e),y=String(n).trim(),k=f.views.find(x=>x.trackId===t&&(x.slug===w||kf(x.name)===w||x.cmd===y&&ee.resolve(x.serveCwd??x.cwd)===u));if(k)return bC(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>=Gn)throw new Error(`view cap reached (${Gn} live) \u2014 stop one first`);let h={id:YO().slice(0,8),trackId:t,box:a||null,name:e.trim(),slug:mC(f,e),cmd:n?String(n).trim():null,cwd:r,serveCwd:u,branch:c,port:await hC(f,s),origin:i,state:"starting",error:null,createdAt:Date.now(),lastHealthyAt:null};return i!=="detected"&&await Af(h),f.views.push(h),await Ne(),await rn(h,"created",{origin:i}),bf(t,h.id),i==="detected"&&await la(h.port)&&(h.state="live",h.lastHealthyAt=Date.now(),await Ne(),await rn(h,"live")),{...h}}async function bC(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 uC(e.serveCwd??e.cwd,s);if((e.state==="live"||e.state==="starting")&&!i&&!c&&await la(e.port))return await Ne(),bf(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>=Gn)throw new Error(`view cap reached (${Gn} live) \u2014 stop one first`);return e.origin==="detected"?(await Tf(e.port),e.origin="agent"):await ua(e.slug),e.cmd=n,s!==void 0&&(e.serveCwd=s),e.state="starting",e.error=null,e.createdAt=Date.now(),nn.delete(e.id),await Af(e),await Ne(),await rn(e,"created",{restarted:!0,reused:!0}),bf(e.trackId,e.id),{...e,reused:!0}}async function Lk(t){let n=(await on()).views.find(r=>r.id===t);if(!n)throw new Error("view not found");return n.origin==="detected"?await Tf(n.port):await ua(n.slug),n.state!=="stopped"&&(n.state="stopped",nn.delete(n.id),await Ne(),await rn(n,"stopped")),{...n}}async function Fk(t){let e=await on(),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>=Gn)throw new Error(`view cap reached (${Gn} live) \u2014 stop one first`);return await ua(n.slug),n.state="starting",n.error=null,n.createdAt=Date.now(),nn.delete(n.id),await Af(n),await Ne(),await rn(n,"created",{restarted:!0}),{...n}}async function Uk(t){let e=await on(),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 Tf(r.port):await ua(r.slug),e.views.splice(n,1),nn.delete(r.id),await Ne(),await rn(r,"deleted"),{ok:!0,id:t,slug:r.slug}}async function Hk(t){let e=await on(),n=e.views.filter(r=>r.trackId===t);for(let r of n)r.origin!=="detected"&&await ua(r.slug),nn.delete(r.id);return n.length&&(e.views=e.views.filter(r=>r.trackId!==t),await Ne()),n.length}async function Wk(t,e){if(!t?.id||!Array.isArray(e)||!e.length)return[];let n=await on(),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 Ne()),!o.length)return[];let a=new Set;for(let c of o)for(let l of String(c.text||"").matchAll(kC)){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 la(c))try{i.push(await If({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 Me,QO,$k,Ek,_k,Gn,tC,Po,Ik,aa,eC,yf,nC,rC,oC,xf,Ok,hf,iC,lC,Mk,Ac,Ce,wf,ia,vf,Nk,nn,gC,gf,kC,Ic=C(()=>{Gt();st();Sn();Me=ZO(XO),QO=process.env.BOSTRAT_STATE_DIR||ee.join(process.env.HOME||zO.tmpdir(),".bostrat"),$k=ee.join(QO,"views.json"),[Ek,_k]=(process.env.BOSTRAT_VIEW_PORTS||"4300-4349").split("-").map(t=>Number(t)||0),Gn=Number(process.env.BOSTRAT_VIEW_MAX)||3,tC="bostrat-view-",Po=t=>`${tC}${t}`,Ik=new Set(["bostrat","www","api","views","app"]),aa=t=>Object.assign(new Error(t),{status:400}),eC=new Set(["npm","pnpm","yarn","bun"]),yf="package.json",nC=/[|;&`]|\$\(/,rC=new Set(["sh","bash","zsh","dash","env","exec","nohup","time"]),oC=/(^|\s)(-C|--cwd|--manifest-path|--dir)(=|\s)/,xf=t=>String(t).trim().split(/\s+/).filter(Boolean),Ok=/^[A-Za-z_][A-Za-z0-9_]*=/;hf=t=>t==="/",iC=t=>t===".."||t.startsWith("../")||t.includes("/../")||t.endsWith("/..");lC=t=>ca.stat(t).then(e=>e.isDirectory(),()=>!1),Mk=t=>ca.stat(t).then(e=>e.isFile(),()=>!1),Ac=t=>ca.realpath(t).catch(()=>ee.resolve(t));Ce=null,wf=null;ia=new Map,vf=Number(process.env.BOSTRAT_VIEW_JOB_TIMEOUT)||3e5,Nk=12e3;nn=new Map,gC=12e4;gf=!1;kC=/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::(\d{2,5}))?(?:\/|\b)/g});import qk from"node:fs/promises";import Kk from"node:path";import xC from"node:os";function $c({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};Rc.push(l),Rc.length>SC&&Rc.shift();let u=Rf.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)),Rf.set(t,u),TC(l),l}async function TC(t){try{await qk.mkdir(Gk,{recursive:!0}),await qk.appendFile(vC,JSON.stringify(t)+`
140
+ `)}catch{}}function Vk(){let t={};for(let[e,n]of Rf)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:Rc.slice(-20)}}var Gk,vC,SC,Rc,Rf,Oc=C(()=>{Gk=process.env.BOSTRAT_STATE_DIR||Kk.join(process.env.HOME||xC.tmpdir(),".bostrat"),vC=Kk.join(Gk,"github-latency.ndjson"),SC=100,Rc=[],Rf=new Map});import{execFile as AC}from"node:child_process";import{promisify as EC}from"node:util";async function _C(t){let e=/workspaces[/\\]([0-9a-f]{8})(?:[/\\]|$)/.exec(t||"")?.[1];if(e)try{let[{stdout:n},{stdout:r}]=await Promise.all([Do("git",["-C",t,"rev-parse","HEAD"]),Do("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 fe(t,e,n={}){let{caller:r="prs",...o}=n,s=await Ie({cwd:t});Ze(r);try{let{stdout:a}=await Do("gh",e,{cwd:t,...IC,...o,env:{...process.env,...s,...o.env||{}}});return String(a||"")}catch(a){throw Ln(a)&&Fn(a),a}}async function Cf(){if(Cc&&Date.now()-Cc.at<6e4)return Cc.data;let t;try{Ze("auth");let e=await Do("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 vs();e.configured&&(t={installed:!0,authenticated:!0,login:e.username,via:"broker"})}catch{}return Cc={at:Date.now(),data:t},t}async function RC(t){try{let{stdout:e}=await Do("git",["-C",t,"config","--get","remote.origin.url"],{timeout:5e3});return/github\.com/.test(e)}catch{return!1}}function Jk(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 $f(t){let e=(t||[]).map(Jk),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 Nf(t){return/Resource not accessible by personal access token/.test(String(t?.stderr||t?.message||""))}async function Xk(t,e){if(!e)return null;let n=await ut(t);if(!n)return null;try{let r=await fe(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 Zk(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 Qk(t,e){let n=await Xk(t,e);return n===null?{...$f([]),unavailable:!0}:$f(Zk(n))}function Mc(t,e=$f(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 OC(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)<$C}for(let o of Bo.keys())o.startsWith(`${t}#`)&&!r.has(o)&&Bo.delete(o);return e}async function jo(t,e){let n=await sn(t),r=Number(e);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{let o=await fe(n.path,["pr","view",String(r),"--json",Mf]);return Mc(JSON.parse(o))}catch(o){if(!Nf(o))throw o;let s=await fe(n.path,["pr","view",String(r),"--json",Yk]),a=JSON.parse(s);return Mc(a,await Qk(n.path,a.headRefOid))}}async function Pr(t,{caller:e="prs"}={}){try{let n=await fe(t,["pr","list","--json",Mf,"--limit","50"],{caller:e});return JSON.parse(n||"[]").map(r=>Mc(r)).sort(zk)}catch(n){if(!Nf(n))throw n;let r=await fe(t,["pr","list","--json",Yk,"--limit","50"],{caller:e});return(await Promise.all(JSON.parse(r||"[]").map(async o=>Mc(o,await Qk(t,o.headRefOid))))).sort(zk)}}function Be(){da.clear()}async function NC(t,e){if(!t)return e;for(let n of e){let r=await Vt(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 pc(t,n.number,{headSha:n.headSha}).catch(()=>{}):n.ciFix={delegatedAt:r.ciFix.delegatedAt,trackId:r.ciFix.trackId??null}),r.reconcile&&(o(r.reconcile)?await hc(t,n.number,{headSha:n.headSha}).catch(()=>{}):n.reconcile={delegatedAt:r.reconcile.delegatedAt,trackId:r.reconcile.trackId??null})}return e}async function tx(){let t=await Cf();if(!t.authenticated)return{auth:t,repos:[]};let e=[];for(let a of await qe())await RC(a.path)&&e.push(a);let n=Date.now(),r=dc(n)>0,o=await Promise.all(e.map(async a=>{let i=da.get(a.path),c=i?.pending?MC:CC;if(i&&(r||n-i.at<c))return i.entry;try{let l=await ut(a.path).catch(()=>null),u=OC(a.path,await Pr(a.path,{caller:"tab"}),n);if(await NC(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&&$c({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 da.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:Pe(l)}}})),s=new Set(e.map(a=>a.path));for(let a of da.keys())s.has(a)||da.delete(a);return{auth:t,repos:o}}async function sn(t){let e=(await qe()).find(n=>n.path===t);if(!e)throw new Error(`unknown repo: ${t}`);return e}async function Br(t){return Zr(t)}async function Lo(t,e,{method:n="squash"}={}){let r=await sn(t);if(!fa.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 Ie({cwd:r.path})).GH_TOKEN){let a=await zl().catch(()=>null);a&&s.push("--body",`Merged by bostrat on behalf of @${a}`)}try{await fe(r.path,s)}catch(a){throw new Error(Pe(a))}finally{Be()}return{ok:!0,number:o}}async function pa(t,e){let n=await sn(t),r=Number(e);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await fe(n.path,["api","-X","PUT",`repos/{owner}/{repo}/pulls/${r}/update-branch`])}catch(s){throw new Error(Pe(s))}finally{Be()}let o=await ut(n.path).catch(()=>null);return o&&await Fb(o,r).catch(()=>{}),{ok:!0,number:r}}async function Pf(t,e){let n=await sn(t),r=Number(e);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await fe(n.path,["pr","merge",String(r),"--disable-auto"])}catch(o){throw new Error(Pe(o))}finally{Be()}return{ok:!0,number:r}}function Bf(t){return t.green&&!t.isDraft}function jC(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 ex(t,{update:e=!0}={}){return t.isDraft?{action:"skip",reason:"draft"}:Bf(t)?{action:"merge"}:e&&t.mergeStateStatus==="BEHIND"&&t.mergeable!=="CONFLICTING"&&t.checks.failed===0?{action:"update-arm"}:{action:"arm"}}function nx(t){return[...t.filter(e=>e.plan.action!=="merge"),...t.filter(e=>e.plan.action==="merge")]}function rx(){let t={};for(let[e,n]of Of)t[e]={...n};return t}async function ox(t,{method:e="merge",onMerged:n=null}={}){let r=await sn(t);if(!fa.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 Pr(r.path)).filter(Bf).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),FC(s,o,{listPrs:()=>Pr(r.path),merge:a=>Lo(r.path,a,{method:e}),sleep:DC,onMerged:n}).catch(()=>{}),{ok:!0,repo:r.path,total:s.total,queue:o.map(a=>a.number)}}async function LC(t,e){let n=Date.now()+(e.settleMaxMs??BC),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(PC)}}async function FC(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 LC(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: ${Pe(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(!Bf(a)){t.skipped.push({number:a.number,title:a.title,reason:jC(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:Pe(i)})}}}finally{t.current=null,t.running=!1,t.finishedAt=Date.now(),Be()}}async function Df(t,{title:e,body:n="",base:r=null}={}){if(typeof e!="string"||!e.trim())throw new Error("title required");try{await Do("git",["-C",t,"push","-u","origin","HEAD"],{timeout:12e4,maxBuffer:4*1024*1024})}catch(l){throw new Error(`push failed: ${Pe(l)}`)}await _C(t);let o=n||"";if((await Ie({cwd:t})).GH_TOKEN){let l=await zl().catch(()=>null);l&&(o=`${o?`${o}
140
141
 
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 Nk(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(!Sf(i))throw i;let c=await ue(n.path,["pr","view",String(r),"--json","headRefOid"]),l=await Ek(n.path,JSON.parse(c).headRefOid);if(l===null)throw new Error(Ne(i));o=_k(l).map(Tk).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=uC(i.link),l=null;c&&!s.has(c)&&(s.add(c),l=await ue(n.path,["run","view",c,"--log-failed"]).then(u=>dC(u)).catch(()=>null)),a.push({name:i.name,link:i.link||null,log:l})}return a}function uC(t){return String(t||"").match(/\/actions\/runs\/(\d+)/)?.[1]??null}function dC(t,{maxLines:e=400,maxBytes:n=64*1024}={}){let r=String(t||""),o=r.split(`
142
+ `:""}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 fe(t,s)}catch(l){throw new Error(Pe(l))}finally{Be()}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 sx(t,e){let n=await sn(t),r=Number(e);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");let o;try{let i;try{i=await fe(n.path,["pr","checks",String(r),"--json","name,state,link,bucket"])}catch(c){if(i=String(c?.stdout||""),!i.trim())throw new Error(Pe(c))}o=JSON.parse(i||"[]").filter(c=>c.bucket==="fail")}catch(i){if(!Nf(i))throw i;let c=await fe(n.path,["pr","view",String(r),"--json","headRefOid"]),l=await Xk(n.path,JSON.parse(c).headRefOid);if(l===null)throw new Error(Pe(i));o=Zk(l).map(Jk).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=UC(i.link),l=null;c&&!s.has(c)&&(s.add(c),l=await fe(n.path,["run","view",c,"--log-failed"]).then(u=>HC(u)).catch(()=>null)),a.push({name:i.name,link:i.link||null,log:l})}return a}function UC(t){return String(t||"").match(/\/actions\/runs\/(\d+)/)?.[1]??null}function HC(t,{maxLines:e=400,maxBytes:n=64*1024}={}){let r=String(t||""),o=r.split(`
142
143
  `);return o.length>e&&(r=`\u2026 (${o.length-e} earlier lines truncated)
143
144
  `+o.slice(-e).join(`
144
145
  `)),Buffer.byteLength(r)>n&&(r=`\u2026 (truncated)
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 Oo,XO,vc,xf,Ak,QO,$o,vk,eC,nC,ea,na,oC,sC,aC,bf,oa=M(()=>{ar();Wt();Fn();Hs();Sc();ot();Oo=JO(zO),XO={timeout:3e4,maxBuffer:8*1024*1024};vc=null;xf="number,title,url,headRefName,headRefOid,baseRefName,isDraft,author,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup,autoMergeRequest,additions,deletions,createdAt,updatedAt",Ak=xf.replace("statusCheckRollup,","");QO=9e4,$o=new Map;vk=(t,e)=>t.number-e.number;eC=3e4,nC=1500,ea=new Map;na=new Set(["squash","merge","rebase"]);oC=2500,sC=9e4,aC=t=>new Promise(e=>setTimeout(e,t));bf=new Map});function Ac(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>pC?null:n}function mC(t,e){return t?.firstSeen==null||e?.ts==null||t.firstSeen<e.ts}async function Pk(t){let e=t?.workspace?.branch;if(!e)return;let n;try{n=await F(t)}catch{return}let r=Ac(n);if(r==null)return;let o=(t.boxes||[]).find(l=>l.name===t.leadBox);if(await uc(t.leadBox,o?.agent).catch(()=>!1))return;let s=Date.now();if(s-(Ef.get(t.id)||0)<fC)return;Ef.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 Ws(c,i.number))){if(!mC(l,r))return;let d=await F(t).catch(()=>null);if(d&&Ac(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(()=>{}),Ef.delete(t.id)}var fC,Ef,pC,_f=M(()=>{ot();oa();ar();Fn();dc();fC=6e3,Ef=new Map,pC=30*6e4});import If from"node:os";import{execFile as hC}from"node:child_process";import{promisify as wC}from"node:util";async function Ec(){if(process.platform!=="darwin")return If.freemem();try{let{stdout:t}=await gC("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:If.freemem()}catch{return If.freemem()}}var gC,Rf=M(()=>{gC=wC(hC)});import $t from"node:fs/promises";import Ct from"node:path";import jk from"node:os";import{randomUUID as yC}from"node:crypto";import{execFile as bC}from"node:child_process";import{promisify as kC}from"node:util";import{chromium as xC}from"playwright-core";async function je(){return Cr||($f||=(async()=>{try{Cr=JSON.parse(await $t.readFile(Fk,"utf8"))}catch{Cr={mocks:[]}}finally{$f=null}return Cr.mocks||=[],Cr})(),$f)}async function de(){await Yt(Fk,Cr)}function Wk(t,e){De(t,e.v,e.videoRel?.endsWith(".webm")?"webm":"mp4"),e.posterRel&&De(t,e.v,"png")}function Vt(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=aa(t.cwd);return{html:Ct.join(n,`${t.id}.v${e}.html`),png:Ct.join(n,`${t.id}.v${e}.png`)}}function sa(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 Mf(t){return t.length<24||t.readUInt32BE(12)!==1229472850?null:{width:t.readUInt32BE(16),height:t.readUInt32BE(20)}}function _c(t){return Buffer.isBuffer(t)&&t.length>24&&t.subarray(0,8).equals($C)}function OC(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 CC(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 MC({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((p,w)=>{r.onload=p,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,h=-1;for(let p=0;p<s;p++)for(let w=p*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),p<d&&(d=p),h=p);return f<0?null:{imgW:o,imgH:s,bg:l,bbox:{left:u,top:d,right:f,bottom:h}}},e.toString("base64"))}async function PC(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 BC({htmlPath:t,outPath:e,width:n}){let r=Date.now(),o;try{o=await xC.launch({executablePath:vC,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:No})).newPage();a.setDefaultTimeout(Po),await a.goto(`file://${t}`,{waitUntil:"load",timeout:Po}),await a.waitForTimeout(250);let i;for(let l=1;;l++)try{i=await a.screenshot({fullPage:!0,timeout:Po});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&&MC({...l,pad:EC*No,align:No});u&&(i=await PC(a,i,{bg:l.bg,crop:u}))}catch{}if(i.length<Uk)throw new Se(`capture produced a ${i.length}-byte image`);let c=Mf(i);if(!c)throw new Se("output is not a PNG");return await $t.writeFile(e,i),{width:Math.round(c.width/No),height:Math.round(c.height/No),dpr:No,renderMs:Date.now()-r}}catch(s){throw s instanceof Se?s:new Se(/timeout/i.test(s?.message||"")?`render timed out after ${Po}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(jk.tmpdir(),"bostrat-mock-profile-")),o=Date.now(),s="";try{try{s=(await Cf(TC,["--headless","--no-remote","--profile",r,`--window-size=${n}`,"--screenshot",e,`file://${t}`],{env:{...process.env,MOZ_HEADLESS:"1"},timeout:Po,killSignal:"SIGKILL",maxBuffer:4194304})).stderr||""}catch(c){throw s=c?.stderr||"",new Se(c?.killed?`render timed out after ${Po}ms`:"firefox exited non-zero",s)}let a=await $t.stat(e).catch(()=>null);if(!a||a.size<Uk)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=Mf(await CC(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 DC(t){if(SC==="firefox")return Dk(t);try{return await BC(t)}catch(e){if(/failed to launch/i.test(e?.message||""))return Dk(t);throw e}}function qk(t){return Of=Of.then(t,t),Of}async function Kk(t,e){let n=await je(),r=n.mocks.find(o=>o.id===t);if(r){r.state="rendering",await de(),await Vt(r,"rendering",{version:e});try{let o=await Ec();if(o<_C)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 jC({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}Nf(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 Vt(r,"ready",{version:e,width:a.width,height:a.height,dpr:a.dpr}),Be(r),De(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 Vt(r,"error",{version:e,error:r.error}),Be(r)}}}function Nf(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 LC({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?AC:Number(r);if(!Number.isInteger(o)||o<320||o>4e3)throw new Error("invalid width (320-4000)");return o}async function ia({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 Gk({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&&!_c(e))throw new Error("image must be a PNG");if(n){let o=OC(n);if(!o)throw new Error("video must be an mp4 or webm (magic-byte check failed)");if(n.length>Bk)throw new Error(`video must be ${Bk/(1024*1024)} MB or smaller (got ${Math.round(n.length/(1024*1024))} MB)`);return o}return null}async function Vk({trackId:t,name:e,html:n,image:r,video:o,cwd:s,width:a,group:i,box:c,agent:l,prompt:u}){let d=LC({trackId:t,name:e,cwd:s,width:a}),f=typeof n=="string"&&n.trim(),h=Gk({html:n,image:r,video:o}),p=await je(),w={id:yC().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(aa(s),{recursive:!0}),p.mocks.push(w),f?(await $t.writeFile(fe(w,1).html,n),await de(),await Vt(w,"created"),Be(w),De(w,1,"html"),qk(()=>Kk(w.id,1))):o?(await Jk(w,1,o,h),await de(),await Vt(w,"created"),await Vt(w,"ready",{version:1,width:w.width,height:w.height,dpr:w.dpr,durationS:w.versions[0]?.durationS??null}),Be(w),Wk(w,w.versions[0])):(await Yk(w,1,r),await de(),await Vt(w,"created"),await Vt(w,"ready",{version:1,width:w.width,height:w.height,dpr:w.dpr}),Be(w),De(w,1,"png")),{...w}}async function zk(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=Gk({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(aa(a.cwd),{recursive:!0}),i?(a.state="queued",await $t.writeFile(fe(a,l).html,e),await de(),await Vt(a,"updated",{version:l}),Be(a),De(a,l,"html"),qk(()=>Kk(a.id,l))):r?(await Jk(a,l,r,c),await de(),await Vt(a,"updated",{version:l}),await Vt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr,durationS:ve(a)?.durationS??null}),Be(a),Wk(a,a.versions.find(u=>u.v===l))):(await Yk(a,l,n),await de(),await Vt(a,"updated",{version:l}),await Vt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr}),Be(a),De(a,l,"png")),{...a}}async function FC(t){try{let{stdout:e}=await Cf(IC,["-v","error","-print_format","json","-show_format","-show_streams",t],{timeout:Hk,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 UC(t,e){try{await Cf(RC,["-y","-v","error","-i",t,"-frames:v","1","-f","image2",e],{timeout:Hk,killSignal:"SIGKILL",maxBuffer:4*1024*1024});let n=await $t.stat(e).catch(()=>null);return!!n&&n.size>0}catch{return!1}}async function Jk(t,e,n,r){let o=aa(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 FC(s),c=await UC(s,a);Nf(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 Yk(t,e,n){let r=Mf(n);if(!r)throw new Error("image must be a PNG");let o=fe(t,e);await $t.writeFile(o.png,n),Nf(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 Xk(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 Vt(n,"picked",{version:n.readyVersion,siblings:r}),{mock:{...n},siblings:r}}async function Zk(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 Vt(r,"deleted"),we("mocks",r.id).catch(()=>{}),{ok:!0,id:t,name:r.name}}async function Qk(t){let n=(await je()).mocks.filter(i=>i.trackId===t.id);if(!n.length)return 0;let r=Ct.join(Lk,"mock-archive",t.id),o=aa(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(),Be(i)}return await de(),n.length}async function t0(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 e0(){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 Be(r);for(let o of r.versions||[])o.htmlRel&&await De(r,o.v,"html"),(o.pngRel||o.posterRel)&&await De(r,o.v,"png"),o.videoRel&&await De(r,o.v,o.videoRel.endsWith(".webm")?"webm":"mp4")}return{pushed:n.mocks.length,source:"plane"}}var Cf,Lk,Fk,SC,vC,TC,AC,No,EC,Uk,Po,_C,Bk,IC,RC,Hk,Se,Cr,$f,Be,De,aa,$C,jC,Of,Bo=M(()=>{ot();kn();Rf();Sn();Cf=kC(bC),Lk=process.env.BOSTRAT_STATE_DIR||Ct.join(process.env.HOME||jk.tmpdir(),".bostrat"),Fk=Ct.join(Lk,"mocks.json"),SC=process.env.BOSTRAT_MOCK_ENGINE||"chromium",vC=process.env.BOSTRAT_CHROMIUM_BIN||"/usr/bin/chromium",TC=process.env.BOSTRAT_FIREFOX_BIN||"firefox",AC=1300,No=2,EC=32,Uk=1500,Po=Number(process.env.BOSTRAT_MOCK_TIMEOUT_MS)||75e3,_C=700*1024*1024,Bk=100*1024*1024,IC=process.env.BOSTRAT_FFPROBE_BIN||"ffprobe",RC=process.env.BOSTRAT_FFMPEG_BIN||"ffmpeg",Hk=2e4,Se=class extends Error{constructor(e,n=""){super(n?`${e}
146
+ `+r.slice(-n)),r}function Pe(t){return String(t?.stderr||t?.message||t||"").trim().split(`
147
+ `).find(n=>n.trim())||"gh failed"}var Do,IC,Cc,Mf,Yk,$C,Bo,zk,CC,MC,da,fa,PC,BC,DC,Of,ma=C(()=>{cr();qt();Wn();Zs();Oc();st();Do=EC(AC),IC={timeout:3e4,maxBuffer:8*1024*1024};Cc=null;Mf="number,title,url,headRefName,headRefOid,baseRefName,isDraft,author,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup,autoMergeRequest,additions,deletions,createdAt,updatedAt",Yk=Mf.replace("statusCheckRollup,","");$C=9e4,Bo=new Map;zk=(t,e)=>t.number-e.number;CC=3e4,MC=1500,da=new Map;fa=new Set(["squash","merge","rebase"]);PC=2500,BC=9e4,DC=t=>new Promise(e=>setTimeout(e,t));Of=new Map});function Nc(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>qC?null:n}function KC(t,e){return t?.firstSeen==null||e?.ts==null||t.firstSeen<e.ts}async function ax(t){let e=t?.workspace?.branch;if(!e)return;let n;try{n=await B(t)}catch{return}let r=Nc(n);if(r==null)return;let o=(t.boxes||[]).find(u=>u.name===t.leadBox);if(await Mr(t.leadBox,o?.agent).catch(()=>!1))return;let s=Date.now();if(s-(jf.get(t.id)||0)<WC)return;jf.set(t.id,s);let a;try{a=await Pr(t.cwd,{caller:"reconcile"})}catch{return}let i=await Co(t).catch(()=>[e]),c=(a||[]).find(u=>i.includes(u.headRefName));if(!c)return;let l=await ut(t.cwd).catch(()=>null);if(l){let{link:u,created:d}=await se({repo:l,number:c.number,trackId:t.id,url:c.url,headRef:c.headRefName||e,title:c.title,source:"reconciled"});if(!d&&!(u?.trackId===t.id&&await Qe(l,c.number))){if(!KC(u,r))return;let f=await B(t).catch(()=>null);if(f&&Nc(f)==null)return;await I(t,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:t.leadBox,payload:{ts:Date.now(),change:"pushed",number:c.number,url:c.url,title:c.title,branch:e,repo:l}});return}}await I(t,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:t.leadBox,payload:{ts:Date.now(),change:"opened",number:c.number,url:c.url,title:c.title,branch:e,...l?{repo:l}:{}}}).catch(()=>{}),jf.delete(t.id)}var WC,jf,qC,Lf=C(()=>{st();ma();cr();Wn();ra();Mo();WC=6e3,jf=new Map,qC=30*6e4});import Ff from"node:os";import{execFile as GC}from"node:child_process";import{promisify as VC}from"node:util";async function Pc(){if(process.platform!=="darwin")return Ff.freemem();try{let{stdout:t}=await zC("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:Ff.freemem()}catch{return Ff.freemem()}}var zC,Uf=C(()=>{zC=VC(GC)});import Rt from"node:fs/promises";import Ot from"node:path";import lx from"node:os";import{randomUUID as JC}from"node:crypto";import{execFile as YC}from"node:child_process";import{promisify as XC}from"node:util";import{chromium as ZC}from"playwright-core";async function Le(){return Dr||(Hf||=(async()=>{try{Dr=JSON.parse(await Rt.readFile(dx,"utf8"))}catch{Dr={mocks:[]}}finally{Hf=null}return Dr.mocks||=[],Dr})(),Hf)}async function pe(){await Xt(dx,Dr)}function mx(t,e){je(t,e.v,e.videoRel?.endsWith(".webm")?"webm":"mp4"),e.posterRel&&je(t,e.v,"png")}function zt(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 me(t,e){let n=wa(t.cwd);return{html:Ot.join(n,`${t.id}.v${e}.html`),png:Ot.join(n,`${t.id}.v${e}.png`)}}function ha(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?Ot.join(t.cwd,r):null}function Te(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 Kf(t){return t.length<24||t.readUInt32BE(12)!==1229472850?null:{width:t.readUInt32BE(16),height:t.readUInt32BE(20)}}function Bc(t){return Buffer.isBuffer(t)&&t.length>24&&t.subarray(0,8).equals(iM)}function cM(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 lM(t){let e=Buffer.alloc(24),n=await Rt.open(t,"r");try{await n.read(e,0,24,0)}finally{await n.close()}return e}function uM({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 dM(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,d=s,f=-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>f&&(f=y),h<d&&(d=h),p=h);return f<0?null:{imgW:o,imgH:s,bg:l,bbox:{left:u,top:d,right:f,bottom:p}}},e.toString("base64"))}async function fM(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 pM({htmlPath:t,outPath:e,width:n}){let r=Date.now(),o;try{o=await ZC.launch({executablePath:tM,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:Fo})).newPage();a.setDefaultTimeout(Uo),await a.goto(`file://${t}`,{waitUntil:"load",timeout:Uo}),await a.waitForTimeout(250);let i;for(let l=1;;l++)try{i=await a.screenshot({fullPage:!0,timeout:Uo});break}catch(u){if(l>=3||!/captureScreenshot|Unable to capture/i.test(u?.message||""))throw u;await a.waitForTimeout(500)}try{let l=await dM(a,i),u=l&&uM({...l,pad:rM*Fo,align:Fo});u&&(i=await fM(a,i,{bg:l.bg,crop:u}))}catch{}if(i.length<fx)throw new Se(`capture produced a ${i.length}-byte image`);let c=Kf(i);if(!c)throw new Se("output is not a PNG");return await Rt.writeFile(e,i),{width:Math.round(c.width/Fo),height:Math.round(c.height/Fo),dpr:Fo,renderMs:Date.now()-r}}catch(s){throw s instanceof Se?s:new Se(/timeout/i.test(s?.message||"")?`render timed out after ${Uo}ms`:"chromium render failed",s?.message||"")}finally{await o.close().catch(()=>{})}}async function cx({htmlPath:t,outPath:e,width:n}){let r=await Rt.mkdtemp(Ot.join(lx.tmpdir(),"bostrat-mock-profile-")),o=Date.now(),s="";try{try{s=(await qf(eM,["--headless","--no-remote","--profile",r,`--window-size=${n}`,"--screenshot",e,`file://${t}`],{env:{...process.env,MOZ_HEADLESS:"1"},timeout:Uo,killSignal:"SIGKILL",maxBuffer:4194304})).stderr||""}catch(c){throw s=c?.stderr||"",new Se(c?.killed?`render timed out after ${Uo}ms`:"firefox exited non-zero",s)}let a=await Rt.stat(e).catch(()=>null);if(!a||a.size<fx)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=Kf(await lM(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 Rt.rm(r,{recursive:!0,force:!0}).catch(()=>{})}}async function mM(t){if(QC==="firefox")return cx(t);try{return await pM(t)}catch(e){if(/failed to launch/i.test(e?.message||""))return cx(t);throw e}}function hx(t){return Wf=Wf.then(t,t),Wf}async function wx(t,e){let n=await Le(),r=n.mocks.find(o=>o.id===t);if(r){r.state="rendering",await pe(),await zt(r,"rendering",{version:e});try{let o=await Pc();if(o<oM)throw new Se(`box is low on memory (${Math.round(o/1e6)} MB available) \u2014 not spawning a browser`);let s=me(r,e),a=await hM({htmlPath:s.html,outPath:s.png,width:r.width});if(!n.mocks.some(i=>i.id===t)){await Rt.rm(s.png,{force:!0}).catch(()=>{});return}Gf(r,{v:e,source:"html",htmlRel:Ot.relative(r.cwd,s.html),pngRel:Ot.relative(r.cwd,s.png),width:a.width,height:a.height,dpr:a.dpr,renderMs:a.renderMs,createdAt:Date.now()}),await pe(),await zt(r,"ready",{version:e,width:a.width,height:a.height,dpr:a.dpr}),De(r),je(r,e,"png")}catch(o){if(!n.mocks.some(s=>s.id===t))return;r.state="error",r.error=o?.message||String(o),await pe(),await zt(r,"error",{version:e,error:r.error}),De(r)}}}function Gf(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 wM({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?nM:Number(r);if(!Number.isInteger(o)||o<320||o>4e3)throw new Error("invalid width (320-4000)");return o}async function ga({trackId:t,group:e}={}){let n=await Le(),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 an(t){let n=(await Le()).mocks.find(r=>r.id===t);return n?{...n}:null}function gx({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&&!Bc(e))throw new Error("image must be a PNG");if(n){let o=cM(n);if(!o)throw new Error("video must be an mp4 or webm (magic-byte check failed)");if(n.length>ix)throw new Error(`video must be ${ix/(1024*1024)} MB or smaller (got ${Math.round(n.length/(1024*1024))} MB)`);return o}return null}async function yx({trackId:t,name:e,html:n,image:r,video:o,cwd:s,width:a,group:i,box:c,agent:l,prompt:u}){let d=wM({trackId:t,name:e,cwd:s,width:a}),f=typeof n=="string"&&n.trim(),p=gx({html:n,image:r,video:o}),h=await Le(),w={id:JC().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 Rt.mkdir(wa(s),{recursive:!0}),h.mocks.push(w),f?(await Rt.writeFile(me(w,1).html,n),await pe(),await zt(w,"created"),De(w),je(w,1,"html"),hx(()=>wx(w.id,1))):o?(await kx(w,1,o,p),await pe(),await zt(w,"created"),await zt(w,"ready",{version:1,width:w.width,height:w.height,dpr:w.dpr,durationS:w.versions[0]?.durationS??null}),De(w),mx(w,w.versions[0])):(await xx(w,1,r),await pe(),await zt(w,"created"),await zt(w,"ready",{version:1,width:w.width,height:w.height,dpr:w.dpr}),De(w),je(w,1,"png")),{...w}}async function bx(t,{html:e,image:n,video:r,width:o}={}){let a=(await Le()).mocks.find(u=>u.id===t);if(!a)throw new Error("mock not found");let i=typeof e=="string"&&e.trim(),c=gx({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 Rt.mkdir(wa(a.cwd),{recursive:!0}),i?(a.state="queued",await Rt.writeFile(me(a,l).html,e),await pe(),await zt(a,"updated",{version:l}),De(a),je(a,l,"html"),hx(()=>wx(a.id,l))):r?(await kx(a,l,r,c),await pe(),await zt(a,"updated",{version:l}),await zt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr,durationS:Te(a)?.durationS??null}),De(a),mx(a,a.versions.find(u=>u.v===l))):(await xx(a,l,n),await pe(),await zt(a,"updated",{version:l}),await zt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr}),De(a),je(a,l,"png")),{...a}}async function gM(t){try{let{stdout:e}=await qf(sM,["-v","error","-print_format","json","-show_format","-show_streams",t],{timeout:px,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 yM(t,e){try{await qf(aM,["-y","-v","error","-i",t,"-frames:v","1","-f","image2",e],{timeout:px,killSignal:"SIGKILL",maxBuffer:4*1024*1024});let n=await Rt.stat(e).catch(()=>null);return!!n&&n.size>0}catch{return!1}}async function kx(t,e,n,r){let o=wa(t.cwd),s=Ot.join(o,`${t.id}.v${e}.${r.ext}`),a=Ot.join(o,`${t.id}.v${e}.poster.png`);await Rt.writeFile(s,n);let i=await gM(s),c=await yM(s,a);Gf(t,{v:e,source:"video",htmlRel:null,pngRel:null,videoRel:Ot.relative(t.cwd,s),posterRel:c?Ot.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 xx(t,e,n){let r=Kf(n);if(!r)throw new Error("image must be a PNG");let o=me(t,e);await Rt.writeFile(o.png,n),Gf(t,{v:e,source:"image",htmlRel:null,pngRel:Ot.relative(t.cwd,o.png),width:r.width,height:r.height,dpr:1,renderMs:null,createdAt:Date.now()}),t.width=r.width}async function vx(t){let e=await Le(),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 zt(n,"picked",{version:n.readyVersion,siblings:r}),{mock:{...n},siblings:r}}async function Sx(t){let e=await Le(),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=me(r,o);await Rt.rm(s.html,{force:!0}).catch(()=>{}),await Rt.rm(s.png,{force:!0}).catch(()=>{})}for(let o of r.versions||[])for(let s of[o.videoRel,o.posterRel])s&&await Rt.rm(Ot.join(r.cwd,s),{force:!0}).catch(()=>{});return await pe(),await zt(r,"deleted"),ye("mocks",r.id).catch(()=>{}),{ok:!0,id:t,name:r.name}}async function Tx(t){let n=(await Le()).mocks.filter(i=>i.trackId===t.id);if(!n.length)return 0;let r=Ot.join(ux,"mock-archive",t.id),o=wa(t.cwd),s=Ot.join(r,".bostrat","mocks");await Rt.mkdir(s,{recursive:!0});let a=await Rt.readdir(o).catch(()=>[]);for(let i of a)await Rt.copyFile(Ot.join(o,i),Ot.join(s,i));for(let i of n){for(let c of i.versions||[])for(let l of[c.htmlRel,c.pngRel,c.videoRel,c.posterRel]){if(!l)continue;if(!(await Rt.stat(Ot.join(r,l)).catch(()=>null))?.isFile())throw new Error(`mock evacuation incomplete: ${l} missing from the archive`)}i.cwd=r,i.trackDeletedAt=Date.now(),i.trackName=t.name||t.id,i.updatedAt=Date.now(),De(i)}return await pe(),n.length}async function Ax(t){let e=await Le(),n=e.mocks.filter(r=>r.trackId===t);if(n.length){e.mocks=e.mocks.filter(r=>r.trackId!==t),await pe();for(let r of n)ye("mocks",r.id).catch(()=>{})}return n.length}async function Ex(){if(!kt())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 Le();for(let r of n.mocks){await De(r);for(let o of r.versions||[])o.htmlRel&&await je(r,o.v,"html"),(o.pngRel||o.posterRel)&&await je(r,o.v,"png"),o.videoRel&&await je(r,o.v,o.videoRel.endsWith(".webm")?"webm":"mp4")}return{pushed:n.mocks.length,source:"plane"}}var qf,ux,dx,QC,tM,eM,nM,Fo,rM,fx,Uo,oM,ix,sM,aM,px,Se,Dr,Hf,De,je,wa,iM,hM,Wf,Ho=C(()=>{st();Sn();Uf();An();qf=XC(YC),ux=process.env.BOSTRAT_STATE_DIR||Ot.join(process.env.HOME||lx.tmpdir(),".bostrat"),dx=Ot.join(ux,"mocks.json"),QC=process.env.BOSTRAT_MOCK_ENGINE||"chromium",tM=process.env.BOSTRAT_CHROMIUM_BIN||"/usr/bin/chromium",eM=process.env.BOSTRAT_FIREFOX_BIN||"firefox",nM=1300,Fo=2,rM=32,fx=1500,Uo=Number(process.env.BOSTRAT_MOCK_TIMEOUT_MS)||75e3,oM=700*1024*1024,ix=100*1024*1024,sM=process.env.BOSTRAT_FFPROBE_BIN||"ffprobe",aM=process.env.BOSTRAT_FFMPEG_BIN||"ffmpeg",px=2e4,Se=class extends Error{constructor(e,n=""){super(n?`${e}
147
148
  ${n.trim().split(`
148
149
  `).slice(-6).join(`
149
- `)}`:e),this.name="MockRenderError"}},Cr=null,$f=null;Be=t=>qt("mocks",{...t},{trackId:t.trackId}).catch(()=>{}),De=(t,e,n)=>{let r=(t.versions||[]).find(s=>s.v===e),o=n==="mp4"||n==="webm"?sa(t,r,"video"):r&&sa(t,r,n)||(n==="html"?fe(t,e).html:null);return o?xn("mocks",t.id,e,n,o).catch(()=>{}):Promise.resolve()};aa=t=>Ct.join(t,".bostrat","mocks");$C=Buffer.from([137,80,78,71,13,10,26,10]);jC=DC,Of=Promise.resolve()});import HC from"node:fs/promises";import a0 from"node:path";import WC from"node:os";import{randomUUID as i0}from"node:crypto";async function sn(){return on||(Pf||=(async()=>{let t=!0;try{on=JSON.parse(await HC.readFile(c0,"utf8"))}catch{on={flows:[]},t=!1}finally{Pf=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})(),Pf)}async function Do(){await Yt(c0,on)}function Bf(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 l0({trackId:t,steps:e,prevSteps:n=[]}){if(!Array.isArray(e)||e.length<1||e.length>n0)throw new Error(`steps must be an array of 1-${n0}`);let r=await ia({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>o0)throw new Error(`${l}: caption over ${o0} chars`);let d=c.title==null?null:String(c.title).trim()||null;if(d&&d.length>s0)throw new Error(`${l}: title over ${s0} chars`);let f=String(c.mock??"").trim().replace(/^mock:/,"");if(!f)throw new Error(`${l}: mock (name or id) required`);let h=r.filter(x=>x.id===f);if(h.length||(h=r.filter(x=>x.name.toLowerCase()===f.toLowerCase())),!h.length)throw new Error(`${l}: no mock matching "${f}" in this Track \u2014 see \`bostrat-mock ls\``);if(h.length>1)throw new Error(`${l}: "${f}" is ambiguous (${h.map(x=>`mock:${x.id}`).join(", ")}) \u2014 use the id`);let p=h[0],w=null;if(c.v!=null&&(w=Number(c.v),!Number.isInteger(w)||!(p.versions||[]).some(x=>x.v===w)))throw new Error(`${l}: "${p.name}" has no captured v${c.v} to pin`);let y=o.findIndex(x=>x.mockId===p.id),k=y>=0?o.splice(y,1)[0].id:i0().slice(0,8);s.push({id:k,mockId:p.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 KC(t){if(typeof t!="string"||!t.trim())throw new Error("name (string) required");if(t.trim().length>r0)throw new Error(`name over ${r0} chars`);return t.trim()}async function u0({trackId:t}={}){let e=await sn();return(t?e.flows.filter(r=>r.trackId===t):e.flows).map(r=>({...r}))}async function GC(t){let n=(await sn()).flows.find(r=>r.id===t);return n?{...n}:null}async function d0(t){let e=await GC(t);if(!e)return null;let n=new Map((await ia({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 f0({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=KC(e),i=await sn(),c=i.flows.find(h=>h.trackId===t&&h.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 l0({trackId:t,steps:n}),d=Date.now(),f={id:i0().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 Do(),await Bf(f,"created"),Ic(f),{...f}}async function p0(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 l0({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 Bf(o,"updated",{version:o.version,...n?{note:String(n).slice(0,200)}:{}}),Ic(o),{...o}}async function m0(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 Bf(r,"deleted"),we("flows",r.id).catch(()=>{}),{ok:!0,id:t,name:r.name}}async function h0(t){return(await sn()).flows.filter(n=>n.steps.some(r=>r.mockId===t)).map(n=>({...n}))}async function w0(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(),Ic(r);return n.length&&await Do(),n.length}async function g0(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 y0(){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 Ic(r);return{pushed:n.flows.length,source:"plane"}}var qC,c0,n0,r0,o0,s0,on,Pf,Ic,Df=M(()=>{ot();kn();Bo();Sn();qC=process.env.BOSTRAT_STATE_DIR||a0.join(process.env.HOME||WC.tmpdir(),".bostrat"),c0=a0.join(qC,"flows.json"),n0=20,r0=80,o0=500,s0=80,on=null,Pf=null;Ic=t=>qt("flows",{...t},{trackId:t.trackId}).catch(()=>{})});import ln from"node:fs/promises";import un from"node:path";import VC from"node:os";import{randomUUID as zC}from"node:crypto";function ca(t){return JC.filter(({re:e})=>e.test(t)).map(({label:e})=>e)}async function Le(){return an||(jf||=(async()=>{let t=!0;try{an=JSON.parse(await ln.readFile(k0,"utf8"))}catch{an={runbooks:[]},t=!1}finally{jf=null}return an.runbooks||=[],!t&&vt()&&await YC().catch(()=>{}),an})(),jf)}async function Nr(){await Yt(k0,an)}function $c(t){return la(qt("runbooks",{...t},{trackId:t.trackId}))}async function YC(){let{records:t,source:e}=await Mt("runbooks");if(!(e!=="plane"||!t.length)){await ln.mkdir(Rc,{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 bs("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 jo(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(Rc,`${t.id}.v${e}.md`)}function x0(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 S0(t){if(typeof t!="string"||!t.trim())throw new Error("md (markdown string) required");let e=Buffer.byteLength(t,"utf8");if(e>b0)throw new Error(`runbook is ${Math.round(e/1024)} KB \u2014 over the ${b0/1024} KB cap; a doc that size belongs in the repo, not a runbook`);let n=ca(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 XC(t,e){if(t.trackDeletedAt)throw new Error(`runbook is orphaned (its Track was deleted) \u2014 cannot ${e} it`)}async function ZC({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 v0({trackId:t,status:e}={}){let n=await Le(),r=await ZC({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 Lf(t){let e=await QC(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 T0(t,e){let n=await bs("runbooks",t.id,e,"md");return typeof n=="string"?n:null}async function QC(t){let n=(await Le()).runbooks.find(r=>r.id===t);return n?{...n}:null}async function A0({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=S0(r),c=await Le(),l={id:zC().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(Rc,{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 jo(l,"created",{version:1}),$c(l),la(xn("runbooks",l.id,1,"md",cn(l,1))),{...l}}async function E0(t,{md:e,note:n}={}){let o=(await Le()).runbooks.find(i=>i.id===t);if(!o)throw new Error("runbook not found");XC(o,"update");let s=S0(e),a=o.version+1;return o.version=a,o.updatedAt=Date.now(),await ln.mkdir(Rc,{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 jo(o,"updated",{version:a,...n?{note:String(n).slice(0,200)}:{}}),$c(o),la(xn("runbooks",o.id,a,"md",cn(o,a))),{...o}}async function _0(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 jo(r,e==="done"?"done":"reopened"),$c(r),{...r})}async function I0(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 jo(r,"deleted"),la(we("runbooks",r.id)),{ok:!0,id:t,name:r.name}}async function R0(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 jo(r,"orphaned"),r.cwd=null,$c(r);return n.length&&await Nr(),n.length}async function $0(t){let e=await Le(),n=e.runbooks.filter(r=>r.trackId===t);for(let r of n){await jo(r,"deleted");for(let o of r.versions||[])await ln.rm(un.join(Mr,o.mdRel),{force:!0}).catch(()=>{});la(we("runbooks",r.id))}return n.length&&(e.runbooks=e.runbooks.filter(r=>r.trackId!==t),await Nr()),n.length}async function O0(){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 qt("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,k0,Rc,b0,JC,an,jf,la,Oc=M(()=>{kn();ot();Sn();Mr=process.env.BOSTRAT_STATE_DIR||un.join(process.env.HOME||VC.tmpdir(),".bostrat"),k0=un.join(Mr,"runbooks.json"),Rc=un.join(Mr,"runbooks"),b0=256*1024,JC=[{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,jf=null;la=t=>Promise.resolve(t).catch(()=>{})});import Ff from"node:fs/promises";import ua from"node:path";import{randomUUID as tM}from"node:crypto";function Hf(t){let e=String(t||"").toLowerCase().replace(/^\./,"");return eM.has(e)?"image":nM.has(e)?"doc":null}function rM(t){let r=ua.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 N0(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>C0)throw new Error(`file too large \u2014 max ${Math.floor(C0/(1024*1024))} MB`);let r=rM(e),o=ua.extname(r).slice(1),s=Hf(o);if(!s)throw new Error(`unsupported file type "${o||"unknown"}" \u2014 attach an image or a document`);let a=tM().slice(0,8),i=Uf(t);await Ff.mkdir(i,{recursive:!0});let c=`${a}-${r}`;return await Ff.writeFile(ua.join(i,c),n,{mode:384}),await Ff.chmod(ua.join(i,c),384).catch(()=>{}),{id:a,name:r,rel:`${M0}/${c}`,kind:s,size:n.length}}function P0(t){let e=t.map(r=>`\`${r}\``).join(", ");return`[Attached \u2014 please read ${t.length===1?"this file":`these ${t.length} files`}: ${e}]`}function Wf(t){return t.role==="user"&&oM.test((t.text||"").trim())}var M0,Uf,C0,eM,nM,oM,qf=M(()=>{M0=".bostrat/uploads",Uf=t=>ua.join(t,M0),C0=Number(process.env.BOSTRAT_MAX_UPLOAD_BYTES)||24*1024*1024,eM=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","tif","tiff","heic","heif","avif","ico"]),nM=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"]);oM=/\[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 B0=M(()=>{});import{execFile as sM}from"node:child_process";import{promisify as aM}from"node:util";function Kf(t){return`refs/bostrat/wip/${t}`}function lM(t,e=Date.now()){return`refs/bostrat/rescue/${t}-${e}`}function L0(t=process.env){let e=String(t.BOSTRAT_WIP_SYNC_MS??"").trim().toLowerCase();return e!=="0"&&e!=="off"&&e!=="false"}function uM(t=process.env){let e=Number(t.BOSTRAT_WIP_SYNC_MS);return Number.isFinite(e)&&e>0?e:cM}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 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 ko(r,"bostrat: wip snapshot"),{stdout:s}=await qn(r,["rev-parse",`${o}^{tree}`]),a=s.trim();if(Cc.get(r)===a)return{pushed:!1,reason:"unchanged"};let i=Kf(n);return await qn(r,["push","--force","origin",`${o}:${i}`],j0),Cc.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 Vf(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 ko(r,"bostrat: transfer rescue snapshot"),{stdout:s}=await qn(r,["rev-parse",`${o}^{tree}`]),a=s.trim();if(Cc.get(r)===a)return{pushed:!1,reason:"unchanged"};let i=lM(n);return await qn(r,["push","origin",`${o}:${i}`],j0),Cc.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 F0({listTracks:t,sweepMs:e=uM(),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 Gf(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 iM,cM,j0,qn,Cc,D0,zf=M(()=>{$d();ot();iM=aM(sM),cM=12e4,j0=6e4;qn=(t,e,n=15e3)=>iM("git",["-C",t,...e],{timeout:n,maxBuffer:4*1024*1024}),Cc=new Map,D0=new Set});import dM from"node:fs";import Jf from"node:fs/promises";import fM from"node:path";function wM(t=process.env){return!!(gt(t)&&t.BOSTRAT_PLANE_TOKEN)}async function U0(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(!wM(e))return{restored:!1,reason:"plane not configured"};let s=so(t),a=fM.join(s,`${o}.ndjson`);try{if(dM.statSync(a).size>0)return{restored:!1,reason:"log not empty"}}catch{}let i=gt(e),c={authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`},l=[],u=0;for(;;){let f=new AbortController,h=setTimeout(()=>f.abort(),hM),p;try{p=await n(`${i}/v1/spine/${encodeURIComponent(o)}?after=${u}&limit=${pM}`,{headers:c,signal:f.signal})}finally{clearTimeout(h)}if(p.status===404)return{restored:!1,reason:"unknown to plane"};if(!p.ok)return{restored:!1,reason:`plane ${p.status}`};let w=await p.json();for(let y of w.events||[])l.push(JSON.stringify(y));if(l.length>mM)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 Jf.mkdir(s,{recursive:!0});let d=`${a}.pull-${process.pid}-${Date.now()}`;return await Jf.writeFile(d,l.join(`
150
+ `)}`:e),this.name="MockRenderError"}},Dr=null,Hf=null;De=t=>Kt("mocks",{...t},{trackId:t.trackId}).catch(()=>{}),je=(t,e,n)=>{let r=(t.versions||[]).find(s=>s.v===e),o=n==="mp4"||n==="webm"?ha(t,r,"video"):r&&ha(t,r,n)||(n==="html"?me(t,e).html:null);return o?Tn("mocks",t.id,e,n,o).catch(()=>{}):Promise.resolve()};wa=t=>Ot.join(t,".bostrat","mocks");iM=Buffer.from([137,80,78,71,13,10,26,10]);hM=mM,Wf=Promise.resolve()});import bM from"node:fs/promises";import Ox from"node:path";import kM from"node:os";import{randomUUID as Cx}from"node:crypto";async function ln(){return cn||(Vf||=(async()=>{let t=!0;try{cn=JSON.parse(await bM.readFile(Mx,"utf8"))}catch{cn={flows:[]},t=!1}finally{Vf=null}if(cn.flows||=[],!t&&kt()){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&&cn.flows.push(r.data);cn.flows.length&&await Wo().catch(()=>{})}}return cn})(),Vf)}async function Wo(){await Xt(Mx,cn)}function zf(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 Nx({trackId:t,steps:e,prevSteps:n=[]}){if(!Array.isArray(e)||e.length<1||e.length>_x)throw new Error(`steps must be an array of 1-${_x}`);let r=await ga({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>Rx)throw new Error(`${l}: caption over ${Rx} chars`);let d=c.title==null?null:String(c.title).trim()||null;if(d&&d.length>$x)throw new Error(`${l}: title over ${$x} chars`);let f=String(c.mock??"").trim().replace(/^mock:/,"");if(!f)throw new Error(`${l}: mock (name or id) required`);let p=r.filter(x=>x.id===f);if(p.length||(p=r.filter(x=>x.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(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:Cx().slice(0,8);s.push({id:k,mockId:h.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 vM(t){if(typeof t!="string"||!t.trim())throw new Error("name (string) required");if(t.trim().length>Ix)throw new Error(`name over ${Ix} chars`);return t.trim()}async function Px({trackId:t}={}){let e=await ln();return(t?e.flows.filter(r=>r.trackId===t):e.flows).map(r=>({...r}))}async function SM(t){let n=(await ln()).flows.find(r=>r.id===t);return n?{...n}:null}async function Bx(t){let e=await SM(t);if(!e)return null;let n=new Map((await ga({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=Te(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 Dx({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=vM(e),i=await ln(),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 Nx({trackId:t,steps:n}),d=Date.now(),f={id:Cx().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 Wo(),await zf(f,"created"),Dc(f),{...f}}async function jx(t,{steps:e,note:n}={}){let o=(await ln()).flows.find(i=>i.id===t);if(!o)throw new Error("flow not found");let{steps:s,resolved:a}=await Nx({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 Wo(),await zf(o,"updated",{version:o.version,...n?{note:String(n).slice(0,200)}:{}}),Dc(o),{...o}}async function Lx(t){let e=await ln(),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 Wo(),await zf(r,"deleted"),ye("flows",r.id).catch(()=>{}),{ok:!0,id:t,name:r.name}}async function Fx(t){return(await ln()).flows.filter(n=>n.steps.some(r=>r.mockId===t)).map(n=>({...n}))}async function Ux(t){let n=(await ln()).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(),Dc(r);return n.length&&await Wo(),n.length}async function Hx(t){let e=await ln(),n=e.flows.filter(r=>r.trackId===t);if(n.length){e.flows=e.flows.filter(r=>r.trackId!==t),await Wo();for(let r of n)ye("flows",r.id).catch(()=>{})}return n.length}async function Wx(){if(!kt())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 ln();for(let r of n.flows)await Dc(r);return{pushed:n.flows.length,source:"plane"}}var xM,Mx,_x,Ix,Rx,$x,cn,Vf,Dc,Jf=C(()=>{st();Sn();Ho();An();xM=process.env.BOSTRAT_STATE_DIR||Ox.join(process.env.HOME||kM.tmpdir(),".bostrat"),Mx=Ox.join(xM,"flows.json"),_x=20,Ix=80,Rx=500,$x=80,cn=null,Vf=null;Dc=t=>Kt("flows",{...t},{trackId:t.trackId}).catch(()=>{})});import fn from"node:fs/promises";import pn from"node:path";import TM from"node:os";import{randomUUID as AM}from"node:crypto";function ya(t){return EM.filter(({re:e})=>e.test(t)).map(({label:e})=>e)}async function Fe(){return un||(Yf||=(async()=>{let t=!0;try{un=JSON.parse(await fn.readFile(Kx,"utf8"))}catch{un={runbooks:[]},t=!1}finally{Yf=null}return un.runbooks||=[],!t&&kt()&&await _M().catch(()=>{}),un})(),Yf)}async function Lr(){await Xt(Kx,un)}function Lc(t){return ba(Kt("runbooks",{...t},{trackId:t.trackId}))}async function _M(){let{records:t,source:e}=await Mt("runbooks");if(!(e!=="plane"||!t.length)){await fn.mkdir(jc,{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 Is("runbooks",r.id,o.v,"md");typeof s=="string"&&await fn.writeFile(dn(r,o.v),s).catch(()=>{})}un.runbooks.push(r)}un.runbooks.length&&await Lr()}}function qo(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 dn(t,e){return pn.join(jc,`${t.id}.v${e}.md`)}function Gx(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 Vx(t){if(typeof t!="string"||!t.trim())throw new Error("md (markdown string) required");let e=Buffer.byteLength(t,"utf8");if(e>qx)throw new Error(`runbook is ${Math.round(e/1024)} KB \u2014 over the ${qx/1024} KB cap; a doc that size belongs in the repo, not a runbook`);let n=ya(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 IM(t,e){if(t.trackDeletedAt)throw new Error(`runbook is orphaned (its Track was deleted) \u2014 cannot ${e} it`)}async function RM({trackId:t,status:e}={}){let n=await Fe(),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 zx({trackId:t,status:e}={}){let n=await Fe(),r=await RM({trackId:t,status:e});if(!kt())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 Xf(t){let e=await $M(t);if(e)return e;if(!kt())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 Jx(t,e){let n=await Is("runbooks",t.id,e,"md");return typeof n=="string"?n:null}async function $M(t){let n=(await Fe()).runbooks.find(r=>r.id===t);return n?{...n}:null}async function Yx({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=Vx(r),c=await Fe(),l={id:AM().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 fn.mkdir(jc,{recursive:!0}),await fn.writeFile(dn(l,1),r),l.versions.push({v:1,mdRel:pn.relative(jr,dn(l,1)),bytes:i,note:null,createdAt:Date.now()}),c.runbooks.push(l),await Lr(),await qo(l,"created",{version:1}),Lc(l),ba(Tn("runbooks",l.id,1,"md",dn(l,1))),{...l}}async function Xx(t,{md:e,note:n}={}){let o=(await Fe()).runbooks.find(i=>i.id===t);if(!o)throw new Error("runbook not found");IM(o,"update");let s=Vx(e),a=o.version+1;return o.version=a,o.updatedAt=Date.now(),await fn.mkdir(jc,{recursive:!0}),await fn.writeFile(dn(o,a),e),o.versions.push({v:a,mdRel:pn.relative(jr,dn(o,a)),bytes:s,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),await Lr(),await qo(o,"updated",{version:a,...n?{note:String(n).slice(0,200)}:{}}),Lc(o),ba(Tn("runbooks",o.id,a,"md",dn(o,a))),{...o}}async function Zx(t,e){if(e!=="open"&&e!=="done")throw new Error('status must be "open" or "done"');let r=(await Fe()).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 Lr(),await qo(r,e==="done"?"done":"reopened"),Lc(r),{...r})}async function Qx(t){let e=await Fe(),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 fn.rm(pn.join(jr,o.mdRel),{force:!0}).catch(()=>{});return await Lr(),r.trackDeletedAt||await qo(r,"deleted"),ba(ye("runbooks",r.id)),{ok:!0,id:t,name:r.name}}async function t0(t){let n=(await Fe()).runbooks.filter(r=>r.trackId===t&&!r.trackDeletedAt);for(let r of n)r.trackDeletedAt=Date.now(),r.updatedAt=Date.now(),await qo(r,"orphaned"),r.cwd=null,Lc(r);return n.length&&await Lr(),n.length}async function e0(t){let e=await Fe(),n=e.runbooks.filter(r=>r.trackId===t);for(let r of n){await qo(r,"deleted");for(let o of r.versions||[])await fn.rm(pn.join(jr,o.mdRel),{force:!0}).catch(()=>{});ba(ye("runbooks",r.id))}return n.length&&(e.runbooks=e.runbooks.filter(r=>r.trackId!==t),await Lr()),n.length}async function n0(){if(!kt())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 Fe();for(let r of n.runbooks){await Kt("runbooks",{...r},{trackId:r.trackId}).catch(()=>{});for(let o of r.versions||[])await Tn("runbooks",r.id,o.v,"md",pn.join(jr,o.mdRel)).catch(()=>{})}return{pushed:n.runbooks.length,source:"plane"}}var jr,Kx,jc,qx,EM,un,Yf,ba,Fc=C(()=>{Sn();st();An();jr=process.env.BOSTRAT_STATE_DIR||pn.join(process.env.HOME||TM.tmpdir(),".bostrat"),Kx=pn.join(jr,"runbooks.json"),jc=pn.join(jr,"runbooks"),qx=256*1024,EM=[{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/}];un=null,Yf=null;ba=t=>Promise.resolve(t).catch(()=>{})});import Zf from"node:fs/promises";import ka from"node:path";import{randomUUID as OM}from"node:crypto";function tp(t){let e=String(t||"").toLowerCase().replace(/^\./,"");return CM.has(e)?"image":MM.has(e)?"doc":null}function NM(t){let r=ka.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 s0(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>r0)throw new Error(`file too large \u2014 max ${Math.floor(r0/(1024*1024))} MB`);let r=NM(e),o=ka.extname(r).slice(1),s=tp(o);if(!s)throw new Error(`unsupported file type "${o||"unknown"}" \u2014 attach an image or a document`);let a=OM().slice(0,8),i=Qf(t);await Zf.mkdir(i,{recursive:!0});let c=`${a}-${r}`;return await Zf.writeFile(ka.join(i,c),n,{mode:384}),await Zf.chmod(ka.join(i,c),384).catch(()=>{}),{id:a,name:r,rel:`${o0}/${c}`,kind:s,size:n.length}}function a0(t){let e=t.map(r=>`\`${r}\``).join(", ");return`[Attached \u2014 please read ${t.length===1?"this file":`these ${t.length} files`}: ${e}]`}function ep(t){return t.role==="user"&&PM.test((t.text||"").trim())}var o0,Qf,r0,CM,MM,PM,np=C(()=>{o0=".bostrat/uploads",Qf=t=>ka.join(t,o0),r0=Number(process.env.BOSTRAT_MAX_UPLOAD_BYTES)||24*1024*1024,CM=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","tif","tiff","heic","heif","avif","ico"]),MM=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"]);PM=/\[Attached — please read (?:this file|these \d+ files): [^\]]*\]$/});function Fr(t,e,n=Date.now()){return e?t.idleSince==null?(t.idleSince=n,!1):n-t.idleSince>=6500:(t.idleSince=null,!1)}var i0=C(()=>{});import{execFile as BM}from"node:child_process";import{promisify as DM}from"node:util";function rp(t){return`refs/bostrat/wip/${t}`}function FM(t,e=Date.now()){return`refs/bostrat/rescue/${t}-${e}`}function u0(t=process.env){let e=String(t.BOSTRAT_WIP_SYNC_MS??"").trim().toLowerCase();return e!=="0"&&e!=="off"&&e!=="false"}function UM(t=process.env){let e=Number(t.BOSTRAT_WIP_SYNC_MS);return Number.isFinite(e)&&e>0?e:LM}async function op(t,{log:e=console}={}){let{id:n,cwd:r}=t??{};if(!n||!r)return{pushed:!1,reason:"no-workspace"};try{await Vn(r,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await Vn(r,["remote","get-url","origin"])}catch{return c0.has(r)||(c0.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 So(r,"bostrat: wip snapshot"),{stdout:s}=await Vn(r,["rev-parse",`${o}^{tree}`]),a=s.trim();if(Uc.get(r)===a)return{pushed:!1,reason:"unchanged"};let i=rp(n);return await Vn(r,["push","--force","origin",`${o}:${i}`],l0),Uc.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(`
151
+ `)[0]}`),{pushed:!1,reason:"push-failed"}}}async function sp(t,{log:e=console}={}){let{id:n,cwd:r}=t??{};if(!n||!r)return{pushed:!1,reason:"no-workspace"};try{await Vn(r,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await Vn(r,["remote","get-url","origin"])}catch{return{pushed:!1,reason:"no-origin"}}try{let o=await So(r,"bostrat: transfer rescue snapshot"),{stdout:s}=await Vn(r,["rev-parse",`${o}^{tree}`]),a=s.trim();if(Uc.get(r)===a)return{pushed:!1,reason:"unchanged"};let i=FM(n);return await Vn(r,["push","origin",`${o}:${i}`],l0),Uc.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(`
152
+ `)[0]}`),{pushed:!1,reason:"push-failed"}}}function d0({listTracks:t,sweepMs:e=UM(),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 op(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 jM,LM,l0,Vn,Uc,c0,ap=C(()=>{Ld();st();jM=DM(BM),LM=12e4,l0=6e4;Vn=(t,e,n=15e3)=>jM("git",["-C",t,...e],{timeout:n,maxBuffer:4*1024*1024}),Uc=new Map,c0=new Set});import HM from"node:fs";import ip from"node:fs/promises";import WM from"node:path";function VM(t=process.env){return!!(gt(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(!VM(e))return{restored:!1,reason:"plane not configured"};let s=ho(t),a=WM.join(s,`${o}.ndjson`);try{if(HM.statSync(a).size>0)return{restored:!1,reason:"log not empty"}}catch{}let i=gt(e),c={authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`},l=[],u=0;for(;;){let f=new AbortController,p=setTimeout(()=>f.abort(),GM),h;try{h=await n(`${i}/v1/spine/${encodeURIComponent(o)}?after=${u}&limit=${qM}`,{headers:c,signal:f.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>KM)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 ip.mkdir(s,{recursive:!0});let d=`${a}.pull-${process.pid}-${Date.now()}`;return await ip.writeFile(d,l.join(`
152
153
  `)+`
153
- `),await Jf.rename(d,a),r.log?.(`[spine-pull] rehydrated ${o}: ${l.length} event(s) \u2192 ${a}`),{restored:!0,rows:l.length}}var pM,mM,hM,H0=M(()=>{Wt();ot();pM=1e3,mM=5e5,hM=3e4});var vx={};Ol(vx,{HANDOFF_LATEST_REL:()=>Br,KNOWN_AGENTS:()=>xa,addTrackRepo:()=>bp,adoptTrack:()=>Mp,agentAvailability:()=>Bc,answerFullscreenOffer:()=>_p,answerPrompt:()=>jc,archiveTrack:()=>Dr,archiveTrackForMergedPr:()=>Xe,augmentFirstPromptAfterHandoff:()=>Z0,buildAgentCmd:()=>Y0,canResumeSubtask:()=>kx,cancelQueued:()=>Ta,cancelQueuedToDraft:()=>pp,cancelStopJob:()=>Aa,cancelSubtask:()=>zc,changedRepos:()=>Io,commitTransferOut:()=>Gc,createSetupTrack:()=>Sp,createTrack:()=>Fc,deleteTrack:()=>Tp,demoteTransferredTracks:()=>Cp,ensureLeadEpochs:()=>qc,forceMergeSubtask:()=>Dp,getHandoffJob:()=>Vo,getSubtaskJob:()=>wN,getTrack:()=>Y,getTransferOutJob:()=>$p,interruptLead:()=>Lc,isArchiving:()=>iN,isHandoffNoteEcho:()=>rp,isInterruptEcho:()=>op,isModelSwitchEcho:()=>sp,listSubtaskJobs:()=>jr,listTracks:()=>nt,matchTranscriptsToBoxes:()=>ex,mergeNotifyMessage:()=>wx,navigatePrompt:()=>dp,notifyTrackForMergedPr:()=>Ze,notifyTrackForResolvedPr:()=>Uc,queueShipCompleteNotify:()=>mp,queuedMessages:()=>Wo,reapArchivedOrphans:()=>Ep,reconcileHandoffOutcome:()=>gx,reconcileInterruptedHandoffs:()=>Rp,reconcileInterruptedSubtasks:()=>Np,reconcileSubtaskOutcome:()=>bx,refreshStandingInstructions:()=>xp,rehydrateLead:()=>Hc,removeTrackRepo:()=>kp,reposOf:()=>ae,resolveTrackBox:()=>Js,resolveTrackBoxByHookToken:()=>lp,restartLead:()=>Wc,resumeAgentCmd:()=>cp,sayToLead:()=>me,sendOptionsForAgent:()=>$e,setTrackDraft:()=>gp,setTrackModel:()=>yp,startLeadHandoff:()=>Kc,startSpinUpView:()=>hp,startSubtask:()=>Bp,startTransferOut:()=>Op,stopJobActive:()=>ax,subtaskMessages:()=>up,trackMessages:()=>Dc,unarchiveTrack:()=>Ap});import H from"node:fs/promises";import W from"node:path";import{randomUUID as ka}from"node:crypto";import{execFile as gM}from"node:child_process";import{promisify as yM}from"node:util";function Y0(t,{skipPermissions:e=!0}={}){let n=Pc[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 cp(t,e,{skipPermissions:n=!0}={}){let r=Pc[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 Sa(t){let e=Pc[t];if(e)return process.env[e.envVar]||e.base}async function Bc({maxAgeMs:t=6e4}={}){if(Kn.value&&Date.now()-Kn.at<t)return Kn.value;let e=Kn.value,n=await Promise.all(xa.map(async r=>{let o=await bi(Sa(r),{retries:[]});return o===Qr?[r,e?.[r]??!0]:[r,o===yi]}));return Kn.value=Object.fromEntries(n),Kn.at=Date.now(),Kn.value}async function va(t,e=!0){let n=Y0(t,{skipPermissions:e});if(await bi(n)===Zr){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.":ru[r]?`Install it on this node: ${ru[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 Z0(t,e=Br){return`${t.trim()}
154
+ `),await ip.rename(d,a),r.log?.(`[spine-pull] rehydrated ${o}: ${l.length} event(s) \u2192 ${a}`),{restored:!0,rows:l.length}}var qM,KM,GM,p0=C(()=>{qt();st();qM=1e3,KM=5e5,GM=3e4});var V0={};Ul(V0,{HANDOFF_LATEST_REL:()=>Ur,KNOWN_AGENTS:()=>$a,addTrackRepo:()=>Cp,adoptTrack:()=>Gp,agentAvailability:()=>Kc,answerFullscreenOffer:()=>Fp,answerPrompt:()=>Vc,archiveTrack:()=>Hr,archiveTrackForMergedPr:()=>tn,augmentFirstPromptAfterHandoff:()=>S0,buildAgentCmd:()=>x0,canResumeSubtask:()=>q0,cancelQueued:()=>Ma,cancelQueuedToDraft:()=>Ap,cancelStopJob:()=>Na,cancelSubtask:()=>ol,changedRepos:()=>No,commitTransferOut:()=>nl,createSetupTrack:()=>Pp,createTrack:()=>Yc,deleteTrack:()=>Dp,demoteTransferredTracks:()=>Kp,ensureLeadEpochs:()=>tl,forceMergeSubtask:()=>Yp,getHandoffJob:()=>ts,getSubtaskJob:()=>JN,getTrack:()=>X,getTransferOutJob:()=>Wp,interruptLead:()=>Jc,isArchiving:()=>LN,isHandoffNoteEcho:()=>wp,isInterruptEcho:()=>gp,isModelSwitchEcho:()=>yp,listSubtaskJobs:()=>Wr,listTracks:()=>ot,matchTranscriptsToBoxes:()=>E0,mergeNotifyMessage:()=>F0,navigatePrompt:()=>Tp,notifyTrackForMergedPr:()=>en,notifyTrackForResolvedPr:()=>Xc,queueShipCompleteNotify:()=>_p,queuedMessages:()=>Jo,reapArchivedOrphans:()=>Lp,reconcileHandoffOutcome:()=>U0,reconcileInterruptedHandoffs:()=>Hp,reconcileInterruptedSubtasks:()=>Vp,reconcileSubtaskOutcome:()=>W0,refreshStandingInstructions:()=>Np,rehydrateLead:()=>Zc,removeTrackRepo:()=>Mp,reposOf:()=>ie,resolveTrackBox:()=>sa,resolveTrackBoxByHookToken:()=>vp,restartLead:()=>Qc,resumeAgentCmd:()=>xp,sayToLead:()=>we,sendOptionsForAgent:()=>Oe,setTrackDraft:()=>$p,setTrackModel:()=>Op,startLeadHandoff:()=>el,startSpinUpView:()=>Ip,startSubtask:()=>Jp,startTransferOut:()=>qp,stopJobActive:()=>$0,subtaskMessages:()=>Sp,trackMessages:()=>Gc,unarchiveTrack:()=>jp});import W from"node:fs/promises";import q from"node:path";import{randomUUID as Qo}from"node:crypto";import{execFile as zM}from"node:child_process";import{promisify as JM}from"node:util";function x0(t,{skipPermissions:e=!0}={}){let n=qc[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 xp(t,e,{skipPermissions:n=!0}={}){let r=qc[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 Oa(t){let e=qc[t];if(e)return process.env[e.envVar]||e.base}async function Kc({maxAgeMs:t=6e4}={}){if(zn.value&&Date.now()-zn.at<t)return zn.value;let e=zn.value,n=await Promise.all($a.map(async r=>{let o=await Ei(Oa(r),{retries:[]});return o===oo?[r,e?.[r]??!0]:[r,o===Ai]}));return zn.value=Object.fromEntries(n),zn.at=Date.now(),zn.value}async function Ca(t,e=!0){let n=x0(t,{skipPermissions:e});if(await Ei(n)===ro){zn.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.":pu[r]?`Install it on this node: ${pu[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=Ur){return`${t.trim()}
154
155
 
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 rp(t){return t.role==="user"&&xM.test((t.text||"").trim())}async function K(){return pe||(Yf||=(async()=>{try{pe=JSON.parse(await H.readFile(J0,"utf8"))}catch{pe={tracks:[]}}finally{Yf=null}return pe})(),Yf)}async function J(){await Yt(J0,pe)}function TM(t,e){let n=JSON.stringify({trackId:t,...e})+`
156
- `;return Xf=Xf.then(()=>H.mkdir(fn,{recursive:!0})).then(()=>H.appendFile(bM,n)).catch(()=>{}),Xf}function Q0(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=>AM.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 tx(t,e,n,{kind:r}={}){let o=await et(e);if(!o)throw new Error(`box "${e}" is not running`);let s=Sa(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 V({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 EM(t){let e=W.join(so(t),`${t.id}.ndjson`),n;try{n=await H.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 F(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 _M(t,e){let n=e.find(r=>r.name===t.leadBox);return n?.state!=="live"?{working:!1,prompted:!1}:Wd(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([EM(t),_M(t,r)]);return{...t,boxes:r,lastResponseAt:o,working:s,prompted:a,archiving:ya.has(t.id)}}function ex(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-IM,f=r[u+1]?.createdAt??1/0,h=o.find(p=>!s.has(p.id)&&p.birthMs>=d&&p.birthMs<f);h&&(s.add(h.id),c.push({box:l.name,sessionId:h.id}))}return c}async function nx(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=Zh(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=ex(u,a,f=>i.has(f));for(let f of d){let h=u.find(p=>p.name===f.box);h&&(h.sessionId=f.sessionId),await Wh(f.box,f.sessionId),n=!0}}return n}async function nt(){let t=await K();await nx(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 Js(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 lp(t){let e=is(t);if(!e)return null;let n=await K();for(let r of n.tracks||[])for(let o of r.boxes||[])if(o.hookTokenHash&&zm(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 nx(e)&&await J(),Fe(n)):null}function op(t){if(t.role!=="user")return!1;let e=(t.text||"").trim();return(RM[t.agent]||[]).some(n=>n.test(e))}function sp(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=Vo(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=df(n.id),c=!!(i&&!i.finishedAt),l=c&&i.startedAt&&i.box?[{box:i.box,from:i.startedAt,to:Date.now()+1e12}]:[],u=[...dk(n),...l],f={windows:[...Tg(n),...Ag(n,Li),...a,...u]},p=(await Promise.all(n.boxes.map(b=>ld(b,e)))).flat(),w=p.map(b=>{let _={kind:"message",...b};if(_.role==="assistant"&&(_.text||"").trim()&&_.tools?.length){let R=Ls(_.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 _=Bi(b.text);return _?_.kind==="suppress"?null:{...b,note:_,text:zw(_)}:b}).filter(Boolean).filter(b=>!(b.role==="user"&&r.has((b.text||"").trim()))).filter(b=>!op(b)).filter(b=>!sp(b)).filter(b=>!rp(b)).filter(b=>!Wf(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===Ou);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=>ry(b,e)));await Vb(n,k.flat()),await Kb(n,w),await Zy(n),await yk(n,w).catch(()=>{});for(let b of n.boxes)b.agent==="codex"&&b.state==="live"&&await Jb(n,b),b.agent==="cursor"&&b.state==="live"&&await tk(n,b);let x=await Promise.all(n.boxes.map(b=>ny(b,e)));await Gb(n,x.flat().filter(b=>!Zf(b.box,b.ts,u)));let E=await F(n),$=c&&i.viewId?i.viewId:null,G=cb(E),C=hr(E).filter(b=>!(b.kind==="message"&&(op(b)||sp(b)||rp(b)||Wf(b)))&&!(b.kind==="view-card"&&$&&b.viewId===$)),N=lb(C,G),T=C.filter(b=>!(b.kind==="message"&&b.role==="assistant"&&!N.has(b)&&Zf(b.box,b.ts,G))),B=qu(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=>!Zf(b.anchorBox,b.anchorTs??b.ts,u)),j=eg(ng([...T,...B].filter(b=>b.ts!=null).sort((b,_)=>b.ts-_.ts))),at=CM(n),rt=at.size?j.filter(b=>b.kind==="event"||!at.has(b.box??b.anchorBox)):j,A=n.boxes.find(b=>b.name===n.leadBox)||null,D=A?await vs(A.cwd,A.sessionId,{fallbackNewest:!1}):null;if(!D&&A){let b=[...E].reverse().find(_=>_.type==="context.usage"&&_.boxId===A.name);b?.payload?.window&&(D={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=[...p].reverse().find(b=>b.role==="assistant"&&b.model),bt=X?.model||null,dt=[...n.events||[]].reverse().find(b=>b.type==="model-change"),kt=D?.model||bt;dt&&(!X?.ts||dt.at>=X.ts)&&(kt=dt.to);let xt=A?await Tt(A.name,{lines:Nt}).catch(()=>""):"",g=A&&yo(A.agent,xt)?await En(A.name).catch(()=>xt):xt,m=A?Sr(A,g):null;if(m&&A){let b=qi(A,m,g);if(b){let _=by(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&&!Es(A.agent,xt)&&!Wo(n.id).length&&(m=Hu(rt,{leadBoxId:A.name,provider:A.agent,isAnswered:b=>E.some(_=>_.type==="prompt.answered"&&_.payload?.promptId===b)})),m&&Qy(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&&lc(A.name,A.agent,xt)&&!m;A&&!A.readyAt&&(it||m||xt&&Ri(A.agent,xt))&&(A.readyAt=Date.now(),await J());let ct=!!A&&!A.readyAt&&Date.now()-(n.createdAt||0)<OM;if(n.kind==="setup"&&n.setup?.provider&&!n.setup.connectedAt&&A&&Ri(A.agent,xt)&&!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 _=gc(n.id);_&&(pt(n,"view-spinup",{box:i.box,startedAt:i.startedAt,endedAt:_.finishedAt}),await J())}else if(m||b>lk&&!it&&!i.viewId||b>uf){let _=m?"needs-input":b>uf?"timeout":"no-view";gc(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:D?{pct:D.pct,occupancy:D.occupancy,window:D.window,windowKnown:D.windowKnown,model:D.model}:null,models:{current:kt,options:Ky(A?.agent)},pendingPrompt:m,working:it,stopping:ax(n.id),leadStarting:ct,handoff:mt,view:sr,queued:Wo(n.id).filter(b=>b.kind!=="ship-notify"&&b.kind!=="prompt-answer"),draft:n.draft||null,draftRev:n.draftRev||0}}function CM(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 up(t,e){let n=await Y(t);if(!n)return null;let r=jr(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 F(n),a=hr(s).filter(d=>d.box===o&&!(d.kind==="message"&&d.role==="assistant"&&d.ask&&!String(d.text||"").trim()&&!d.images?.length)),i=qu(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 Tt(o,{lines:Nt}).catch(()=>"");u=lc(o,l.agent||r.agent,d)}return{items:c,working:u,box:o,agent:r.agent,task:r.task}}async function jc(t,{promptId:e,answers:n,text:r}={}){let o=Z(await K(),t);if(!o)throw new Error(`track "${t}" not found`);Aa(t,"prompt-answer");let s=o.boxes.find(p=>p.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 wd(s);if(i||(i=await MM(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 p=typeof r=="string"?r.trim():"";if(!p)throw new Error("this prompt needs a code \u2014 paste it into the card");if(/\s/.test(p)||p.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,p,{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 p=Zw(i,n||[],typeof r=="string"?r:"");if(!p)throw new Error("no answer selected \u2014 pick an option or reply in chat");await me(o.id,p,{kind:"prompt-answer"}),c={mode:"say",value:p,count:1}}else if(i.provider==="claude"||i.answerMode==="keys"){let p=hy(i,n||[]);await It(o.leadBox,p,{kind:"answer-prompt"}),c={mode:"keys",value:p.join(" "),count:p.length}}else{let p=dw(i,n||[]);await Pt(o.leadBox,p,{enter:!0,kind:"answer-prompt"}),c={mode:"text",value:p,count:1}}if(i.answerMode==="say"){let p=i.questions||[];for(let w=0;w<p.length;w++){let y=p[w],k=new Set(Array.isArray(n?.[w])?n[w]:[]),x=[...k].map($=>y.options?.[$]).filter(Boolean).map($=>({label:$.label,description:$.description||""})),E=(y.options||[]).map(($,G)=>k.has(G)?null:$?.label).filter(Boolean);Bd(o,s,i,{...c,groupId:i.groupId||i.promptId,questionIndex:w,questionTotal:i.questionTotal??p.length,header:y.header||"",question:y.question||"",multiSelect:!!y.multiSelect,chosen:x,rejected:E})}return await V({flow:"prompt",phase:"answered",sessionName:o.leadBox,agent:s.agent,provider:i.provider,promptId:i.promptId,...c}).catch(()=>{}),{ok:!0,promptId:i.promptId,sent:c.count}}let l=i.questions?.[0]||{},u=new Set(Array.isArray(n?.[0])?n[0]:[]),d=[...u].map(p=>l.options?.[p]).filter(Boolean).map(p=>({label:p.label,description:p.description||""})),f=(l.options||[]).map((p,w)=>u.has(w)?null:p?.label).filter(Boolean),h=i.review?"review":/^claude:model-confirm:/.test(i.promptId||"")?"model-confirm":/^claude:resume-confirm:/.test(i.promptId||"")?"resume-confirm":void 0;return c={...c,groupId:i.groupId||i.promptId,questionIndex:i.questionIndex??0,questionTotal:i.questionTotal??1,header:l.header||"",question:l.question||"",multiSelect:!!l.multiSelect,chosen:d,rejected:f,...h?{control:h}:{}},await V({flow:"prompt",phase:"answered",sessionName:o.leadBox,agent:s.agent,provider:i.provider,promptId:i.promptId,...c}).catch(()=>{}),Bd(o,s,i,c),{ok:!0,promptId:i.promptId,sent:c.count}}async function MM(t,e){if(!e)return null;let n=await F(t).catch(()=>[]);return Hu(hr(n),{leadBoxId:e.name,provider:e.agent,isAnswered:r=>n.some(o=>o.type==="prompt.answered"&&o.payload?.promptId===r)})}async function dp(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 wd(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=wy(a,n);return c.length?(await It(r.leadBox,c,{kind:"navigate-prompt"}),await V({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 fp(t){let e=ma.get(t);return e||(e={items:[],timer:null,flushing:!1,idleSince:null},ma.set(t,e)),e}function Wo(t){return(ma.get(t)?.items??[]).map(e=>({...e}))}function Ta(t){let e=ma.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 pp(t){let e=Ta(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=qo(o,n),await J(),{removed:e,restored:r,draftRev:o.draftRev||0}}return{removed:e,restored:r,draftRev:null}}function rx(t){let e=fp(t);e.timer||(e.timer=setInterval(()=>PM(t).catch(()=>{}),NM))}async function PM(t){let e=ma.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){Ta(t);return}let r=Vo(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(Ii(s?.agent,a)){Pr(e,!1);return}if(yo(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 sx(n,s,o,i.text,i.kind??null,i.attachments??null),await J()}finally{e.flushing=!1}}}async function ox(t,e,n,r){let o=Tr(e?.agent);if(!o)return;if(!r&&typeof n=="string"&&n.trim()&&(qo(t,[n]),await J()),Py(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 sx(t,e,n,r,o=null,s=null){await ox(t,e,r,o);let a=ha.get(t.id)||0,i=r,c=!1;t.pendingHandoffHydrate&&(i=Z0(r,t.pendingHandoffHydrate.artifact||Br),delete t.pendingHandoffHydrate,c=!0);let l=Array.isArray(s)?s.filter(d=>d&&d.rel):[];if(l.length){let d=P0(l.map(f=>f.rel));i=i.trim()?`${i.trim()}
156
+ (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 wp(t){return t.role==="user"&&ZM.test((t.text||"").trim())}async function G(){return he||(cp||=(async()=>{try{he=JSON.parse(await W.readFile(k0,"utf8"))}catch{he={tracks:[]}}finally{cp=null}return he})(),cp)}async function Y(){await Xt(k0,he)}function eN(t,e){let n=JSON.stringify({trackId:t,...e})+`
157
+ `;return lp=lp.then(()=>W.mkdir(hn,{recursive:!0})).then(()=>W.appendFile(YM,n)).catch(()=>{}),lp}function T0(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=>nN.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 A0(t,e,n,{kind:r}={}){let o=await nt(e);if(!o)throw new Error(`box "${e}" is not running`);let s=Oa(o.agent);await On({cwd:o.cwd,sessionId:o.sessionId,sessionName:e,agent:o.agent,agentCmd:s}),await Pt(e,n,{...Oe(o.agent),kind:r||"orchestration"}),await z({flow:"orchestration",phase:"sent",trackId:t,sessionName:e,agent:o.agent,kind:r||"orchestration",promptHead:n.slice(0,160)});let a=await G(),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 Y()}async function rN(t){let e=q.join(ho(t),`${t.id}.ndjson`),n;try{n=await W.stat(e)}catch{return null}let r=m0.get(t.id);if(r&&r.mtimeMs===n.mtimeMs)return r.at;let o=null;for(let s of await B(t)){if(s.type!=="turn.agent")continue;let a=s.payload?.ts??s.ts;a&&(!o||a>o)&&(o=a)}return m0.set(t.id,{mtimeMs:n.mtimeMs,at:o}),o}async function oN(t,e){let n=e.find(r=>r.name===t.leadBox);return n?.state!=="live"?{working:!1,prompted:!1}:Zd(n.name,n.agent)}async function Ue(t,e=null){let n=e??new Map((await be()).map(i=>[i.name,i])),r=t.boxes.map(i=>{let c=n.get(i.name),l=Jn.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([rN(t),oN(t,r)]);return{...t,boxes:r,lastResponseAt:o,working:s,prompted:a,archiving:Ia.has(t.id)}}function E0(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-sN,f=r[u+1]?.createdAt??1/0,p=o.find(h=>!s.has(h.id)&&h.birthMs>=d&&h.birthMs<f);p&&(s.add(p.id),c.push({box:l.name,sessionId:p.id}))}return c}async function _0(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=uw(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=E0(u,a,f=>i.has(f));for(let f of d){let p=u.find(h=>h.name===f.box);p&&(p.sessionId=f.sessionId),await ew(f.box,f.sessionId),n=!0}}return n}async function ot(){let t=await G();await _0(t)&&await Y();let e=new Map((await be()).map(n=>[n.name,n]));return Promise.all(t.tracks.map(n=>Ue(n,e)))}async function sa(t,e){let n=await G();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 vp(t){let e=ws(t);if(!e)return null;let n=await G();for(let r of n.tracks||[])for(let o of r.boxes||[])if(o.hookTokenHash&&ah(o.hookTokenHash,e))return{track:r,box:o};return null}async function X(t){let e=await G(),n=Z(e,t);return n?(await _0(e)&&await Y(),Ue(n)):null}function gp(t){if(t.role!=="user")return!1;let e=(t.text||"").trim();return(aN[t.agent]||[]).some(n=>n.test(e))}function yp(t){let e=(t.text||"").trim();return e?iN.some(n=>n.test(e)):!1}async function Gc(t,e={}){let n=await X(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=ts(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=Sf(n.id),c=!!(i&&!i.finishedAt),l=c&&i.startedAt&&i.box?[{box:i.box,from:i.startedAt,to:Date.now()+1e12}]:[],u=[...Bk(n),...l],f={windows:[...Lg(n),...Fg(n,Vi),...a,...u]},h=(await Promise.all(n.boxes.map(b=>yd(b,e)))).flat(),w=h.map(b=>{let E={kind:"message",...b};if(E.role==="assistant"&&(E.text||"").trim()&&E.tools?.length){let O=Js(E.agent).cliTools,P=E.tools.filter(wt=>!O.has(wt));return{...E,tools:P.length?P:void 0}}return E}).map(b=>{if(b.role!=="user")return b;let E=qi(b.text);return E?E.kind==="suppress"?null:{...b,note:E,text:lg(E)}:b}).filter(Boolean).filter(b=>!(b.role==="user"&&r.has((b.text||"").trim()))).filter(b=>!gp(b)).filter(b=>!yp(b)).filter(b=>!wp(b)).filter(b=>!ep(b)).filter(b=>b.role!=="assistant"||!!(b.text||"").trim()||!!b.images?.length).filter(b=>!Ug(b,f)),y=w.filter(b=>b.failed&&b.text===hr);if(y.length){let b=new Map;for(let E of y){if(!b.has(E.box)){let wt=[...(await xt(E.box,{lines:Nt}).catch(()=>"")).matchAll(/^\s*■\s+(.+?)\s*$/gm)].map(mt=>mt[1]);b.set(E.box,wt.length?wt[wt.length-1]:null)}let O=b.get(E.box);O&&(E.text=`\u25A0 ${O}`)}}let k=await Promise.all(n.boxes.map(b=>yy(b,e)));await yk(n,k.flat()),await wk(n,w),await pb(n),await Wk(n,w).catch(()=>{});for(let b of n.boxes)b.agent==="codex"&&b.state==="live"&&await kk(n,b),b.agent==="cursor"&&b.state==="live"&&await Ak(n,b);let x=await Promise.all(n.boxes.map(b=>gy(b,e)));await gk(n,x.flat().filter(b=>!up(b.box,b.ts,u)));let A=await B(n),R=c&&i.viewId?i.viewId:null,V=Sb(A),M=br(A).filter(b=>!(b.kind==="message"&&(gp(b)||yp(b)||wp(b)||ep(b)))&&!(b.kind==="view-card"&&R&&b.viewId===R)),N=Tb(M,V),T=M.filter(b=>!(b.kind==="message"&&b.role==="assistant"&&!N.has(b)&&up(b.box,b.ts,V))),D=Qu(A,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=>!up(b.anchorBox,b.anchorTs??b.ts,u)),F=wg(gg([...T,...D].filter(b=>b.ts!=null).sort((b,E)=>b.ts-E.ts))),ct=lN(n),Q=ct.size?F.filter(b=>b.kind==="event"||!ct.has(b.box??b.anchorBox)):F,_=n.boxes.find(b=>b.name===n.leadBox)||null,U=_?await Cs(_.cwd,_.sessionId,{fallbackNewest:!1}):null;if(!U&&_){let b=[...A].reverse().find(E=>E.type==="context.usage"&&E.boxId===_.name);b?.payload?.window&&(U={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 j=[...h].reverse().find(b=>b.role==="assistant"&&b.model),at=j?.model||null,Et=[...n.events||[]].reverse().find(b=>b.type==="model-change"),Lt=U?.model||at;Et&&(!j?.ts||Et.at>=j.ts)&&(Lt=Et.to);let it=_?await xt(_.name,{lines:Nt}).catch(()=>""):"",g=_&&Er(_.agent,it)?await Ve(_.name).catch(()=>it):it,m=_?Dn(_,g):null;if(m&&_){let b=Zi(_,m,g);if(b){let E=Ny(_.name,m.promptId);E.action!=="give-up"&&(E.action==="send"&&(_t(_.name,b.keys,{kind:"auto-reject"}).catch(()=>{}),E.first&&I(n,{type:"prompt.autoRejected",actor:"system",source:"pane",boxId:_.name,provider:_.agent,payload:{ts:Date.now(),promptId:m.promptId,rule:b.id}}).catch(()=>{})),m=null)}}!m&&_&&!Ls(_.agent,it)&&!Jo(n.id).length&&(m=Xu(Q,{leadBoxId:_.name,provider:_.agent,isAnswered:b=>A.some(E=>E.type==="prompt.answered"&&E.payload?.promptId===b)})),m&&mb(n,_,m);let S=Q.filter(b=>!(b.kind==="message"&&b.role==="assistant"&&b.ask&&!String(b.text||"").trim()&&!b.images?.length)),lt=!!_&&gc(_.name,_.agent,it)&&!m;_&&!_.readyAt&&(lt||m||it&&Di(_.agent,it))&&(_.readyAt=Date.now(),await Y());let ht=!!_&&!_.readyAt&&Date.now()-(n.createdAt||0)<cN;if(n.kind==="setup"&&n.setup?.provider&&!n.setup.connectedAt&&_&&Di(_.agent,it)&&!m){let b=await G(),E=Z(b,n.id);E?.setup&&!E.setup.connectedAt&&(E.setup.connectedAt=Date.now(),n.setup.connectedAt=E.setup.connectedAt,await I(E,{type:"provider.connected",actor:"system",source:"pane",boxId:_.name,provider:_.agent,payload:{provider:_.agent,ts:E.setup.connectedAt}}).catch(()=>{}),await Y())}let vt=s?{running:!0,step:o.step,toAgent:o.toAgent||null}:null,Ct=null;if(c){let b=Date.now()-i.startedAt;if(i.viewId&&!lt){let E=Ec(n.id);E&&(pt(n,"view-spinup",{box:i.box,startedAt:i.startedAt,endedAt:E.finishedAt}),await Y())}else if(m||b>Nk&&!lt&&!i.viewId||b>vf){let E=m?"needs-input":b>vf?"timeout":"no-view";Ec(n.id,{error:E})&&await I(n,{type:"view.spinup.failed",actor:"orchestrator",source:"orchestrator",boxId:i.box,provider:_?.agent||null,payload:{ts:i.startedAt,name:i.name,reason:E}}).catch(()=>{})}else Ct={running:!0,step:i.step,name:i.name}}return{trackId:n.id,leadBox:n.leadBox,items:S,context:U?{pct:U.pct,occupancy:U.occupancy,window:U.window,windowKnown:U.windowKnown,model:U.model}:null,models:{current:Lt,options:ab(_?.agent)},pendingPrompt:m,working:lt,stopping:$0(n.id),leadStarting:ht,handoff:vt,view:Ct,queued:Jo(n.id).filter(b=>b.kind!=="ship-notify"&&b.kind!=="prompt-answer"),draft:n.draft||null,draftRev:n.draftRev||0}}function lN(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 Sp(t,e){let n=await X(t);if(!n)return null;let r=Wr(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 B(n),a=br(s).filter(d=>d.box===o&&!(d.kind==="message"&&d.role==="assistant"&&d.ask&&!String(d.text||"").trim()&&!d.images?.length)),i=Qu(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 xt(o,{lines:Nt}).catch(()=>"");u=gc(o,l.agent||r.agent,d)}return{items:c,working:u,box:o,agent:r.agent,task:r.task}}async function Vc(t,{promptId:e,answers:n,text:r}={}){let o=Z(await G(),t);if(!o)throw new Error(`track "${t}" not found`);Na(t,"prompt-answer");let s=o.boxes.find(h=>h.name===o.leadBox);if(!s)throw new Error(`track "${t}" has no lead box`);if(!await nt(o.leadBox))throw new Error(`lead box "${o.leadBox}" is not running`);let i=await Ad(s);if(i||(i=await uN(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 h=typeof r=="string"?r.trim():"";if(!h)throw new Error("this prompt needs a code \u2014 paste it into the card");if(/\s/.test(h)||h.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,h,{enter:!0,kind:"answer-prompt"}),c={mode:"text-input",value:"\u2039code\u203A",count:1,redacted:!0}}else if(i.answerMode==="esc")await _t(o.leadBox,["Escape"],{kind:"answer-prompt"}),c={mode:"keys",value:"Escape",count:1};else if(i.answerMode==="say"){let h=pg(i,n||[],typeof r=="string"?r:"");if(!h)throw new Error("no answer selected \u2014 pick an option or reply in chat");await we(o.id,h,{kind:"prompt-answer"}),c={mode:"say",value:h,count:1}}else if(i.provider==="claude"||i.answerMode==="keys"){let h=$y(i,n||[]);await _t(o.leadBox,h,{kind:"answer-prompt"}),c={mode:"keys",value:h.join(" "),count:h.length}}else{let h=jw(i,n||[]);await Pt(o.leadBox,h,{enter:!0,kind:"answer-prompt"}),c={mode:"text",value:h,count:1}}if(i.answerMode==="say"){let h=i.questions||[];for(let w=0;w<h.length;w++){let y=h[w],k=new Set(Array.isArray(n?.[w])?n[w]:[]),x=[...k].map(R=>y.options?.[R]).filter(Boolean).map(R=>({label:R.label,description:R.description||""})),A=(y.options||[]).map((R,V)=>k.has(V)?null:R?.label).filter(Boolean);Kd(o,s,i,{...c,groupId:i.groupId||i.promptId,questionIndex:w,questionTotal:i.questionTotal??h.length,header:y.header||"",question:y.question||"",multiSelect:!!y.multiSelect,chosen:x,rejected:A})}return await z({flow:"prompt",phase:"answered",sessionName:o.leadBox,agent:s.agent,provider:i.provider,promptId:i.promptId,...c}).catch(()=>{}),{ok:!0,promptId:i.promptId,sent:c.count}}let l=i.questions?.[0]||{},u=new Set(Array.isArray(n?.[0])?n[0]:[]),d=[...u].map(h=>l.options?.[h]).filter(Boolean).map(h=>({label:h.label,description:h.description||""})),f=(l.options||[]).map((h,w)=>u.has(w)?null:h?.label).filter(Boolean),p=i.review?"review":/^claude:model-confirm:/.test(i.promptId||"")?"model-confirm":/^claude:resume-confirm:/.test(i.promptId||"")?"resume-confirm":void 0;return c={...c,groupId:i.groupId||i.promptId,questionIndex:i.questionIndex??0,questionTotal:i.questionTotal??1,header:l.header||"",question:l.question||"",multiSelect:!!l.multiSelect,chosen:d,rejected:f,...p?{control:p}:{}},await z({flow:"prompt",phase:"answered",sessionName:o.leadBox,agent:s.agent,provider:i.provider,promptId:i.promptId,...c}).catch(()=>{}),Kd(o,s,i,c),{ok:!0,promptId:i.promptId,sent:c.count}}async function uN(t,e){if(!e)return null;let n=await B(t).catch(()=>[]);return Xu(br(n),{leadBoxId:e.name,provider:e.agent,isAnswered:r=>n.some(o=>o.type==="prompt.answered"&&o.payload?.promptId===r)})}async function Tp(t,{promptId:e,questionIndex:n}={}){let r=Z(await G(),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 nt(r.leadBox))throw new Error(`lead box "${r.leadBox}" is not running`);let a=await Ad(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=Oy(a,n);return c.length?(await _t(r.leadBox,c,{kind:"navigate-prompt"}),await z({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 zc(t){let e=Ta.get(t);return e||(e={items:[],timer:null,flushing:!1,idleSince:null},Ta.set(t,e)),e}function Jo(t){return(Ta.get(t)?.items??[]).map(e=>({...e}))}function Ma(t){let e=Ta.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 Ap(t){let e=Ma(t),n=e.filter(o=>o.text&&!o.kind).map(o=>o.text),r=null;if(n.length){let o=Z(await G(),t);if(o)return r=Yo(o,n),await Y(),{removed:e,restored:r,draftRev:o.draftRev||0}}return{removed:e,restored:r,draftRev:null}}function Ep(t){let e=zc(t);e.timer||(e.timer=setInterval(()=>fN(t).catch(()=>{}),dN))}async function fN(t){let e=Ta.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 G(),t);if(!n||n.archivedAt){Ma(t);return}let r=ts(t);if(r&&!r.finishedAt&&r.step!=="done"&&!r.error){Fr(e,!1);return}let o=await nt(n.leadBox);if(!o){Fr(e,!1);return}let s=n.boxes.find(c=>c.name===n.leadBox);if(Ir(s?.agent)){Fr(e,!1);return}let a=await xt(n.leadBox,{lines:Nt}).catch(()=>"");if(Bi(s?.agent,a)){Fr(e,!1);return}if(Er(s?.agent,a)){let c=await Ve(n.leadBox).catch(()=>a);if(Dn(s,c)){Fr(e,!1);return}}if(!Fr(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=Ir(e?.agent);if(!o)return;if(!r&&typeof n=="string"&&n.trim()&&(Yo(t,[n]),await Y()),Yy(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 pN(t,e){let n=await xt(t.leadBox,{lines:Nt}).catch(()=>"");if(!Er(e?.agent,n))return!1;let r=await Ve(t.leadBox).catch(()=>n);return!!Dn(e,r)}async function R0(t,e,n,r,o=null,s=null){await I0(t,e,r,o);let a=Aa.get(t.id)||0,i=r,c=!1,l=t.pendingHandoffHydrate||null;t.pendingHandoffHydrate&&(i=S0(r,t.pendingHandoffHydrate.artifact||Ur),delete t.pendingHandoffHydrate,c=!0);let u=Array.isArray(s)?s.filter(f=>f&&f.rel):[];if(u.length){let f=a0(u.map(p=>p.rel));i=i.trim()?`${i.trim()}
157
158
 
158
- ${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}:{}});Ho(t,null);try{if(await In({cwd:n.cwd,sessionId:n.sessionId,sessionName:t.leadBox,agent:n.agent,agentCmd:Sa(n.agent)}),(ha.get(t.id)||0)!==a){!o&&r.trim()&&(qo(t,[r]),await J());let d=new Error("delivery stopped \u2014 the message was handed back as the draft");throw d.interrupted=!0,d}await Pt(t.leadBox,i,{...$e(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 YM(t,e,i)||(await ix(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||qo(t,[r])),c&&await V({flow:"lead-handoff",phase:"first-prompt",trackId:t.id,sessionName:t.leadBox,agent:e?.agent,userTextLen:r.length})}function mp(t,{actions:e}={}){fp(t).items.push({id:ka(),text:ub(e),ts:Date.now(),kind:"ship-notify"}),rx(t)}async function me(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"||!bo(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(f=>f.name===s.leadBox),i=bo(e);await ox(s,a,i,n),Aa(t,"say");let c=await et(s.leadBox);if(!c&&await Hc(s)&&(await J(),c=await et(s.leadBox)),!c)throw new Error(`lead box "${s.leadBox}" is not running`);let l=fp(t),u=await Tt(s.leadBox,{lines:Nt}).catch(()=>""),d=l.items.length>0||Ii(a?.agent,u);if(!d&&yo(a?.agent,u)){let f=await En(s.leadBox).catch(()=>u);d=!!Sr(a,f)}if(d){let f={id:ka(),text:i,ts:Date.now(),...n?{kind:n}:{},...o.length?{attachments:o}:{}};return l.items.push(f),rx(t),Ho(s,null),await J(),{ok:!0,leadBox:s.leadBox,queued:!0,id:f.id,position:l.items.length}}return await sx(s,a,c,i,n,o),await J(),{ok:!0,leadBox:s.leadBox}}async function hp(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=df(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";uk(n.id,{name:s,box:n.leadBox});let a=String(e||"").trim()?`${q0}
159
+ ${f}`:f}let d=pt(t,"said",{box:t.leadBox,agent:e?.agent,boxRole:e?.role,text:r,...o?{kind:o}:{},...u.length?{attachments:u}:{}});zo(t,null);try{if(await On({cwd:n.cwd,sessionId:n.sessionId,sessionName:t.leadBox,agent:n.agent,agentCmd:Oa(n.agent),bailOnDialog:!0}),(Aa.get(t.id)||0)!==a){!o&&r.trim()&&(Yo(t,[r]),await Y());let f=new Error("delivery stopped \u2014 the message was handed back as the draft");throw f.interrupted=!0,f}if(await pN(t,e)){l&&(t.pendingHandoffHydrate=l);let f=zc(t.id),p={id:Qo(),text:r,ts:Date.now(),...o?{kind:o}:{},...u.length?{attachments:u}:{}};f.items.unshift(p),Ep(t.id);let h=new Error("lead is blocked on a prompt \u2014 message queued");throw h.requeued={id:p.id,position:f.items.length},h}await Pt(t.leadBox,i,{...Oe(e?.agent),kind:c?"lead-handoff-first-prompt":"say"})}catch(f){if(pt(t,"unsaid",{box:t.leadBox,agent:e?.agent,boxRole:e?.role,saidTs:d.at,text:r,...f?.interrupted?{reason:"interrupted"}:{},...f?.requeued?{reason:"requeued"}:{}}),f?.requeued)return{queued:!0,...f.requeued};throw f}await IN(t,e,i)||(await O0(t.leadBox,e?.agent,i.length+8).catch(()=>{}),pt(t,"unsaid",{box:t.leadBox,agent:e?.agent,boxRole:e?.role,saidTs:d.at,text:r,reason:"unsubmitted"}),o||Yo(t,[r])),c&&await z({flow:"lead-handoff",phase:"first-prompt",trackId:t.id,sessionName:t.leadBox,agent:e?.agent,userTextLen:r.length})}function _p(t,{actions:e}={}){zc(t).items.push({id:Qo(),text:Ab(e),ts:Date.now(),kind:"ship-notify"}),Ep(t)}async function we(t,e,{kind:n=null,attachments:r=null}={}){let o=Array.isArray(r)?r.filter(p=>p&&typeof p.rel=="string"):[];if((typeof e!="string"||!vo(e))&&!o.length)throw new Error("text (string) or an attachment required");let s=Z(await G(),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(p=>p.name===s.leadBox),i=vo(e);await I0(s,a,i,n),Na(t,"say");let c=await nt(s.leadBox);if(!c&&await Zc(s)&&(await Y(),c=await nt(s.leadBox)),!c)throw new Error(`lead box "${s.leadBox}" is not running`);let l=zc(t),u=await xt(s.leadBox,{lines:Nt}).catch(()=>""),d=l.items.length>0||Bi(a?.agent,u);if(!d&&Er(a?.agent,u)){let p=await Ve(s.leadBox).catch(()=>u);d=!!Dn(a,p)}if(d){let p={id:Qo(),text:i,ts:Date.now(),...n?{kind:n}:{},...o.length?{attachments:o}:{}};return l.items.push(p),Ep(t),zo(s,null),await Y(),{ok:!0,leadBox:s.leadBox,queued:!0,id:p.id,position:l.items.length}}let f=await R0(s,a,c,i,n,o);return await Y(),f?.queued?{ok:!0,leadBox:s.leadBox,queued:!0,id:f.id,position:f.position}:{ok:!0,leadBox:s.leadBox}}async function Ip(t,{hint:e}={}){let n=Z(await G(),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=Sf(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";Pk(n.id,{name:s,box:n.leadBox});let a=String(e||"").trim()?`${h0}
159
160
 
160
- What to preview: ${String(e).trim()}`:q0;try{await me(t,a,{kind:"spin-up-view"})}catch(i){throw gc(n.id,{error:"drive-failed"}),i}return{ok:!0,running:!0}}async function Lc(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`);ha.set(t,(ha.get(t)||0)+1);let n=Ta(t),r=n.filter(i=>i.text&&!i.kind).map(i=>i.text),o=Uo.get(t);if(o&&!o.canceled){o.clicks++;let i=null;return r.length&&(i=qo(e,r),await J()),{ok:!0,interrupted:!0,stopped:!1,stopping:!0,dropped:n.length,restored:i,draftRev:e.draftRev||0}}let s=UM(t,{droppedCount:n.length,droppedTexts:r});await Promise.race([s.settled,Vn(BM)]);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 ax(t){let e=Uo.get(t);return!!e&&!e.canceled}function Aa(t,e){let n=Uo.get(t);n&&!n.canceled&&(n.canceled=!0,n.cancelReason=e||null)}function wp(t){Aa(t,"track-ended"),ha.delete(t),Ta(t)}function UM(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}),Uo.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<DM&&!r.canceled;y++){await It(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.escSends++;for(let k of jM){await Vn(k);let x=await Tt(s.leadBox,{lines:Nt}).catch(()=>"");if(!Es(a?.agent,x)){c=!0;break t}}}if(!c){l=!0;for(let y=0;y<FM&&!r.canceled&&(await Vn(LM),!r.canceled);y++){let k=await Tt(s.leadBox,{lines:Nt}).catch(()=>"");if(!Es(a?.agent,k)){c=!0;break}await It(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.bgSends++}}}let u=Z(await K(),t)||s,d=u?.boxes.find(y=>y.name===u.leadBox)||a,f=null,h=null;u&&d&&i&&c&&!r.canceled&&(f=await KM(u,d).catch(()=>null),f||(h=await zM(u,d).catch(()=>null)));let p=u&&i&&!r.canceled?await WM(u).catch(()=>null):null,w=[f||h,...r.queuedTexts].filter(Boolean);u&&w.length&&(r.restored=qo(u,w),await J()),r.result=i?r.canceled?"canceled":c?l?"stopped-late":"stopped":"gave-up":"no-session",await HM(u||s,d,{ts:r.startedAt,result:r.result,dropped:e,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!f,lostRestored:!!h,queuedRestored:r.queuedTexts.length,shipDismissed:!!p,durationMs:Date.now()-r.startedAt,...r.cancelReason?{cancelReason:r.cancelReason}:{}}),await V({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:!!h,queuedRestored:r.queuedTexts.length,shipDismissed:!!p}).catch(()=>{})})().catch(()=>{}).finally(()=>{r.result||(r.result=r.canceled?"canceled":"gave-up"),Uo.get(t)===r&&Uo.delete(t),o()}),r}async function HM(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 WM(t){let e=Ac(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 KM(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 qM){await Vn(r);let o=await Tt(t.leadBox,{lines:Nt}).catch(()=>""),s=Ns(e.agent,o);if(s&&Cu(n.text,s))return await ix(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 zM(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>GM||n.some(s=>s.type==="unsaid"&&s.saidTs===r.at)||!Ot(r.text))return null;for(let s of VM){await Vn(s);let a;try{a=await ld(e,{})}catch{return null}if(Fw(a,r))return null;let i=await Tt(t.leadBox,{lines:Nt}).catch(()=>"");if(Ns(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 YM(t,e,n){if(e?.agent!=="claude")return!0;for(let r=0;r<=Qf;r++){let o=!1;for(let s of JM){await Vn(s);let a=await Tt(t.leadBox,{lines:Nt}).catch(()=>""),i=Uw(e.agent,n,a,{busy:Es(e.agent,a)});if(i==="stuck"){o=!0;break}if(i==="submitted")return!0}if(!o)return!0;r<Qf&&(await It(t.leadBox,["Enter"],{kind:"submit-retry"}),V({flow:"say",phase:"submit-retry",trackId:t.id,sessionName:t.leadBox,agent:e.agent,attempt:r+1,textHead:n.slice(0,120)}).catch(()=>{}))}return V({flow:"say",phase:"submit-failed",trackId:t.id,sessionName:t.leadBox,agent:e.agent,retries:Qf,textHead:n.slice(0,120)}).catch(()=>{}),!1}async function ix(t,e,n){for(let r=0;r<3;r++){await no(t,n,{kind:"unsend-wipe"}).catch(()=>{}),await Vn(200);let o=await Tt(t,{lines:Nt}).catch(()=>""),s=Ns(e,o);if(!s)return!0;n=s.length+8}return!1}function Ho(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 qo(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?Ho(t,n.join(`
161
+ What to preview: ${String(e).trim()}`:h0;try{await we(t,a,{kind:"spin-up-view"})}catch(i){throw Ec(n.id,{error:"drive-failed"}),i}return{ok:!0,running:!0}}async function Jc(t){let e=Z(await G(),t);if(!e)throw new Error(`track "${t}" not found`);if(e.archivedAt)throw new Error(`track "${t}" is archived`);Aa.set(t,(Aa.get(t)||0)+1);let n=Ma(t),r=n.filter(i=>i.text&&!i.kind).map(i=>i.text),o=Vo.get(t);if(o&&!o.canceled){o.clicks++;let i=null;return r.length&&(i=Yo(e,r),await Y()),{ok:!0,interrupted:!0,stopped:!1,stopping:!0,dropped:n.length,restored:i,draftRev:e.draftRev||0}}let s=bN(t,{droppedCount:n.length,droppedTexts:r});await Promise.race([s.settled,Yn(mN)]);let a=Z(await G(),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=Vo.get(t);return!!e&&!e.canceled}function Na(t,e){let n=Vo.get(t);n&&!n.canceled&&(n.canceled=!0,n.cancelReason=e||null)}function Rp(t){Na(t,"track-ended"),Aa.delete(t),Ma(t)}function bN(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}),Vo.set(t,r),(async()=>{let s=Z(await G(),t),a=s?.boxes.find(y=>y.name===s.leadBox),i=s?await nt(s.leadBox):null,c=!1,l=!1;if(i){t:for(let y=0;y<hN&&!r.canceled;y++){await _t(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.escSends++;for(let k of wN){await Yn(k);let x=await xt(s.leadBox,{lines:Nt}).catch(()=>"");if(!Ls(a?.agent,x)){c=!0;break t}}}if(!c){l=!0;for(let y=0;y<yN&&!r.canceled&&(await Yn(gN),!r.canceled);y++){let k=await xt(s.leadBox,{lines:Nt}).catch(()=>"");if(!Ls(a?.agent,k)){c=!0;break}await _t(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.bgSends++}}}let u=Z(await G(),t)||s,d=u?.boxes.find(y=>y.name===u.leadBox)||a,f=null,p=null;u&&d&&i&&c&&!r.canceled&&(f=await SN(u,d).catch(()=>null),f||(p=await EN(u,d).catch(()=>null)));let h=u&&i&&!r.canceled?await xN(u).catch(()=>null):null,w=[f||p,...r.queuedTexts].filter(Boolean);u&&w.length&&(r.restored=Yo(u,w),await Y()),r.result=i?r.canceled?"canceled":c?l?"stopped-late":"stopped":"gave-up":"no-session",await kN(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:!!h,durationMs:Date.now()-r.startedAt,...r.cancelReason?{cancelReason:r.cancelReason}:{}}),await z({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:!!h}).catch(()=>{})})().catch(()=>{}).finally(()=>{r.result||(r.result=r.canceled?"canceled":"gave-up"),Vo.get(t)===r&&Vo.delete(t),o()}),r}async function kN(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 xN(t){let e=Nc(await B(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 SN(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 vN){await Yn(r);let o=await xt(t.leadBox,{lines:Nt}).catch(()=>""),s=qs(e.agent,o);if(s&&Uu(n.text,s))return await O0(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 EN(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>TN||n.some(s=>s.type==="unsaid"&&s.saidTs===r.at)||!$t(r.text))return null;for(let s of AN){await Yn(s);let a;try{a=await yd(e,{})}catch{return null}if(eg(a,r))return null;let i=await xt(t.leadBox,{lines:Nt}).catch(()=>"");if(qs(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 IN(t,e,n){if(e?.agent!=="claude")return!0;for(let r=0;r<=dp;r++){let o=!1;for(let s of _N){await Yn(s);let a=await xt(t.leadBox,{lines:Nt}).catch(()=>""),i=ng(e.agent,n,a,{busy:Ls(e.agent,a)});if(i==="stuck"){o=!0;break}if(i==="submitted")return!0}if(!o)return!0;r<dp&&(await _t(t.leadBox,["Enter"],{kind:"submit-retry"}),z({flow:"say",phase:"submit-retry",trackId:t.id,sessionName:t.leadBox,agent:e.agent,attempt:r+1,textHead:n.slice(0,120)}).catch(()=>{}))}return z({flow:"say",phase:"submit-failed",trackId:t.id,sessionName:t.leadBox,agent:e.agent,retries:dp,textHead:n.slice(0,120)}).catch(()=>{}),!1}async function O0(t,e,n){for(let r=0;r<3;r++){await io(t,n,{kind:"unsend-wipe"}).catch(()=>{}),await Yn(200);let o=await xt(t,{lines:Nt}).catch(()=>""),s=qs(e,o);if(!s)return!0;n=s.length+8}return!1}function zo(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 Yo(t,e){let n=[],r=o=>n.some(s=>$t(s).includes($t(o)));for(let o of[t.draft?.text,...e])o&&o.trim()&&!r(o)&&n.push(o);return n.length?zo(t,n.join(`
161
162
 
162
- `),{source:"restore"})?.text??null:null}function ZM(t,e){let n=Ot(e);if(!n)return!1;if(Wo(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>XM)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 gp(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=bo(e);if(typeof n=="number"&&n<(r.draftRev||0)&&s&&ZM(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))?Ho(r,o):Ho(r,`${i}
163
+ `),{source:"restore"})?.text??null:null}function $N(t,e){let n=$t(e);if(!n)return!1;if(Jo(t.id).some(o=>$t(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>RN)break;if(!(s.type!=="said"||!s.text||$t(s.text)!==n))return!r.some(a=>a.type==="unsaid"&&a.saidTs===s.at)}return!1}async function $p(t,e,{rev:n=null}={}){if(typeof e!="string")throw new Error("text (string) required");let r=Z(await G(),t);if(!r)throw new Error(`track "${t}" not found`);let o=e,s=vo(e);if(typeof n=="number"&&n<(r.draftRev||0)&&s&&$N(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;$t(o).includes($t(i))?zo(r,o):zo(r,`${i}
163
164
 
164
- ${o}`,{source:"restore"})}else Ho(r,o);return await J(),{ok:!0,draft:r.draft||null,rev:r.draftRev||0}}async function yp(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(d=>d.name===r.leadBox)?.agent||o.agent||"claude",i=Gy(a,n),l=[...r.events||[]].reverse().find(d=>d.type==="model-change")?.to??null;l||(l=(await vs(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:Sa(o.agent)});let u=await Vy(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 cx(t){for(let e of t){if(!e||!await Ki(e))continue;let n=await vy(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 Io(t){let e=[];for(let n of ae(t?.workspace)){if(!n?.dir)continue;let r=await vd(n.dir,{ignorePlumbing:!0}).catch(()=>!1),o=await Td(n.dir,n.baseRef).catch(()=>0);(r||o>0)&&e.push({...n,dirty:r,ahead:o})}return e}async function lx(t){let e=t;typeof e=="string"&&!W.isAbsolute(e)&&/^[^/\s]+\/[^/\s]+$/.test(e)&&(e=await Vr(e)??await si(e));let n=await cx([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 QM(t,e,n,r){let o=`track/${Pp(e)}-${t}`,s=[];try{await H.mkdir(n,{recursive:!0});let a=new Set([".bostrat"]);for(let i of r){let c=await lx(i);if(s.some(h=>h.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 h=2;a.has(u);h++)u=`${W.basename(c)}-${h}`;a.add(u);let d=W.join(n,u),f=await So(c);await xo(c,d,o,f),s.push({name:u,dir:d,base:c,baseRef:f,repo:l})}return await Ea(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 bp(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 lx(typeof e=="string"?e.trim():e);if((o.repos??[]).some(f=>f?.base===s))throw new Error(`repo already tagged: ${e}`);let a=await lt(s).catch(()=>null),i=new Set([".bostrat",...(o.repos??[]).map(f=>f?.name).filter(Boolean)]),c=W.basename(s);i.has(c)&&a&&(c=a.replace("/","-"));for(let f=2;i.has(c);f++)c=`${W.basename(s)}-${f}`;let l=W.join(o.dir,c),u=await So(s);await Ty(s,o.branch)?await Gi(s,l,o.branch):await xo(s,l,o.branch,u);let d={name:c,dir:l,base:s,baseRef:u,repo:a};return o.repos=[...(o.repos??[]).filter(Boolean),d],await Ea(o.dir,o.repos,o.branch),pt(r,"retagged",{action:"add",repo:a??s,name:c,workspace:ux(o)}),await J(),d}async function kp(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 vd(s.dir,{ignorePlumbing:!0}).catch(()=>!1),i=await Td(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 Ea(o.dir,o.repos,o.branch),pt(r,"retagged",{action:"remove",repo:s.repo??s.base,name:s.name,workspace:ux(o)}),await J(),{removed:s.name}}async function tN(t,e,{repo:n,repos:r,cwd:o}={}){await H.mkdir(fa,{recursive:!0});let s=W.join(fa,t),a=Array.isArray(r)?r.map(c=>typeof c=="string"?c.trim():"").filter(Boolean):[];if(a.length>=2)return QM(t,e,s,a);a.length===1&&!n&&(n=a[0]),typeof n=="string"&&!W.isAbsolute(n)&&/^[^/\s]+\/[^/\s]+$/.test(n)&&(n=await Vr(n)??await si(n));let i=await cx([n,o,kM]);if(i){let c=`track/${Pp(e)}-${t}`;try{let l=await So(i);await xo(i,s,c,l),await ga(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 Ad(s),await ga(s),{dir:s,base:null,branch:null,kind:"repo"}}async function ga(t){try{await H.writeFile(W.join(t,"AGENTS.md"),da,{flag:"wx"})}catch{return}await oN(t,["/AGENTS.md"])}function rN(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`${nN}
165
+ ${o}`,{source:"restore"})}else zo(r,o);return await Y(),{ok:!0,draft:r.draft||null,rev:r.draftRev||0}}async function Op(t,e){if(typeof e!="string"||!e.trim())throw new Error("model (string) required");let n=e.trim(),r=Z(await G(),t);if(!r)throw new Error(`track "${t}" not found`);let o=await nt(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=ib(a,n),l=[...r.events||[]].reverse().find(d=>d.type==="model-change")?.to??null;l||(l=(await Cs(o.cwd,o.sessionId,{fallbackNewest:!1}).catch(()=>null))?.model??null),await On({cwd:o.cwd,sessionId:o.sessionId,sessionName:r.leadBox,agent:o.agent,agentCmd:Oa(o.agent)});let u=await cb(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 C0(t){for(let e of t){if(!e||!await Qi(e))continue;let n=await jy(e).catch(()=>null);if(!n)continue;if((await W.stat(q.join(n,".git")).catch(()=>null))?.isDirectory())return n}return null}function ie(t){let e=t;return e?e.kind==="multi"?Array.isArray(e.repos)?e.repos.filter(Boolean):[]:e.base?[{name:q.basename(e.base),dir:e.dir??null,base:e.base,baseRef:e.baseRef??null,repo:e.repo??null}]:[]:[]}async function No(t){let e=[];for(let n of ie(t?.workspace)){if(!n?.dir)continue;let r=await Cd(n.dir,{ignorePlumbing:!0}).catch(()=>!1),o=await Md(n.dir,n.baseRef).catch(()=>0);(r||o>0)&&e.push({...n,dirty:r,ahead:o})}return e}async function M0(t){let e=t;typeof e=="string"&&!q.isAbsolute(e)&&/^[^/\s]+\/[^/\s]+$/.test(e)&&(e=await Zr(e)??await fi(e));let n=await C0([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 ON(t,e,n,r){let o=`track/${zp(e)}-${t}`,s=[];try{await W.mkdir(n,{recursive:!0});let a=new Set([".bostrat"]);for(let i of r){let c=await M0(i);if(s.some(p=>p.base===c))throw new Error(`repo tagged twice: ${i}`);let l=await ut(c).catch(()=>null),u=q.basename(c);a.has(u)&&l&&(u=l.replace("/","-"));for(let p=2;a.has(u);p++)u=`${q.basename(c)}-${p}`;a.add(u);let d=q.join(n,u),f=await Ao(c);await To(c,d,o,f),s.push({name:u,dir:d,base:c,baseRef:f,repo:l})}return await Pa(n,s,o),{dir:n,kind:"multi",branch:o,repos:s}}catch(a){for(let i of s)await oe(i.base,i.dir).catch(()=>{});throw await W.rm(n,{recursive:!0,force:!0}).catch(()=>{}),a}}async function Cp(t,e){let n=await G(),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 M0(typeof e=="string"?e.trim():e);if((o.repos??[]).some(f=>f?.base===s))throw new Error(`repo already tagged: ${e}`);let a=await ut(s).catch(()=>null),i=new Set([".bostrat",...(o.repos??[]).map(f=>f?.name).filter(Boolean)]),c=q.basename(s);i.has(c)&&a&&(c=a.replace("/","-"));for(let f=2;i.has(c);f++)c=`${q.basename(s)}-${f}`;let l=q.join(o.dir,c),u=await Ao(s);await Ly(s,o.branch)?await tc(s,l,o.branch):await To(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 Pa(o.dir,o.repos,o.branch),pt(r,"retagged",{action:"add",repo:a??s,name:c,workspace:N0(o)}),await Y(),d}async function Mp(t,e){let n=await G(),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 ae.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 Cd(s.dir,{ignorePlumbing:!0}).catch(()=>!1),i=await Md(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 oe(s.base,s.dir).catch(()=>{}),await W.rm(s.dir,{recursive:!0,force:!0}).catch(()=>{}),o.repos=(o.repos??[]).filter(c=>c&&c!==s),await Pa(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 CN(t,e,{repo:n,repos:r,cwd:o}={}){await W.mkdir(va,{recursive:!0});let s=q.join(va,t),a=Array.isArray(r)?r.map(c=>typeof c=="string"?c.trim():"").filter(Boolean):[];if(a.length>=2)return ON(t,e,s,a);a.length===1&&!n&&(n=a[0]),typeof n=="string"&&!q.isAbsolute(n)&&/^[^/\s]+\/[^/\s]+$/.test(n)&&(n=await Zr(n)??await fi(n));let i=await C0([n,o,XM]);if(i){let c=`track/${zp(e)}-${t}`;try{let l=await Ao(i);await To(i,s,c,l),await _a(s);let u=await ut(i).catch(()=>null);return{dir:s,base:i,branch:c,kind:"worktree",baseRef:l,repo:u}}catch{await W.rm(s,{recursive:!0,force:!0}).catch(()=>{})}}return await W.mkdir(s,{recursive:!0}),await Nd(s),await _a(s),{dir:s,base:null,branch:null,kind:"repo"}}async function _a(t){try{await W.writeFile(q.join(t,"AGENTS.md"),xa,{flag:"wx"})}catch{return}await BN(t,["/AGENTS.md"])}function PN(t,e){let n=t.map(r=>`- \`${r.name}/\`${r.repo?` \u2014 github.com/${r.repo}`:""}${r.baseRef?` (forked from ${r.baseRef})`:""}`).join(`
166
+ `);return`${NN}
166
167
 
167
168
  This directory is NOT a git repo. It is a bostrat Track workspace holding one
168
169
  git worktree per tagged repo, ALL on the same branch \`${e}\`:
@@ -174,20 +175,20 @@ push / open PRs) in each repo separately, always on that shared branch. Work
174
175
  only needs to land in the repos it actually touches \u2014 an untouched repo's
175
176
  branch simply stays at its fork point and never gets pushed. When asked to run
176
177
  or preview an app, run it from that app's own repo directory.
177
- `}async function Ea(t,e,n){let r=rN(e,n);for(let o of["CLAUDE.md","AGENTS.md"])await H.writeFile(W.join(t,o),r).catch(()=>{})}async function fx(t){let{stdout:e}=await z0("git",["-C",t,"rev-parse","--git-path","info/exclude"]);return W.resolve(t,e.trim())}async function oN(t,e){try{let n=await fx(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(`
178
+ `}async function Pa(t,e,n){let r=PN(e,n);for(let o of["CLAUDE.md","AGENTS.md"])await W.writeFile(q.join(t,o),r).catch(()=>{})}async function B0(t){let{stdout:e}=await b0("git",["-C",t,"rev-parse","--git-path","info/exclude"]);return q.resolve(t,e.trim())}async function BN(t,e){try{let n=await B0(t);await W.mkdir(q.dirname(n),{recursive:!0});let r=await W.readFile(n,"utf8").catch(()=>""),o=e.filter(s=>!r.split(`
179
+ `).includes(s));o.length&&await W.appendFile(n,(r.endsWith(`
179
180
  `)||!r?"":`
180
181
  `)+o.join(`
181
182
  `)+`
182
- `)}catch{}}async function sN(t,e){try{let n=await fx(t),r=await H.readFile(n,"utf8"),o=r.split(`
183
+ `)}catch{}}async function DN(t,e){try{let n=await B0(t),r=await W.readFile(n,"utf8"),o=r.split(`
183
184
  `).filter(s=>s!==e);o.length!==r.split(`
184
- `).length&&await H.writeFile(n,o.join(`
185
- `))}catch{}}async function xp(){let t={refreshed:0,removed:0,codexGlobal:null};try{await H.mkdir(fn,{recursive:!0}),await H.writeFile(W.join(fn,"CLAUDE.md"),eN).catch(()=>{}),await H.writeFile(W.join(fn,"AGENTS.md"),da).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,ep,{flag:"wx"}).catch(()=>{}),t.codexGlobal="created"):tp(o)&&o!==ep&&(await H.writeFile(r,ep).catch(()=>{}),t.codexGlobal="refreshed")}for(let r of[fa,Go]){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&&tp(c)&&c!==da&&(await H.writeFile(i,da).catch(()=>{}),t.refreshed++);let l=W.join(a,"CLAUDE.md"),u=await H.readFile(l,"utf8").catch(()=>null);u!==null&&tp(u)&&(await H.rm(l,{force:!0}).catch(()=>{}),await sN(a,"/CLAUDE.md"),t.removed++)}}}catch{}return t}async function px(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 Fc({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 va(o,s),i=await K(),c=ka().slice(0,8),l=await tN(c,t,{repo:n,repos:r,cwd:e}),u=new Set(i.tracks.flatMap(p=>(p.boxes||[]).map(w=>w.name))),d=`${t.trim()} lead`;u.has(ki(d))&&(d=`${t.trim().slice(0,50).trim()} ${c} lead`);let f=await An(d,l.dir,{agentCmd:a,agent:o});_s({cwd:f.cwd,sessionName:f.name,agent:o,agentCmd:a});let h={id:c,name:t.trim(),cwd:f.cwd,workspace:l,leadBox:f.name,boxes:[Ip(f,"lead","live")],events:[],createdAt:Date.now()};return pt(h,"opened",{agent:o,box:f.name,skipPermissions:s,name:h.name,cwd:h.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:p,base:w,baseRef:y,repo:k})=>({name:p,base:w,baseRef:y,repo:k}))}:{}}}),i.tracks.push(h),await J(),Fe(h)}async function Sp({provider:t="claude",fresh:e=!1}={}){if(!aN.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(f=>f.name===u.leadBox)?.state==="live")return u}await Dr(r.id).catch(()=>{})}let o=(await va(t,!1)).replace(/\s+--(?:dangerously-skip-permissions|dangerously-bypass-approvals-and-sandbox)\b/g,""),s=ka().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"&&_s({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:[Ip(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 vp(t,e,n){await gk(t).catch(()=>{});let r=Ko.get(t);r&&!r.finishedAt&&(r.error=n,r.finishedAt=Date.now()),Ko.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 jp(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 Tp(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 Qk(s),wp(t),await vp(t,s,"track deleted"),n?await $0(t).catch(()=>{}):await R0(t).catch(()=>{}),await Yy(),await px(s),e&&await t0(t).catch(()=>{}),e?await g0(t).catch(()=>{}):await w0(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 Dr(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(),wp(t),pt(n,"archived",{boxes:n.boxes.length}),await J(),n.kind==="setup"?(await mx(t),Fe(n)):(ya.add(t),lN(t).catch(()=>{}).finally(()=>ya.delete(t)),{...await Fe(n),archiving:!0})}async function lN(t){try{await uN(t)}catch{}await mx(t).catch(()=>{})}async function mx(t){let e=await K(),n=Z(e,t);if(!(!n||!n.archivedAt)){await vp(t,n,"track archived");for(let r of n.boxes)Gn.has(r.state)||(r.state="stopped");await J()}}async function uN(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 Sg(n.leadBox,i.cwd,{timeoutMs:cN})),s="lead-cli"}catch{}if(r||(r=Bg(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 Gt(t,e).catch(()=>null);if(!n?.archiveOnMerge||!n.trackId)return!1;let r=await hx(n);if(r.length){for(let o of r)await _r(o.repo,o.number,!0).catch(()=>{});return!1}try{return await Dr(n.trackId),!0}catch(o){if(/already archived/i.test(String(o?.message||o)))return!1;throw o}}async function hx(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 Uc(t,e,"merged")}async function Uc(t,e,n="merged"){let r=await Gt(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 hx(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 me(r.trackId,wx(a),{kind:"merge-notify"}),!0}catch{return!1}}function wx(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 ${K0[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 ${K0[i.outcome]??i.outcome}`).join(`
185
+ `).length&&await W.writeFile(n,o.join(`
186
+ `))}catch{}}async function Np(){let t={refreshed:0,removed:0,codexGlobal:null};try{await W.mkdir(hn,{recursive:!0}),await W.writeFile(q.join(hn,"CLAUDE.md"),MN).catch(()=>{}),await W.writeFile(q.join(hn,"AGENTS.md"),xa).catch(()=>{});let e=process.env.CODEX_HOME||q.join(process.env.HOME||"/tmp",".codex");if((await W.stat(e).catch(()=>null))?.isDirectory()){let r=q.join(e,"AGENTS.md"),o=await W.readFile(r,"utf8").catch(()=>null);o===null?(await W.writeFile(r,pp,{flag:"wx"}).catch(()=>{}),t.codexGlobal="created"):fp(o)&&o!==pp&&(await W.writeFile(r,pp).catch(()=>{}),t.codexGlobal="refreshed")}for(let r of[va,Zo]){let o=await W.readdir(r,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(!s.isDirectory())continue;let a=q.join(r,s.name),i=q.join(a,"AGENTS.md"),c=await W.readFile(i,"utf8").catch(()=>null);c!==null&&fp(c)&&c!==xa&&(await W.writeFile(i,xa).catch(()=>{}),t.refreshed++);let l=q.join(a,"CLAUDE.md"),u=await W.readFile(l,"utf8").catch(()=>null);u!==null&&fp(u)&&(await W.rm(l,{force:!0}).catch(()=>{}),await DN(a,"/CLAUDE.md"),t.removed++)}}}catch{}return t}async function D0(t){let e=t.workspace;if(!(!e||!e.dir))try{if(e.kind==="multi"){for(let n of ie(e))n.base&&n.dir&&await oe(n.base,n.dir).catch(()=>{});await W.rm(e.dir,{recursive:!0,force:!0})}else e.kind==="worktree"&&e.base?await oe(e.base,e.dir):await W.rm(e.dir,{recursive:!0,force:!0})}catch{}}async function Yc({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 Ca(o,s),i=await G(),c=Qo().slice(0,8),l=await CN(c,t,{repo:n,repos:r,cwd:e}),u=new Set(i.tracks.flatMap(h=>(h.boxes||[]).map(w=>w.name))),d=`${t.trim()} lead`;u.has(_i(d))&&(d=`${t.trim().slice(0,50).trim()} ${c} lead`);let f=await In(d,l.dir,{agentCmd:a,agent:o});Fs({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:[Up(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:h,base:w,baseRef:y,repo:k})=>({name:h,base:w,baseRef:y,repo:k}))}:{}}}),i.tracks.push(p),await Y(),Ue(p)}async function Pp({provider:t="claude",fresh:e=!1}={}){if(!jN.has(t))throw new Error(`unknown setup provider "${t}" (claude | codex | cursor)`);let r=(await G()).tracks.find(u=>u.kind==="setup"&&u.setup?.provider===t&&!u.archivedAt);if(r){if(!e){let u=await Ue(r);if(u.boxes.find(f=>f.name===u.leadBox)?.state==="live")return u}await Hr(r.id).catch(()=>{})}let o=(await Ca(t,!1)).replace(/\s+--(?:dangerously-skip-permissions|dangerously-bypass-approvals-and-sandbox)\b/g,""),s=Qo().slice(0,8),a=q.join(hn,"setup",s);await W.mkdir(a,{recursive:!0});let i=await In(`Connect ${t} ${s}`,a,{agentCmd:o,agent:t,firstRun:!0});t==="codex"&&Fs({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:[Up(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 G()).tracks.push(c),await Y(),Ue(c)}async function Bp(t,e,n){await Hk(t).catch(()=>{});let r=Xo.get(t);r&&!r.finishedAt&&(r.error=n,r.finishedAt=Date.now()),Xo.delete(t),e.handoff&&!e.handoff.finishedAt&&(e.handoff.step="error",e.handoff.error=n,e.handoff.finishedAt=Date.now());for(let a of Wr(t))a.finishedAt||(a.canceled=!0,a.finishedAt=Date.now()),await Xp(a).catch(()=>{}),ae.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 G(),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 Dp(t,{cascadeMocks:e=!0,cascadeRunbooks:n=!1}={}){let r=await G(),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 Tx(s),Rp(t),await Bp(t,s,"track deleted"),n?await e0(t).catch(()=>{}):await t0(t).catch(()=>{}),await db(),await D0(s),e&&await Ax(t).catch(()=>{}),e?await Hx(t).catch(()=>{}):await Ux(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 Hr(t){let e=await G(),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(),Rp(t),pt(n,"archived",{boxes:n.boxes.length}),await Y(),n.kind==="setup"?(await j0(t),Ue(n)):(Ia.add(t),UN(t).catch(()=>{}).finally(()=>Ia.delete(t)),{...await Ue(n),archiving:!0})}async function UN(t){try{await HN(t)}catch{}await j0(t).catch(()=>{})}async function j0(t){let e=await G(),n=Z(e,t);if(!(!n||!n.archivedAt)){await Bp(t,n,"track archived");for(let r of n.boxes)Jn.has(r.state)||(r.state="stopped");await Y()}}async function HN(t){let e=await G(),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 nt(n.leadBox).catch(()=>null):null;if(i?.cwd&&a)try{({text:r,items:o}=await Dg(n.leadBox,i.cwd,{timeoutMs:FN})),s="lead-cli"}catch{}if(r||(r=Xg(n,await B(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 tn(t,e){let n=await Vt(t,e).catch(()=>null);if(!n?.archiveOnMerge||!n.trackId)return!1;let r=await L0(n);if(r.length){for(let o of r)await Or(o.repo,o.number,!0).catch(()=>{});return!1}try{return await Hr(n.trackId),!0}catch(o){if(/already archived/i.test(String(o?.message||o)))return!1;throw o}}async function L0(t){return(await Cr().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 en(t,e){return Xc(t,e,"merged")}async function Xc(t,e,n="merged"){let r=await Vt(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 L0(r);if(s.length){let i=[...r.notifyPending||[],o];for(let c of s)await Wb(c.repo,c.number,i).catch(()=>{});return!1}let a=[...r.notifyPending||[],o];try{return await we(r.trackId,F0(a),{kind:"merge-notify"}),!0}catch{return!1}}function F0(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 ${w0[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 ${w0[i.outcome]??i.outcome}`).join(`
186
187
  `),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}
187
188
  ${s}
188
- ${a}`}async function Hc(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=cp(e.agent,e.sessionId),r=await bi(n);if(r===Zr)return pt(t,"rehydrate-failed",{box:e.name,agent:e.agent,reason:`agent "${e.agent}" is not installed on this box`}),!1;r===Qr&&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=is(o.hookToken),_s({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 Ap(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,ya.delete(t),pt(n,"unarchived",{}),await Hc(n),await J(),Fe(n)}async function Ep(){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 Wc(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(Ii(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 Hc(n);if(await J(),!s)throw new Error("rehydrate failed \u2014 see the track's rehydrate-failed event");return Fe(n)}async function _p(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 Wc(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 qc(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 Nc(t,e){let n=await K(),r=Z(n,t);r&&(r.handoff={...r.handoff||{},...e},await J())}function gx(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 Rp(){let t=await K(),e=!1;for(let n of t.tracks||[]){let r=n.handoff,o=gx(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(),d=qc(l),f=d[d.length-1],h=f.agent,p=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:Br,at:u},pt(n,"lead-handoff",{from:r.fromBox,to:r.fromBox,fromAgent:h,toAgent:r.toAgent,fromSessionId:p,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 V({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 V({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 Kc(t,e,n=!0,r=null){let o=Ko.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`);Aa(t,"handoff");let a=await va(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:Q0(r),toBox:s.leadBox,startedAt:Date.now(),finishedAt:null,error:null};return Ko.set(t,l),await Nc(t,{step:l.step,fromBox:l.fromBox,toAgent:e,toBox:l.toBox,skipPermissions:n,startedAt:l.startedAt,finishedAt:null,error:null}),dN(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 Nc(t,{step:l.step,error:l.error,finishedAt:l.finishedAt}).catch(()=>{}),V({flow:"lead-handoff",phase:"failed",trackId:t,step:l.step,error:l.error,fromBox:l.fromBox,toAgent:l.toAgent,toBox:l.toBox}).catch(()=>{})}),V({flow:"lead-handoff",phase:"started",trackId:t,fromBox:l.fromBox,toAgent:e,cwd:c.cwd}).catch(()=>{}),l}async function dN(t,e,n,r,o){let s=async($,G={})=>{t.step=$,console.log(`[lead-handoff ${t.trackId}] step \u2192 ${$}`),await Nc(t.trackId,{step:$,toBox:t.toBox}),await V({flow:"lead-handoff",phase:$,trackId:t.trackId,fromBox:t.fromBox,toBox:t.toBox,toAgent:o,sessionName:G.sessionName,...G})};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($=>$.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 Vu(t.fromBox,{timeoutMs:X0})}catch($){t.checkpoint="reconstructed",await V({flow:"lead-handoff",phase:"checkpoint-fallback",trackId:t.trackId,fromBox:t.fromBox,error:$?.message||String($)}).catch(()=>{})}t.checkpoint!=="llm"&&(t.statusArtifact=await zu(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 td(t.fromBox,{agentCmd:r,agent:o});await s("hydrate",{sessionName:t.fromBox}),await In({cwd:n.cwd,sessionId:f.sessionId,sessionName:t.fromBox,agent:o,agentCmd:Sa(o)});let h=await Tt(t.fromBox,{lines:Nt}).catch(()=>"");if(!Ri(o,h)){await s("rollback",{sessionName:t.fromBox,fromAgent:c});let $=cp(c,l,{skipPermissions:t.skipPermissions});await td(t.fromBox,{agentCmd:$,agent:c,resumeSessionId:l,pinned:u});let G=await K(),C=Z(G,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 p=await K(),w=Z(p,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($=>$.name===t.fromBox);if(!y)throw new Error(`lead box row "${t.fromBox}" missing during handoff commit`);let k=Date.now(),x=qc(y),E=x[x.length-1];E.endedAt=k,t.reason&&(E.endReason=t.reason),x.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||Br,at:k},pt(w,"lead-handoff",{from:t.fromBox,to:t.fromBox,fromAgent:c,toAgent:o,fromSessionId:l,toSessionId:f.sessionId,epoch:x.length-1,singleBox:!0,forced:f.forced||void 0,skipPermissions:t.skipPermissions,reason:t.reason,handoffStartedAt:t.startedAt,checkpoint:t.checkpoint}),await J(),await s("done",{sessionName:t.fromBox}),await Nc(t.trackId,{finishedAt:Date.now(),error:null}),t.finishedAt=Date.now()}async function Op(t){let e=ip.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=Ko.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 ip.set(t,s),fN(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 fN(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 Vu(e.leadBox,{timeoutMs:X0})}catch{t.checkpoint="reconstructed"}t.checkpoint!=="llm"&&await zu(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 d={name:u.name??null,repo:u.repo??null,baseSha:null,pushed:!1};try{await dn(u.dir,["push","origin",o],ap);let{stdout:f}=await dn(u.dir,["rev-parse","HEAD"]);d.baseSha=f.trim(),d.pushed=!0}catch(f){d.error=String(f?.message||f).split(`
189
- `)[0]}s.push(d)}t.step="wip";let a=await Gf({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&&qc(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:d,baseSha:f})=>({name:u,repo:d,baseSha:f})),unpushed:s.filter(u=>!u.pushed).map(({name:u,repo:d,error:f})=>({name:u,repo:d,error:f})),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 Gc(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};wp(t),await vp(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 Vf({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 Cp(t){let e=[];for(let n of Array.isArray(t)?t:[])if(!(!n?.id||!n?.toNode))try{let r=await Gc(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 G0(t,e,n){try{await Gi(t,e,n)}catch{await dn(t,["worktree","prune"]).catch(()=>{}),await Gi(t,e,n)}return e}async function Mp(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(np.has(e))throw new Error("an adopt is already running for this Track");np.set(e,{startedAt:Date.now()});try{return await pN({...t,trackId:e,name:n,agent:r,skipPermissions:o,mode:s})}finally{np.delete(e)}}async function pN({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:d=[],createdAt:f=null,leadBox:h=null,reason:p=null}){let w=await va(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 Vf({id:k.id,cwd:k.cwd}).catch(()=>{}),await px(k),y.tracks.splice(y.tracks.indexOf(k),1),await J()),await H.mkdir(fa,{recursive:!0});let x=W.join(fa,t);await H.rm(x,{recursive:!0,force:!0}).catch(()=>{});let E=null,$=!1,G=[];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 Vr(m)??await si(m);await dn(v,["fetch","origin",`+refs/heads/${i}:refs/heads/${i}`],ap),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 G0(g,x,i),G.push({base:g,dir:x}),await ga(x);let v=await So(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 O=v.name||W.basename(v.base);g.has(O)&&(O=v.slug.replace("/","-"));for(let mt=2;g.has(O);mt++)O=`${W.basename(v.base)}-${mt}`;g.add(O);let it=W.join(x,O);await G0(v.base,it,i),G.push({base:v.base,dir:it});let ct=await So(v.base);m.push({name:O,dir:it,base:v.base,baseRef:ct,repo:v.slug})}await Ea(x,m,i),E={dir:x,kind:"multi",branch:i,repos:m}}else $=!0,await H.mkdir(x,{recursive:!0}),await Ad(x),await ga(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||Kf(t)],ap);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 U0({id:t,cwd:x}).catch(()=>({restored:!1}));let B=W.join(x,Br),j=null;(await pi(x)).restored?j="checkpoint":typeof u=="string"&&u.trim()&&(await H.mkdir(W.dirname(B),{recursive:!0}),await H.writeFile(B,u),j="brief");let rt=new Set(y.tracks.flatMap(g=>(g.boxes||[]).map(m=>m.name))),A=null;h&&!rt.has(h)&&!await et(h).catch(()=>null)?A=h:(A=`${e.trim()} lead`,rt.has(ki(A))&&(A=`${e.trim().slice(0,50).trim()} ${t} lead`));let D=await An(A,x,{agentCmd:w,agent:n});_s({cwd:D.cwd,sessionName:D.name,agent:n,agentCmd:w});let X=Date.now(),bt=Ip(D,"lead","live"),dt=(Array.isArray(d)?d:[]).filter(g=>g&&typeof g=="object").map(g=>({...g})),kt=dt[dt.length-1];kt&&kt.endedAt==null&&(kt.endedAt=X,kt.endReason==null&&(kt.endReason=o==="recover"?"node-offline":"node-transfer")),dt.push({agent:n,sessionId:D.sessionId??null,pinned:D.pinned===!0,startedAt:X,endedAt:null}),bt.epochs=dt;let xt={id:t,name:e.trim(),cwd:D.cwd,workspace:E,leadBox:D.name,boxes:[bt],events:[],createdAt:Number.isFinite(f)?f:X,...j?{pendingHandoffHydrate:{artifact:Br,at:X}}:{}};return pt(xt,"transferred-in",{box:D.name,agent:n,fromNode:s,toNode:a,mode:o,reason:p,branch:E.branch??null,wip:N,epoch:dt.length-1,name:xt.name,cwd:xt.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:O})=>({name:g,base:m,baseRef:v,repo:O}))}:{}}}),y.tracks.push(xt),await J(),{...await Fe(xt),adopt:{wipApplied:N,wipSkipped:T,codeless:$,artifactSource:j}}}catch(C){for(let N of G)await re(N.base,N.dir).catch(()=>{});throw await H.rm(x,{recursive:!0,force:!0}).catch(()=>{}),C}}async function yx(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 Fo(t,e){t.step=e,await _a(t)}function bx(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 kx(t){return!!t&&!t.finishedAt&&!t.canceled&&t.step==="working"&&!!t.box&&!!t.dir&&!!t.base&&!!t.branch}async function gN(t,e,n){if(!kx(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),Sx(s,o).catch(a=>xx(s,a)),!0}async function Np(){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 gN(n,r,o)){e=!0,pt(n,"subtask-resumed",{box:o.box,agent:o.agent,task:o.task,subtaskId:r,resumedStep:o.step}),await V({flow:"subtask",phase:"resumed",trackId:n.id,subtaskId:r,box:o.box,branch:o.branch}).catch(()=>{});continue}let s=o.step,a=bx(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 V({flow:"subtask",phase:"reconciled",trackId:n.id,subtaskId:r,outcome:a.step,recovered:a.recovered,box:o.box,branch:o.branch}).catch(()=>{}),await V0(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(Go,`${n.id}-${r.subtaskId}`):null;await V({flow:"subtask",phase:"reaped-legacy-orphan",trackId:n.id,subtaskId:r.subtaskId,box:r.name}).catch(()=>{}),await V0(n,r.name,o)}}return e=await yN(t)||e,e&&await J(),e}async function V0(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 yN(t){let e;try{e=await H.readdir(Go)}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(Go,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 V({flow:"subtask",phase:"swept-orphan-worktree",dir:s}).catch(()=>{}),r=!0}return r}async function Bp(t,{agent:e,task:n,skipPermissions:r=!0,reason:o=null}={}){if(typeof n!="string"||!bo(n))throw new Error("task (string) required");let s=await va(e,r),a=Tr(e);if(a){let h=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 h.usageCap=a,h}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 h=ae(i.workspace);if(!h.length)throw new Error("this multi-repo Track has no tagged repos to delegate into");for(let p of h)if(!p?.dir||!await Ki(p.dir))throw new Error(`tagged checkout "${p?.name??"?"}" is missing from the lead workspace (${p?.dir??"no dir"})`);u=h.map(p=>({name:p.name,leadDir:p.dir,base:null}))}else if(!await Ki(c.cwd))throw new Error(`subtask delegation needs the lead's workspace to be a git repo (got ${c.cwd})`);let d=ka().slice(0,8),f={id:d,trackId:t,trackName:i.name,agent:e,task:bo(n),skipPermissions:r,reason:Q0(o),step:"snapshot",leadBox:i.leadBox,box:null,branch:`bostrat/${Pp(i.name)}-${d}`,base:null,repos:u,dir:W.join(Go,`${t}-${d}`),stat:null,conflicts:[],applied:null,startedAt:Date.now(),finishedAt:null,error:null,canceled:!1,forceMerge:!1};return se.set(d,f),await _a(f),bN(f,c,s).catch(h=>xx(f,h)),f}async function xx(t,e){t.failedStep=t.step,t.error=e instanceof ba?"canceled":e?.message||String(e),t.step=e instanceof ba?"canceled":"error",t.finishedAt=Date.now(),await jp(t).catch(()=>{}),await _a(t).catch(()=>{}),await vN(t).catch(()=>{})}function zc(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 bN(t,e,n){if(await Fo(t,"snapshot"),t.repos){for(let s of t.repos)s.base=await ko(s.leadDir,`bostrat: snapshot for subtask ${t.id}`);await _a(t)}else t.base=await ko(e.cwd,`bostrat: snapshot for subtask ${t.id}`);if(await Fo(t,"spawn"),await H.mkdir(Go,{recursive:!0}),t.repos){await H.mkdir(t.dir,{recursive:!0});for(let a of t.repos)await xo(a.leadDir,W.join(t.dir,a.name),t.branch,a.base);let s=ae((Z(await K(),t.trackId)||{}).workspace);await Ea(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 xo(e.cwd,t.dir,t.branch,t.base),await ga(t.dir);await kN(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 xN(t,o),await tx(t.trackId,o.name,SM(t.task,!!t.repos),{kind:"subtask"}),await Sx(t,e)}async function Sx(t,e){await Fo(t,"working");let n=W.join(t.dir,Mc);if(await AN(n,t),t.canceled)throw new ba;if(await Fo(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 Sd(u,`bostrat: subtask ${t.id} result (auto-committed)`),l.stat=await _d(l.leadDir,l.base,t.branch,Lo),l.files=await Id(l.leadDir,l.base,t.branch,Lo);let d=await Rd(l.leadDir,l.base,t.branch,Lo);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=>W.join(l.name,f))),i.push(...l.conflicts.map(f=>f.startsWith("patch did not apply cleanly")?`${l.name}: ${f}`:W.join(l.name,f))),d.applied||(c=!1)}t.stat=s,t.files=a,t.conflicts=i,t.applied=c}else{await Sd(t.dir,`bostrat: subtask ${t.id} result (auto-committed)`),t.stat=await _d(e.cwd,t.base,t.branch,Lo),t.files=await Id(e.cwd,t.base,t.branch,Lo);let s=await Rd(e.cwd,t.base,t.branch,Lo);t.applied=s.applied,t.conflicts=s.conflicts}await _a(t);let r=await TN(t,e,n);await Fo(t,"resume"),await tx(t.trackId,t.leadBox,vM(t.task,t.stat,t.conflicts,r),{kind:"subtask-resume"}),await Fo(t,"reap"),await jp(t),t.step="done";let o=Date.now();await yx(t.trackId,t.id,{...Vc(t),finishedAt:o}),await SN(t,o),t.finishedAt=o}async function kN(t,e){let n=W.join(t.dir,W.dirname(pa));await H.mkdir(n,{recursive:!0});let r="";try{r=await tw(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}
189
+ ${a}`}async function Zc(t){let e=t.boxes.find(o=>o.name===t.leadBox);if(!e)return!1;let n=mp.get(e.name);if(n)return n;let r=WN(t,e).finally(()=>mp.delete(e.name));return mp.set(e.name,r),r}async function WN(t,e){if(t.archivedAt||Jn.has(e.state)||await nt(e.name))return!1;let n=xp(e.agent,e.sessionId),r=await Ei(n);if(r===ro)return pt(t,"rehydrate-failed",{box:e.name,agent:e.agent,reason:`agent "${e.agent}" is not installed on this box`}),!1;r===oo&&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 In(e.name,e.cwd,{agentCmd:n,agent:e.agent,resumeSessionId:e.sessionId,pinned:e.pinned===!0});return e.hookTokenHash=ws(o.hookToken),Fs({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 jp(t){let e=await G(),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,Ia.delete(t),pt(n,"unarchived",{}),await Zc(n),await Y(),Ue(n)}async function Lp(){let t=await G(),e=new Set((await be()).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),!Jn.has(a.state)&&a.state!=="stopped"&&(a.state="stopped",o=!0);return o&&await Y(),r}async function Qc(t){let e=await G(),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(Jn.has(r.state))throw new Error("lead box is terminal \u2014 nothing to restart");if(await nt(n.leadBox)){let a=await xt(n.leadBox,{lines:Nt}).catch(()=>"");if(Bi(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 Zc(n);if(await Y(),!s)throw new Error("rehydrate failed \u2014 see the track's rehydrate-failed event");return Ue(n)}async function Fp(t,e,n){let r=await X(t);if(!r)throw new Error(`track "${t}" not found`);if(!e)throw new Error("unknown offer");let o=await B(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 Qc(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 tl(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 Wc(t,e){let n=await G(),r=Z(n,t);r&&(r.handoff={...r.handoff||{},...e},await Y())}function U0(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 Hp(){let t=await G(),e=!1;for(let n of t.tracks||[]){let r=n.handoff,o=U0(n);if(!o)continue;e=!0;let s=!!r.toBox&&r.toBox===r.fromBox;if(s&&o.step==="error"){let c=await nt(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=tl(l),f=d[d.length-1],p=f.agent,h=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:Ur,at:u},pt(n,"lead-handoff",{from:r.fromBox,to:r.fromBox,fromAgent:p,toAgent:r.toAgent,fromSessionId:h,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 z({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 z({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 el(t,e,n=!0,r=null){let o=Xo.get(t);if(o&&!o.finishedAt)throw new Error("a lead handoff is already running for this Track");let s=Z(await G(),t);if(!s)throw new Error(`track "${t}" not found`);Na(t,"handoff");let a=await Ca(e,n),i=Ir(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 nt(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:T0(r),toBox:s.leadBox,startedAt:Date.now(),finishedAt:null,error:null};return Xo.set(t,l),await Wc(t,{step:l.step,fromBox:l.fromBox,toAgent:e,toBox:l.toBox,skipPermissions:n,startedAt:l.startedAt,finishedAt:null,error:null}),qN(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 Wc(t,{step:l.step,error:l.error,finishedAt:l.finishedAt}).catch(()=>{}),z({flow:"lead-handoff",phase:"failed",trackId:t,step:l.step,error:l.error,fromBox:l.fromBox,toAgent:l.toAgent,toBox:l.toBox}).catch(()=>{})}),z({flow:"lead-handoff",phase:"started",trackId:t,fromBox:l.fromBox,toAgent:e,cwd:c.cwd}).catch(()=>{}),l}async function qN(t,e,n,r,o){let s=async(R,V={})=>{t.step=R,console.log(`[lead-handoff ${t.trackId}] step \u2192 ${R}`),await Wc(t.trackId,{step:R,toBox:t.toBox}),await z({flow:"lead-handoff",phase:R,trackId:t.trackId,fromBox:t.fromBox,toBox:t.toBox,toAgent:o,sessionName:V.sessionName,...V})};console.log(`[lead-handoff ${t.trackId}] ${t.fromBox}: ${n.agent} \u2192 ${o} IN PLACE`);let a=await G(),i=Z(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",Ir(c))t.checkpoint="skipped-capped";else try{await nd(t.fromBox,{timeoutMs:v0})}catch(R){t.checkpoint="reconstructed",await z({flow:"lead-handoff",phase:"checkpoint-fallback",trackId:t.trackId,fromBox:t.fromBox,error:R?.message||String(R)}).catch(()=>{})}t.checkpoint!=="llm"&&(t.statusArtifact=await rd(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 ld(t.fromBox,{agentCmd:r,agent:o});await s("hydrate",{sessionName:t.fromBox}),await On({cwd:n.cwd,sessionId:f.sessionId,sessionName:t.fromBox,agent:o,agentCmd:Oa(o)});let p=await xt(t.fromBox,{lines:Nt}).catch(()=>"");if(!Di(o,p)){await s("rollback",{sessionName:t.fromBox,fromAgent:c});let R=xp(c,l,{skipPermissions:t.skipPermissions});await ld(t.fromBox,{agentCmd:R,agent:c,resumeSessionId:l,pinned:u});let V=await G(),M=Z(V,t.trackId);if(M){let N=M.boxes.find(T=>T.name===t.fromBox);N&&(N.state="live"),pt(M,"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 h=await G(),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(R=>R.name===t.fromBox);if(!y)throw new Error(`lead box row "${t.fromBox}" missing during handoff commit`);let k=Date.now(),x=tl(y),A=x[x.length-1];A.endedAt=k,t.reason&&(A.endReason=t.reason),x.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||Ur,at:k},pt(w,"lead-handoff",{from:t.fromBox,to:t.fromBox,fromAgent:c,toAgent:o,fromSessionId:l,toSessionId:f.sessionId,epoch:x.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 Wc(t.trackId,{finishedAt:Date.now(),error:null}),t.finishedAt=Date.now()}async function qp(t){let e=kp.get(t);if(e&&!e.finishedAt)throw new Error("a transfer is already running for this Track");let n=await G(),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=Xo.get(t);if(o&&!o.finishedAt)throw new Error("a lead handoff is running \u2014 retry when it settles");for(let a of ae.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 kp.set(t,s),KN(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 KN(t,e){let n=e.boxes.find(u=>u.name===e.leadBox)||null,r=n?await nt(n.name).catch(()=>null):null;if(t.checkpoint="llm",!r||n&&Ir(n.agent))t.checkpoint=r?"skipped-capped":"skipped-dead";else try{await nd(e.leadBox,{timeoutMs:v0})}catch{t.checkpoint="reconstructed"}t.checkpoint!=="llm"&&await rd(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 ie(e.workspace)){if(!u?.dir)continue;let d={name:u.name??null,repo:u.repo??null,baseSha:null,pushed:!1};try{await mn(u.dir,["push","origin",o],bp);let{stdout:f}=await mn(u.dir,["rev-parse","HEAD"]);d.baseSha=f.trim(),d.pushed=!0}catch(f){d.error=String(f?.message||f).split(`
190
+ `)[0]}s.push(d)}t.step="wip";let a=await op({id:e.id,cwd:e.cwd}),i=await G(),c=Z(i,e.id),l=c?.boxes.find(u=>u.name===c.leadBox)||null;l&&tl(l),await Y(),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:d,baseSha:f})=>({name:u,repo:d,baseSha:f})),unpushed:s.filter(u=>!u.pushed).map(({name:u,repo:d,error:f})=>({name:u,repo:d,error:f})),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 nl(t,{toNode:e,mode:n="transfer"}={}){if(!e||typeof e!="string")throw new Error("toNode required");let r=await G(),o=Z(r,t);if(!o)throw new Error(`track "${t}" not found`);if(o.transferredTo)return{ok:!0,alreadyTransferred:o.transferredTo};Rp(t),await Bp(t,o,n==="recover"?"track recovered onto another node":"track transferred to another node");for(let a of o.boxes)Jn.has(a.state)||(a.state="stopped");let s=await sp({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 Y(),{ok:!0,toNode:e,rescue:s.pushed?{ref:s.ref,sha:s.sha}:null}}async function Kp(t){let e=[];for(let n of Array.isArray(t)?t:[])if(!(!n?.id||!n?.toNode))try{let r=await nl(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 g0(t,e,n){try{await tc(t,e,n)}catch{await mn(t,["worktree","prune"]).catch(()=>{}),await tc(t,e,n)}return e}async function Gp(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(hp.has(e))throw new Error("an adopt is already running for this Track");hp.set(e,{startedAt:Date.now()});try{return await GN({...t,trackId:e,name:n,agent:r,skipPermissions:o,mode:s})}finally{hp.delete(e)}}async function GN({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:d=[],createdAt:f=null,leadBox:p=null,reason:h=null}){let w=await Ca(n,r),y=await G(),k=Z(y,t);if(k&&!k.transferredTo)throw new Error(`track "${t}" is already hosted on this node`);k&&(await sp({id:k.id,cwd:k.cwd}).catch(()=>{}),await D0(k),y.tracks.splice(y.tracks.indexOf(k),1),await Y()),await W.mkdir(va,{recursive:!0});let x=q.join(va,t);await W.rm(x,{recursive:!0,force:!0}).catch(()=>{});let A=null,R=!1,V=[];try{let M=[];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 S=await Zr(m)??await fi(m);await mn(S,["fetch","origin",`+refs/heads/${i}:refs/heads/${i}`],bp),M.push({slug:m,base:S,name:typeof g=="object"?g?.name??null:null})}if(i&&M.length===1){let{base:g,slug:m}=M[0];await g0(g,x,i),V.push({base:g,dir:x}),await _a(x);let S=await Ao(g);A={dir:x,base:g,branch:i,kind:"worktree",baseRef:S,repo:m}}else if(i&&M.length>=2){await W.mkdir(x,{recursive:!0});let g=new Set([".bostrat"]),m=[];for(let S of M){let $=S.name||q.basename(S.base);g.has($)&&($=S.slug.replace("/","-"));for(let vt=2;g.has($);vt++)$=`${q.basename(S.base)}-${vt}`;g.add($);let lt=q.join(x,$);await g0(S.base,lt,i),V.push({base:S.base,dir:lt});let ht=await Ao(S.base);m.push({name:$,dir:lt,base:S.base,baseRef:ht,repo:S.slug})}await Pa(x,m,i),A={dir:x,kind:"multi",branch:i,repos:m}}else R=!0,await W.mkdir(x,{recursive:!0}),await Nd(x),await _a(x),A={dir:x,base:null,branch:null,kind:"repo"};let N=!1,T=null;if(l?.sha&&A.kind==="worktree")try{await mn(x,["fetch","origin",l.ref||rp(t)],bp);let{stdout:g}=await mn(x,["rev-parse","FETCH_HEAD^"]),{stdout:m}=await mn(x,["rev-parse","HEAD"]);g.trim()===m.trim()?(await mn(x,["read-tree","--reset","-u","FETCH_HEAD"]),await mn(x,["reset","-q"]),N=!0):T="snapshot does not parent the fetched branch head"}catch(g){T=String(g?.message||g).split(`
191
+ `)[0]}else l?.sha&&(T="wip snapshots cover single-repo worktrees only");await f0({id:t,cwd:x}).catch(()=>({restored:!1}));let D=q.join(x,Ur),F=null;(await ki(x)).restored?F="checkpoint":typeof u=="string"&&u.trim()&&(await W.mkdir(q.dirname(D),{recursive:!0}),await W.writeFile(D,u),F="brief");let Q=new Set(y.tracks.flatMap(g=>(g.boxes||[]).map(m=>m.name))),_=null;p&&!Q.has(p)&&!await nt(p).catch(()=>null)?_=p:(_=`${e.trim()} lead`,Q.has(_i(_))&&(_=`${e.trim().slice(0,50).trim()} ${t} lead`));let U=await In(_,x,{agentCmd:w,agent:n});Fs({cwd:U.cwd,sessionName:U.name,agent:n,agentCmd:w});let j=Date.now(),at=Up(U,"lead","live"),Et=(Array.isArray(d)?d:[]).filter(g=>g&&typeof g=="object").map(g=>({...g})),Lt=Et[Et.length-1];Lt&&Lt.endedAt==null&&(Lt.endedAt=j,Lt.endReason==null&&(Lt.endReason=o==="recover"?"node-offline":"node-transfer")),Et.push({agent:n,sessionId:U.sessionId??null,pinned:U.pinned===!0,startedAt:j,endedAt:null}),at.epochs=Et;let it={id:t,name:e.trim(),cwd:U.cwd,workspace:A,leadBox:U.name,boxes:[at],events:[],createdAt:Number.isFinite(f)?f:j,...F?{pendingHandoffHydrate:{artifact:Ur,at:j}}:{}};return pt(it,"transferred-in",{box:U.name,agent:n,fromNode:s,toNode:a,mode:o,reason:h,branch:A.branch??null,wip:N,epoch:Et.length-1,name:it.name,cwd:it.cwd,workspace:{base:A.base??null,branch:A.branch??null,kind:A.kind,...A.baseRef?{baseRef:A.baseRef}:{},...A.repo?{repo:A.repo}:{},...A.repos?{repos:A.repos.map(({name:g,base:m,baseRef:S,repo:$})=>({name:g,base:m,baseRef:S,repo:$}))}:{}}}),y.tracks.push(it),await Y(),{...await Ue(it),adopt:{wipApplied:N,wipSkipped:T,codeless:R,artifactSource:F}}}catch(M){for(let N of V)await oe(N.base,N.dir).catch(()=>{});throw await W.rm(x,{recursive:!0,force:!0}).catch(()=>{}),M}}async function H0(t,e,n){let r=await G(),o=Z(r,t);o&&(o.subtasks=o.subtasks||{},o.subtasks[e]={...o.subtasks[e]||{},...n},await Y())}async function Go(t,e){t.step=e,await Ba(t)}function W0(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 q0(t){return!!t&&!t.finishedAt&&!t.canceled&&t.step==="working"&&!!t.box&&!!t.dir&&!!t.base&&!!t.branch}async function YN(t,e,n){if(!q0(n)||ae.has(e)||!await nt(n.box).catch(()=>null))return!1;try{await W.access(n.dir)}catch{return!1}let o=await nt(t.leadBox).catch(()=>null);if(!o?.cwd)return!1;let s={...n,id:e,leadBox:t.leadBox,step:"working",canceled:!1,forceMerge:!1};return ae.set(e,s),G0(s,o).catch(a=>K0(s,a)),!0}async function Vp(){let t=await G(),e=!1;for(let n of t.tracks||[]){for(let[r,o]of Object.entries(n.subtasks||{})){if(ae.has(r))continue;if(await YN(n,r,o)){e=!0,pt(n,"subtask-resumed",{box:o.box,agent:o.agent,task:o.task,subtaskId:r,resumedStep:o.step}),await z({flow:"subtask",phase:"resumed",trackId:n.id,subtaskId:r,box:o.box,branch:o.branch}).catch(()=>{});continue}let s=o.step,a=W0(o);if(!a)continue;e=!0,n.subtasks[r]=a;let i=n.boxes.find(c=>c.subtaskId===r);i&&!Jn.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 z({flow:"subtask",phase:"reconciled",trackId:n.id,subtaskId:r,outcome:a.step,recovered:a.recovered,box:o.box,branch:o.branch}).catch(()=>{}),await y0(n,o.box,o.dir)}for(let r of n.boxes){if(r.role!=="subtask"||Jn.has(r.state)||ae.has(r.subtaskId)||n.subtasks?.[r.subtaskId])continue;e=!0,r.state="canceled";let o=r.subtaskId?q.join(Zo,`${n.id}-${r.subtaskId}`):null;await z({flow:"subtask",phase:"reaped-legacy-orphan",trackId:n.id,subtaskId:r.subtaskId,box:r.name}).catch(()=>{}),await y0(n,r.name,o)}}return e=await XN(t)||e,e&&await Y(),e}async function y0(t,e,n){if(e&&await $e(e).catch(()=>{}),!n)return;if(t.workspace?.kind==="multi"){for(let o of ie(t.workspace)){let s=q.join(n,o.name);await oe(o.base,s).then(()=>!0,()=>!1)||await oe(o.dir,s).catch(()=>{})}await W.rm(n,{recursive:!0,force:!0}).catch(()=>{});return}let r=await nt(t.leadBox).catch(()=>null);r?.cwd&&await oe(r.cwd,n).catch(()=>{})}async function XN(t){let e;try{e=await W.readdir(Zo)}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 ae.values())o.dir&&n.add(q.basename(o.dir));let r=!1;for(let o of e){if(n.has(o))continue;let s=q.join(Zo,o),a=(t.tracks||[]).find(i=>o.startsWith(`${i.id}-`));if(a?.workspace?.kind==="multi"){for(let i of ie(a.workspace))await oe(i.base,q.join(s,i.name)).catch(()=>{});await W.rm(s,{recursive:!0,force:!0}).catch(()=>{})}else{let i=a?await nt(a.leadBox).catch(()=>null):null;i?.cwd?await oe(i.cwd,s).catch(()=>{}):await W.rm(s,{recursive:!0,force:!0}).catch(()=>{})}await z({flow:"subtask",phase:"swept-orphan-worktree",dir:s}).catch(()=>{}),r=!0}return r}async function Jp(t,{agent:e,task:n,skipPermissions:r=!0,reason:o=null}={}){if(typeof n!="string"||!vo(n))throw new Error("task (string) required");let s=await Ca(e,r),a=Ir(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 G(),t);if(!i)throw new Error(`track "${t}" not found`);let c=await nt(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=ie(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 d=Qo().slice(0,8),f={id:d,trackId:t,trackName:i.name,agent:e,task:vo(n),skipPermissions:r,reason:T0(o),step:"snapshot",leadBox:i.leadBox,box:null,branch:`bostrat/${zp(i.name)}-${d}`,base:null,repos:u,dir:q.join(Zo,`${t}-${d}`),stat:null,conflicts:[],applied:null,startedAt:Date.now(),finishedAt:null,error:null,canceled:!1,forceMerge:!1};return ae.set(d,f),await Ba(f),ZN(f,c,s).catch(p=>K0(f,p)),f}async function K0(t,e){t.failedStep=t.step,t.error=e instanceof Ra?"canceled":e?.message||String(e),t.step=e instanceof Ra?"canceled":"error",t.finishedAt=Date.now(),await Xp(t).catch(()=>{}),await Ba(t).catch(()=>{}),await nP(t).catch(()=>{})}function ol(t){let e=ae.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 Yp(t){let e=ae.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 ZN(t,e,n){if(await Go(t,"snapshot"),t.repos){for(let s of t.repos)s.base=await So(s.leadDir,`bostrat: snapshot for subtask ${t.id}`);await Ba(t)}else t.base=await So(e.cwd,`bostrat: snapshot for subtask ${t.id}`);if(await Go(t,"spawn"),await W.mkdir(Zo,{recursive:!0}),t.repos){await W.mkdir(t.dir,{recursive:!0});for(let a of t.repos)await To(a.leadDir,q.join(t.dir,a.name),t.branch,a.base);let s=ie((Z(await G(),t.trackId)||{}).workspace);await Pa(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 To(e.cwd,t.dir,t.branch,t.base),await _a(t.dir);await QN(t,e);let r=t.trackName.slice(0,38).trim(),o=await In(`${r} ${t.agent} sub ${t.id}`,t.dir,{agentCmd:n,agent:t.agent});t.box=o.name,await tP(t,o),await A0(t.trackId,o.name,QM(t.task,!!t.repos),{kind:"subtask"}),await G0(t,e)}async function G0(t,e){await Go(t,"working");let n=q.join(t.dir,Hc);if(await oP(n,t),t.canceled)throw new Ra;if(await Go(t,"merge"),t.repos){let s={files:0,insertions:0,deletions:0},a=[],i=[],c=!0;for(let l of t.repos){let u=q.join(t.dir,l.name);await Od(u,`bostrat: subtask ${t.id} result (auto-committed)`),l.stat=await Bd(l.leadDir,l.base,t.branch,Ko),l.files=await Dd(l.leadDir,l.base,t.branch,Ko);let d=await jd(l.leadDir,l.base,t.branch,Ko);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=>q.join(l.name,f))),i.push(...l.conflicts.map(f=>f.startsWith("patch did not apply cleanly")?`${l.name}: ${f}`:q.join(l.name,f))),d.applied||(c=!1)}t.stat=s,t.files=a,t.conflicts=i,t.applied=c}else{await Od(t.dir,`bostrat: subtask ${t.id} result (auto-committed)`),t.stat=await Bd(e.cwd,t.base,t.branch,Ko),t.files=await Dd(e.cwd,t.base,t.branch,Ko);let s=await jd(e.cwd,t.base,t.branch,Ko);t.applied=s.applied,t.conflicts=s.conflicts}await Ba(t);let r=await rP(t,e,n);await Go(t,"resume"),await A0(t.trackId,t.leadBox,tN(t.task,t.stat,t.conflicts,r),{kind:"subtask-resume"}),await Go(t,"reap"),await Xp(t),t.step="done";let o=Date.now();await H0(t.trackId,t.id,{...rl(t),finishedAt:o}),await eP(t,o),t.finishedAt=o}async function QN(t,e){let n=q.join(t.dir,q.dirname(Sa));await W.mkdir(n,{recursive:!0});let r="";try{r=await _w(e.cwd,e.sessionId)}catch{}if(!r)try{r=await W.readFile(q.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}
191
192
 
192
193
  **Delegated task:** ${t.task}
193
194
 
@@ -198,15 +199,15 @@ ${a}`}async function Hc(t){if(t.archivedAt)return!1;let e=t.boxes.find(o=>o.name
198
199
  ## Conversation so far (lead \u2192 you)
199
200
 
200
201
  ${r}
201
- `;await H.writeFile(W.join(t.dir,pa),o)}async function xN(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:is(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]||{},...Vc(t)},await J())}async function SN(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 vN(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]||{},...Vc(t)},await J()}async function TN(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 jp(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 AN(t,e){let n=(e.startedAt||Date.now())+mN;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(hN)}}function Vn(t){return new Promise(e=>setTimeout(e,t))}var z0,fn,J0,bM,fa,kM,Pc,xa,Kn,Br,X0,xM,Mc,pa,SM,vM,pe,Yf,Z,Xf,pt,Zf,AM,Gn,W0,IM,RM,$M,OM,NM,ma,q0,BM,DM,jM,LM,FM,Uo,ha,qM,GM,VM,JM,Qf,XM,ux,wa,dx,eN,da,tp,nN,ep,aN,ya,iN,cN,K0,Ip,Ko,Vo,ap,dn,ip,$p,np,mN,hN,Go,Lo,se,wN,jr,Vc,_a,Pp,ba,Rr=M(()=>{Kt();Yu();Dg();$i();kn();fu();Ug();Wt();Ke();ls();Ai();oy();uo();gd();bd();xy();Mu();Ei();Wu();ye();$d();ar();Is();Yi();zy();Dd();zb();Ku();ju();Yb();ef();ot();bc();dc();Eo();_f();Bo();Df();Oc();qf();Fn();B0();zf();H0();mi();z0=yM(gM),fn=process.env.BOSTRAT_STATE_DIR||W.join(process.env.HOME||"/tmp",".bostrat"),J0=W.join(fn,"tracks.json"),bM=W.join(fn,"events.jsonl"),fa=W.join(fn,"workspaces"),kM=process.env.BOSTRAT_DEFAULT_REPO||null,Pc={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"}},xa=Object.keys(Pc);Kn={at:0,value:null};Br=".bostrat/handoff/latest.md",X0=Number(process.env.BOSTRAT_HANDOFF_CHECKPOINT_TIMEOUT_MS)||9e4;xM=/\(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\.\)$/;Mc=".bostrat/handoff/subtask-result.md",pa=".bostrat/handoff/lead-context.md",SM=(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 ${pa} \u2014 read that first for context. Your scoped task:
202
+ `;await W.writeFile(q.join(t.dir,Sa),o)}async function tP(t,e){let n=await G(),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:ws(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]||{},...rl(t)},await Y())}async function eP(t,e=t.finishedAt){let n=await G(),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 Y()}async function nP(t){let e=await G(),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]||{},...rl(t)},await Y()}async function rP(t,e,n){let r=`.bostrat/handoff/subtask-${t.id}.md`;try{let o=q.join(e.cwd,r);await W.mkdir(q.dirname(o),{recursive:!0}),await W.copyFile(n,o)}catch{}return r}async function Xp(t){if(t.box&&await $e(t.box).catch(()=>{}),t.repos&&t.dir){for(let e of t.repos)await oe(e.leadDir,q.join(t.dir,e.name)).catch(()=>{});await W.rm(t.dir,{recursive:!0,force:!0}).catch(()=>{})}else if(t.dir){let n=(await nt(t.leadBox).catch(()=>null))?.cwd;n&&await oe(n,t.dir).catch(()=>{})}}async function oP(t,e){let n=(e.startedAt||Date.now())+VN;for(;;){if(e.canceled||e.forceMerge)return;try{await W.access(t);return}catch{}if(Date.now()>n)throw new Error("subtask timed out without signaling completion (no result digest written)");await Yn(zN)}}function Yn(t){return new Promise(e=>setTimeout(e,t))}var b0,hn,k0,YM,va,XM,qc,$a,zn,Ur,v0,ZM,Hc,Sa,QM,tN,he,cp,Z,lp,pt,up,nN,Jn,m0,sN,aN,iN,cN,dN,Ta,h0,mN,hN,wN,gN,yN,Vo,Aa,vN,TN,AN,_N,dp,RN,N0,Ea,P0,MN,xa,fp,NN,pp,jN,Ia,LN,FN,w0,mp,Up,Xo,ts,bp,mn,kp,Wp,hp,VN,zN,Zo,Ko,ae,JN,Wr,rl,Ba,zp,Ra,Nr=C(()=>{Gt();sd();Zg();ji();Sn();Ou();ny();qt();Ge();ys();Mi();by();wr();Ed();Id();By();Hu();Ni();Zu();ke();Ld();cr();Us();oc();lb();Gd();bk();td();Vu();xk();mf();st();Ic();ra();Ro();Lf();Ho();Jf();Fc();np();Wn();i0();ap();p0();xi();b0=JM(zM),hn=process.env.BOSTRAT_STATE_DIR||q.join(process.env.HOME||"/tmp",".bostrat"),k0=q.join(hn,"tracks.json"),YM=q.join(hn,"events.jsonl"),va=q.join(hn,"workspaces"),XM=process.env.BOSTRAT_DEFAULT_REPO||null,qc={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"}},$a=Object.keys(qc);zn={at:0,value:null};Ur=".bostrat/handoff/latest.md",v0=Number(process.env.BOSTRAT_HANDOFF_CHECKPOINT_TIMEOUT_MS)||9e4;ZM=/\(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\.\)$/;Hc=".bostrat/handoff/subtask-result.md",Sa=".bostrat/handoff/lead-context.md",QM=(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 ${Sa} \u2014 read that first for context. Your scoped task:
202
203
 
203
204
  ${t}
204
205
 
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 ${Mc} (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 ${pa} \u2014 read that first for context. Your scoped task:
206
+ 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 ${Hc} (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 ${Sa} \u2014 read that first for context. Your scoped task:
206
207
 
207
208
  ${t}
208
209
 
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 ${Mc} 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.`,vM=(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,Yf=null;Z=(t,e)=>t.tracks.find(n=>n.id===e)||null,Xf=Promise.resolve();pt=(t,e,n={})=>{let r={at:Date.now(),type:e,...n};return t.events.push(r),TM(t.id,r),Xy(t,r),r};ow(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(()=>{}))});Zf=(t,e,n)=>e!=null&&n.some(r=>t===r.box&&e>=r.from&&e<=r.to),AM=new Set(["stuck","wrong-approach","too-slow","want-different-model","context-refresh","cost","parallelize","other"]);Gn=new Set(["merged","conflict","canceled","failed","handed-off"]),W0=new Map;IM=5e3;RM={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];OM=10*6e4;NM=1500,ma=new Map;q0="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.";BM=4e3,DM=3,jM=[300,350,400],LM=1e3,FM=12,Uo=new Map,ha=new Map;qM=[250,400,500,600];GM=3e4,VM=[350,650,900];JM=[250,450,700],Qf=2;XM=12e4;ux=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}))});wa="# bostrat workspace",dx=`${wa}
210
+ 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 ${Hc} 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.`,tN=(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."),he=null,cp=null;Z=(t,e)=>t.tracks.find(n=>n.id===e)||null,lp=Promise.resolve();pt=(t,e,n={})=>{let r={at:Date.now(),type:e,...n};return t.events.push(r),eN(t.id,r),fb(t,r),r};Ow(async({sessionName:t,from:e,to:n,version:r,status:o,error:s})=>{let i=(await G()).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(()=>{}))});up=(t,e,n)=>e!=null&&n.some(r=>t===r.box&&e>=r.from&&e<=r.to),nN=new Set(["stuck","wrong-approach","too-slow","want-different-model","context-refresh","cost","parallelize","other"]);Jn=new Set(["merged","conflict","canceled","failed","handed-off"]),m0=new Map;sN=5e3;aN={claude:[/^\[Request interrupted by user(?: for tool use)?\]$/i],codex:[/^\[?Request interrupted/i,/^Conversation interrupted/i],cursor:[/^\[?Request interrupted/i]};iN=[/^\/model(?:\s|$)/i,/<command-(?:name|message|args)>[^<]*\bmodel\b/i,/^Model changed to\b/i];cN=10*6e4;dN=1500,Ta=new Map;h0="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.";mN=4e3,hN=3,wN=[300,350,400],gN=1e3,yN=12,Vo=new Map,Aa=new Map;vN=[250,400,500,600];TN=3e4,AN=[350,650,900];_N=[250,450,700],dp=2;RN=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}))});Ea="# bostrat workspace",P0=`${Ea}
210
211
 
211
212
  TRACK MEMORY: if \`.bostrat/memory/MEMORY.md\` exists in your workspace, read it
212
213
  before substantive work \u2014 it is the shared cross-provider memory for this repo
@@ -474,68 +475,68 @@ which steps to run (and which to skip). An offer buried mid-message, phrased as
474
475
  statement, or omitted entirely renders no controls \u2014 so close EVERY completed
475
476
  implementation turn this way, every time. When the operator has already asked you
476
477
  to commit / push / open the PR, just do it; do not re-offer.
477
- `,eN=dx,da=dx+Qw;tp=t=>typeof t=="string"&&(t===wa||t.startsWith(`${wa}
478
- `)),nN="# bostrat multi-repo workspace";ep=da.replace(`${wa}
479
- `,`${wa}
478
+ `,MN=P0,xa=P0+mg;fp=t=>typeof t=="string"&&(t===Ea||t.startsWith(`${Ea}
479
+ `)),NN="# bostrat multi-repo workspace";pp=xa.replace(`${Ea}
480
+ `,`${Ea}
480
481
 
481
482
  (Global copy managed by bostrat \u2014 rewritten on service start; edits will be lost.)
482
483
  SCOPE: these instructions apply ONLY when your working directory is under
483
484
  ~/.bostrat/workspaces/ or ~/.bostrat/worktrees/ \u2014 a bostrat-orchestrated box.
484
485
  When working anywhere else, ignore everything below.
485
- `);aN=new Set(["claude","codex","cursor"]);ya=new Set,iN=t=>ya.has(t);cN=9e4;K0={merged:"merged",closed:"closed on GitHub WITHOUT merging",lost:"no longer found on GitHub (deleted, or its repo left the grant)"};Ip=(t,e,n)=>({name:t.name,agent:t.agent,role:e,state:n,cwd:t.cwd,sessionId:t.sessionId,pinned:t.pinned===!0,hookTokenHash:is(t.hookToken),createdAt:Date.now()});Ko=new Map,Vo=t=>Ko.get(t)||(pe?Z(pe,t)?.handoff:null)||null;ap=6e4,dn=(t,e,n=15e3)=>z0("git",["-C",t,...e],{timeout:n,maxBuffer:8*1024*1024}),ip=new Map,$p=t=>ip.get(t)||null;np=new Map;mN=Number(process.env.BOSTRAT_SUBTASK_TIMEOUT_MS)||18e5,hN=Number(process.env.BOSTRAT_SUBTASK_POLL_MS)||3e3,Go=W.join(fn,"worktrees"),Lo=[pa,Mc],se=new Map,wN=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)},Vc=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});_a=t=>yx(t.trackId,t.id,Vc(t));Pp=t=>t.trim().replace(/\s+/g,"-").replace(/[^A-Za-z0-9._-]/g,"").toLowerCase()||"track",ba=class extends Error{}});Kt();import ut from"node:path";import Ut from"node:fs";import cj from"node:readline";import{fileURLToPath as lj}from"node:url";import he from"express";import uj from"node:http";import dj from"node:https";import qm from"node:os";import{WebSocketServer as fj}from"ws";Kt();import cE from"node-pty";async function Vh(t,e,n={}){if(!At(e)){Ti(t,`invalid session name: ${e}`),t.close(1008,"invalid session name");return}if(!await Tn()){Ti(t,`host tmux server not running on ${ne}`),t.close(1011,"tmux server unavailable");return}if(!await et(e)){Ti(t,`session "${e}" not found`),t.close(1008,"session not found");return}let r=Gh(n.cols,120,zh),o=Gh(n.rows,32,Jh),s;try{s=cE.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){Ti(t,`failed to spawn tmux attach: ${a.message}`),t.close(1011,"spawn failed");return}s.onData(a=>{t.readyState===t.OPEN&&ou(t,{type:"data",data:a})}),s.onExit(({exitCode:a,signal:i})=>{t.readyState===t.OPEN&&(ou(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"&&fE(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{}dE(e)})}var lE=6,uE=250;async function dE(t,e=lE,n=uE){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 zh=20,Jh=6;function fE(t,e){return Number.isFinite(Number(t))&&Number.isFinite(Number(e))&&Number(t)>=zh&&Number(e)>=Jh}function Gh(t,e,n){let r=Number(t);return!Number.isFinite(r)||r<n?e:Math.min(500,r|0)}function ou(t,e){try{t.send(JSON.stringify(e))}catch{}}function Ti(t,e){ou(t,{type:"error",message:e})}function Yh(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();Ai();Yu();Rr();var EN=t=>!!t&&!t.finishedAt&&!t.canceled&&!t.error;function Tx({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(EN)&&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}}ot();Wt();var _N=(...t)=>fetch(...t);function IN(t=process.env){return!!(gt(t)&&t.BOSTRAT_PLANE_TOKEN)}async function Lp(t=process.env){if(!IN(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 _N(`${gt(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 zo(t,e=process.env){let n=String(t??"").trim();if(!n)throw new Error("a circuit name or id is required");let r=await Lp(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 Jc(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}})}ot();Wt();var RN=(...t)=>fetch(...t);async function Yc(t,e,n,r=process.env){if(!(gt(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 RN(`${gt(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 Yc("POST","/v1/circuits",{name:t},e).then(n=>n.circuit)}async function Ax({circuitRef:t,newCircuitName:e,name:n,markdown:r},o=process.env){let s=e?await $N(e,o):await zo(t,o),a=await Yc("POST","/v1/blueprints",{circuitId:s.id,name:n,markdown:r},o);return{circuit:s,...a}}async function Fp(t,e=process.env){let n=await zo(t,e),r=await Yc("GET",`/v1/blueprints/${encodeURIComponent(n.id)}`,null,e);return{circuit:n,...r}}async function Up(t,e=process.env){return(await Yc("GET","/v1/circuits",null,e)).memberships?.[t]??null}async function Ex(t,e,n,r=process.env){let{blueprint:o,items:s}=await Fp(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}}ot();Wt();var ON=(...t)=>fetch(...t);async function CN(t,e,n,r=process.env){if(!(gt(r)&&r.BOSTRAT_PLANE_TOKEN))throw new Error("no plane configured \u2014 the decision ledger lives on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let o=new AbortController,s=setTimeout(()=>o.abort(),15e3);try{let a=await ON(`${gt(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)}}async function _x(t,{title:e,context:n="",decision:r,alternatives:o=[],supersedesId:s=null}){if(!String(e??"").trim())throw new Error("a title is required");if(!String(r??"").trim())throw new Error("the decision itself is required (what was decided)");return await I(t,{type:"decision.recorded",actor:"orchestrator",source:"orchestrator",payload:{title:String(e).trim(),context:String(n??"").trim(),decision:String(r).trim(),alternatives:(Array.isArray(o)?o:[]).map(a=>typeof a=="string"?{label:a}:a).filter(a=>a?.label),...s?{supersedesId:s}:{}}}),{title:String(e).trim()}}function Ix(t,e=process.env){return CN("GET",`/v1/decisions?track=${encodeURIComponent(t)}`,null,e)}qf();ot();import Ma from"node:fs/promises";import sl from"node:path";import SP from"node:os";kn();import MN from"node:fs/promises";import Rx from"node:path";import NN from"node:os";var $x=()=>Rx.join(process.env.BOSTRAT_STATE_DIR||Rx.join(process.env.HOME||NN.tmpdir(),".bostrat"),"integrations.json");async function pn(){try{return JSON.parse(await MN.readFile($x(),"utf8"))||{}}catch{return{}}}var Xc=["linked","prOpened","prMerged","create"],Hp=["prompt","auto","off"],PN={create:["prompt","off"]},Ox=t=>PN[t]??Hp;function Zc(t){let e=t.linear||{},n=e.transitions===!0?"auto":"prompt",r={};for(let o of Xc){let s=Ox(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:Zc(t),defaultTeam:n}:null}async function Qc(){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:Zc(t)}}async function Wp(){return Zc(await pn())}async function Cx(t){let e=Object.entries(t||{});if(!e.length)throw new Error(`nothing to set \u2014 phases: ${Xc.join(", ")}`);for(let[r,o]of e){if(!Xc.includes(r))throw new Error(`unknown phase "${r}" \u2014 configurable phases: ${Xc.join(", ")}`);let s=Ox(r);if(!s.includes(o))throw new Error(s.length<Hp.length?`mode "${o}" not allowed for "${r}" \u2014 ${r} is always confirmed (modes: ${s.join(", ")})`:`unknown mode "${o}" \u2014 modes: ${Hp.join(", ")}`)}let n=await pn();return n.ticketFlow={...Zc(n),...Object.fromEntries(e)},n.linear&&(delete n.linear.ticketFlow,delete n.linear.transitions),await Yt($x(),n,{mode:384}),n.ticketFlow}async function Ia(){let t=(await pn()).deepgram||{},e=process.env.DEEPGRAM_API_KEY||t.apiKey;return e?{apiKey:e}:null}async function BN(){let t=(await pn()).openai||{},e=process.env.BOSTRAT_OPENAI_API_KEY||t.apiKey;return e?{apiKey:e}:null}var DN={openai:{model:"gpt-realtime-2.1-mini",voice:"marin"}};async function tl(){let e=(await pn()).voiceChat||{},n=e.provider||"openai",r=DN[n];if(!r)return null;let o=n==="openai"?await BN():null;return o?{provider:n,model:e.model||r.model,voice:e.voice||r.voice,apiKey:o.apiKey}:null}async function Mx(){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}}ot();Sn();wr();Bo();import $a from"node:fs/promises";import Hx from"node:path";import cP from"node:os";import{randomUUID as Wx}from"node:crypto";var Kp={};Ol(Kp,{createComment:()=>GN,findIssueUrl:()=>UN,issueStates:()=>JN,mdToAdf:()=>Bx,moveIssue:()=>YN,parseIssueRef:()=>FN,resolveIssue:()=>HN,uploadImage:()=>VN,upsertCard:()=>WN,whoami:()=>qp});var Jo=t=>String(t.baseUrl||"").replace(/\/$/,""),Px=t=>`Basic ${Buffer.from(`${t.email}:${t.apiToken}`).toString("base64")}`;async function Ur(t,e,n,r){let o=await fetch(`${Jo(t)}${n}`,{method:e,headers:{authorization:Px(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 jN=/\/browse\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,LN=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function FN(t){let e=String(t||"").trim();if(/^https?:\/\//i.test(e)){let r=e.match(jN);return r?r[1].toUpperCase():null}let n=e.match(LN);return n?n[1]:null}function UN(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 HN(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:`${Jo(t)}/browse/${n.key}`,state:n.fields?.status?.name??null}}async function WN(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 qN=/(!\[[^\]]*\]\([^)\s]+\)|\*\*[^*\n]+\*\*|`[^`\n]+`|_[^_\n]+_|https?:\/\/[^\s)]+)/g;function KN(t){let e=[],n=0;for(let r of t.matchAll(qN)){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 Bx(t){let e=String(t??"").split(/\n{2,}/).map(n=>n.trim()).filter(Boolean).map(n=>{let r=[];return n.split(`
486
- `).forEach((o,s)=>{s>0&&r.push({type:"hardBreak"}),r.push(...KN(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 GN(t,e,n){let r=await Ur(t,"POST",`/rest/api/3/issue/${encodeURIComponent(e.key)}/comment`,{body:Bx(n)});return r?.id?`${Jo(t)}/browse/${e.key}?focusedCommentId=${r.id}`:null}async function qp(t){let e=await Ur(t,"GET","/rest/api/3/myself"),n=null;try{n=new URL(Jo(t)).host}catch{n=t.baseUrl??null}return{user:e?.displayName??e?.emailAddress??null,org:n}}async function VN(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(`${Jo(t)}/rest/api/3/issue/${encodeURIComponent(e)}/attachments`,{method:"POST",headers:{authorization:Px(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??`${Jo(t)}/rest/api/3/attachment/content/${c.id}`}var zN={new:"unstarted",indeterminate:"started",done:"completed"},Nx=t=>zN[t?.key]??"started";async function JN(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:Nx(s.statusCategory)}:null,i=(o?.transitions??[]).map((c,l)=>({id:c.id,name:c.to?.name??c.name,type:Nx(c.to?.statusCategory),position:l}));return{current:a,states:i}}async function YN(t,e,n){await Ur(t,"POST",`/rest/api/3/issue/${encodeURIComponent(e.key)}/transitions`,{transition:{id:String(n)}})}var Jp={};Ol(Jp,{createComment:()=>oP,createIssue:()=>zp,createProject:()=>Vp,findIssueUrl:()=>eP,issueStates:()=>aP,moveIssue:()=>iP,parseIssueRef:()=>tP,resolveIssue:()=>nP,teams:()=>Yo,uploadImage:()=>sP,upsertCard:()=>rP,whoami:()=>Gp});var XN=()=>process.env.BOSTRAT_LINEAR_API_URL||"https://api.linear.app/graphql";async function Ue(t,e,n={}){let r=await fetch(XN(),{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 ZN=/linear\.app\/[^/\s]+\/issue\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,QN=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function tP(t){let e=String(t||"").trim(),n=e.match(ZN);if(n)return n[1].toUpperCase();let r=e.match(QN);return r?r[1]:null}function eP(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 nP(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 rP(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 oP(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 Gp(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 sP(t,{filename:e,contentType:n,buffer:r}){let o=await Ue(t,`mutation($contentType: String!, $filename: String!, $size: Int!) {
486
+ `);jN=new Set(["claude","codex","cursor"]);Ia=new Set,LN=t=>Ia.has(t);FN=9e4;w0={merged:"merged",closed:"closed on GitHub WITHOUT merging",lost:"no longer found on GitHub (deleted, or its repo left the grant)"};mp=new Map;Up=(t,e,n)=>({name:t.name,agent:t.agent,role:e,state:n,cwd:t.cwd,sessionId:t.sessionId,pinned:t.pinned===!0,hookTokenHash:ws(t.hookToken),createdAt:Date.now()});Xo=new Map,ts=t=>Xo.get(t)||(he?Z(he,t)?.handoff:null)||null;bp=6e4,mn=(t,e,n=15e3)=>b0("git",["-C",t,...e],{timeout:n,maxBuffer:8*1024*1024}),kp=new Map,Wp=t=>kp.get(t)||null;hp=new Map;VN=Number(process.env.BOSTRAT_SUBTASK_TIMEOUT_MS)||18e5,zN=Number(process.env.BOSTRAT_SUBTASK_POLL_MS)||3e3,Zo=q.join(hn,"worktrees"),Ko=[Sa,Hc],ae=new Map,JN=t=>ae.get(t)||(he?he.tracks.map(e=>e.subtasks?.[t]).find(Boolean):null)||null,Wr=t=>{let e=new Map([...ae.values()].filter(r=>r.trackId===t).map(r=>[r.id,r])),n=he?Z(he,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)},rl=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});Ba=t=>H0(t.trackId,t.id,rl(t));zp=t=>t.trim().replace(/\s+/g,"-").replace(/[^A-Za-z0-9._-]/g,"").toLowerCase()||"track",Ra=class extends Error{}});Gt();import dt from"node:path";import Ht from"node:fs";import qj from"node:readline";import{fileURLToPath as Kj}from"node:url";import ge from"express";import Gj from"node:http";import Vj from"node:https";import nh from"node:os";import{WebSocketServer as zj}from"ws";Gt();import RE from"node-pty";async function sw(t,e,n={}){if(!St(e)){Oi(t,`invalid session name: ${e}`),t.close(1008,"invalid session name");return}if(!await _n()){Oi(t,`host tmux server not running on ${re}`),t.close(1011,"tmux server unavailable");return}if(!await nt(e)){Oi(t,`session "${e}" not found`),t.close(1008,"session not found");return}let r=ow(n.cols,120,aw),o=ow(n.rows,32,iw),s;try{s=RE.spawn(L,["-S",re,"attach-session","-d","-t",e],{name:"xterm-256color",cols:r,rows:o,cwd:process.env.HOME||"/",env:{...process.env,TERM:"xterm-256color"}})}catch(a){Oi(t,`failed to spawn tmux attach: ${a.message}`),t.close(1011,"spawn failed");return}s.onData(a=>{t.readyState===t.OPEN&&mu(t,{type:"data",data:a})}),s.onExit(({exitCode:a,signal:i})=>{t.readyState===t.OPEN&&(mu(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"&&ME(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 $E=6,OE=250;async function CE(t,e=$E,n=OE){for(let r=0;r<e;r++){if(await pr(t).catch(()=>!0))return!0;await new Promise(o=>setTimeout(o,n))}return!1}var aw=20,iw=6;function ME(t,e){return Number.isFinite(Number(t))&&Number.isFinite(Number(e))&&Number(t)>=aw&&Number(e)>=iw}function ow(t,e,n){let r=Number(t);return!Number.isFinite(r)||r<n?e:Math.min(500,r|0)}function mu(t,e){try{t.send(JSON.stringify(e))}catch{}}function Oi(t,e){mu(t,{type:"error",message:e})}function cw(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}}ke();Mi();sd();Nr();var sP=t=>!!t&&!t.finishedAt&&!t.canceled&&!t.error;function z0({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(sP)&&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}}st();qt();var aP=(...t)=>fetch(...t);function iP(t=process.env){return!!(gt(t)&&t.BOSTRAT_PLANE_TOKEN)}async function Zp(t=process.env){if(!iP(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 aP(`${gt(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 es(t,e=process.env){let n=String(t??"").trim();if(!n)throw new Error("a circuit name or id is required");let r=await Zp(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 sl(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}})}st();qt();var cP=(...t)=>fetch(...t);async function al(t,e,n,r=process.env){if(!(gt(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 cP(`${gt(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 lP(t,e=process.env){return al("POST","/v1/circuits",{name:t},e).then(n=>n.circuit)}async function J0({circuitRef:t,newCircuitName:e,name:n,markdown:r},o=process.env){let s=e?await lP(e,o):await es(t,o),a=await al("POST","/v1/blueprints",{circuitId:s.id,name:n,markdown:r},o);return{circuit:s,...a}}async function Qp(t,e=process.env){let n=await es(t,e),r=await al("GET",`/v1/blueprints/${encodeURIComponent(n.id)}`,null,e);return{circuit:n,...r}}async function tm(t,e=process.env){return(await al("GET","/v1/circuits",null,e)).memberships?.[t]??null}async function Y0(t,e,n,r=process.env){let{blueprint:o,items:s}=await Qp(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}}st();qt();var uP=(...t)=>fetch(...t);async function dP(t,e,n,r=process.env){if(!(gt(r)&&r.BOSTRAT_PLANE_TOKEN))throw new Error("no plane configured \u2014 the decision ledger lives on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let o=new AbortController,s=setTimeout(()=>o.abort(),15e3);try{let a=await uP(`${gt(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)}}async function X0(t,{title:e,context:n="",decision:r,alternatives:o=[],supersedesId:s=null}){if(!String(e??"").trim())throw new Error("a title is required");if(!String(r??"").trim())throw new Error("the decision itself is required (what was decided)");return await I(t,{type:"decision.recorded",actor:"orchestrator",source:"orchestrator",payload:{title:String(e).trim(),context:String(n??"").trim(),decision:String(r).trim(),alternatives:(Array.isArray(o)?o:[]).map(a=>typeof a=="string"?{label:a}:a).filter(a=>a?.label),...s?{supersedesId:s}:{}}}),{title:String(e).trim()}}function Z0(t,e=process.env){return dP("GET",`/v1/decisions?track=${encodeURIComponent(t)}`,null,e)}np();st();import Ha from"node:fs/promises";import hl from"node:path";import eB from"node:os";Sn();import fP from"node:fs/promises";import Q0 from"node:path";import pP from"node:os";var tv=()=>Q0.join(process.env.BOSTRAT_STATE_DIR||Q0.join(process.env.HOME||pP.tmpdir(),".bostrat"),"integrations.json");async function wn(){try{return JSON.parse(await fP.readFile(tv(),"utf8"))||{}}catch{return{}}}var il=["linked","prOpened","prMerged","create"],em=["prompt","auto","off"],mP={create:["prompt","off"]},ev=t=>mP[t]??em;function cl(t){let e=t.linear||{},n=e.transitions===!0?"auto":"prompt",r={};for(let o of il){let s=ev(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 qr(){let t=await wn(),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:cl(t),defaultTeam:n}:null}async function ll(){let t=await wn(),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:cl(t)}}async function nm(){return cl(await wn())}async function nv(t){let e=Object.entries(t||{});if(!e.length)throw new Error(`nothing to set \u2014 phases: ${il.join(", ")}`);for(let[r,o]of e){if(!il.includes(r))throw new Error(`unknown phase "${r}" \u2014 configurable phases: ${il.join(", ")}`);let s=ev(r);if(!s.includes(o))throw new Error(s.length<em.length?`mode "${o}" not allowed for "${r}" \u2014 ${r} is always confirmed (modes: ${s.join(", ")})`:`unknown mode "${o}" \u2014 modes: ${em.join(", ")}`)}let n=await wn();return n.ticketFlow={...cl(n),...Object.fromEntries(e)},n.linear&&(delete n.linear.ticketFlow,delete n.linear.transitions),await Xt(tv(),n,{mode:384}),n.ticketFlow}async function Da(){let t=(await wn()).deepgram||{},e=process.env.DEEPGRAM_API_KEY||t.apiKey;return e?{apiKey:e}:null}async function hP(){let t=(await wn()).openai||{},e=process.env.BOSTRAT_OPENAI_API_KEY||t.apiKey;return e?{apiKey:e}:null}var wP={openai:{model:"gpt-realtime-2.1-mini",voice:"marin"}};async function ul(){let e=(await wn()).voiceChat||{},n=e.provider||"openai",r=wP[n];if(!r)return null;let o=n==="openai"?await hP():null;return o?{provider:n,model:e.model||r.model,voice:e.voice||r.voice,apiKey:o.apiKey}:null}async function rv(){let t=(await wn()).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 Kr(){let t=(await wn()).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}}st();An();kr();Ho();import La from"node:fs/promises";import fv from"node:path";import UP from"node:os";import{randomUUID as pv}from"node:crypto";var om={};Ul(om,{createComment:()=>AP,findIssueUrl:()=>kP,issueStates:()=>IP,mdToAdf:()=>av,moveIssue:()=>RP,parseIssueRef:()=>bP,resolveIssue:()=>xP,uploadImage:()=>EP,upsertCard:()=>vP,whoami:()=>rm});var ns=t=>String(t.baseUrl||"").replace(/\/$/,""),sv=t=>`Basic ${Buffer.from(`${t.email}:${t.apiToken}`).toString("base64")}`;async function Gr(t,e,n,r){let o=await fetch(`${ns(t)}${n}`,{method:e,headers:{authorization:sv(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 gP=/\/browse\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,yP=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function bP(t){let e=String(t||"").trim();if(/^https?:\/\//i.test(e)){let r=e.match(gP);return r?r[1].toUpperCase():null}let n=e.match(yP);return n?n[1]:null}function kP(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 xP(t,e){let n;try{n=await Gr(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:`${ns(t)}/browse/${n.key}`,state:n.fields?.status?.name??null}}async function vP(t,e,{url:n,title:r,subtitle:o}){await Gr(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 SP=/(!\[[^\]]*\]\([^)\s]+\)|\*\*[^*\n]+\*\*|`[^`\n]+`|_[^_\n]+_|https?:\/\/[^\s)]+)/g;function TP(t){let e=[],n=0;for(let r of t.matchAll(SP)){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 av(t){let e=String(t??"").split(/\n{2,}/).map(n=>n.trim()).filter(Boolean).map(n=>{let r=[];return n.split(`
487
+ `).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 AP(t,e,n){let r=await Gr(t,"POST",`/rest/api/3/issue/${encodeURIComponent(e.key)}/comment`,{body:av(n)});return r?.id?`${ns(t)}/browse/${e.key}?focusedCommentId=${r.id}`:null}async function rm(t){let e=await Gr(t,"GET","/rest/api/3/myself"),n=null;try{n=new URL(ns(t)).host}catch{n=t.baseUrl??null}return{user:e?.displayName??e?.emailAddress??null,org:n}}async function EP(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(`${ns(t)}/rest/api/3/issue/${encodeURIComponent(e)}/attachments`,{method:"POST",headers:{authorization:sv(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??`${ns(t)}/rest/api/3/attachment/content/${c.id}`}var _P={new:"unstarted",indeterminate:"started",done:"completed"},ov=t=>_P[t?.key]??"started";async function IP(t,e){let n=encodeURIComponent(e.key),[r,o]=await Promise.all([Gr(t,"GET",`/rest/api/3/issue/${n}?fields=status`),Gr(t,"GET",`/rest/api/3/issue/${n}/transitions`)]),s=r?.fields?.status??null,a=s?{id:`status:${s.id}`,name:s.name,type:ov(s.statusCategory)}:null,i=(o?.transitions??[]).map((c,l)=>({id:c.id,name:c.to?.name??c.name,type:ov(c.to?.statusCategory),position:l}));return{current:a,states:i}}async function RP(t,e,n){await Gr(t,"POST",`/rest/api/3/issue/${encodeURIComponent(e.key)}/transitions`,{transition:{id:String(n)}})}var cm={};Ul(cm,{createComment:()=>DP,createIssue:()=>im,createProject:()=>am,findIssueUrl:()=>NP,issueStates:()=>LP,moveIssue:()=>FP,parseIssueRef:()=>MP,resolveIssue:()=>PP,teams:()=>rs,uploadImage:()=>jP,upsertCard:()=>BP,whoami:()=>sm});var $P=()=>process.env.BOSTRAT_LINEAR_API_URL||"https://api.linear.app/graphql";async function He(t,e,n={}){let r=await fetch($P(),{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 OP=/linear\.app\/[^/\s]+\/issue\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,CP=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function MP(t){let e=String(t||"").trim(),n=e.match(OP);if(n)return n[1].toUpperCase();let r=e.match(CP);return r?r[1]:null}function NP(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 PP(t,e){let r=(await He(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 BP(t,e,{url:n,title:r,subtitle:o}){let s=await He(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 DP(t,e,n){let r=await He(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 sm(t){let e=await He(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 jP(t,{filename:e,contentType:n,buffer:r}){let o=await He(t,`mutation($contentType: String!, $filename: String!, $size: Int!) {
487
488
  fileUpload(contentType: $contentType, filename: $filename, size: $size) {
488
489
  success
489
490
  uploadFile { uploadUrl assetUrl headers { key value } }
490
491
  }
491
- }`,{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 aP(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 iP(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 Yo(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 Dx=255;async function Vp(t,{teamId:e,name:n,description:r}){let o=r||null,s=!!o&&o.length>Dx,a=s?`${o.slice(0,Dx-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 zp(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 qx={linear:{api:Jp,config:Lr},jira:{api:Kp,config:Qc}};async function nm(){let t=[];for(let[e,{api:n,config:r}]of Object.entries(qx)){let o=await r();o&&t.push({name:e,api:n,cfg:o})}return t}async function Hr(t){let e=qx[t?.provider];if(!e)return null;let n=await e.config();return n?{name:t.provider,api:e.api,cfg:n}:null}function rm(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 Kx=()=>process.env.BOSTRAT_STATE_DIR||Hx.join(process.env.HOME||cP.tmpdir(),".bostrat"),Qp=()=>Hx.join(Kx(),"tickets.json"),Gx=()=>(process.env.BOSTRAT_PUBLIC_URL||"http://bostrat.globopi").replace(/\/$/,""),el=t=>`${Gx()}/track/${t}`,zn=null,Yp=null,Xp=Promise.resolve();async function Ca(){return zn||(Yp??=$a.readFile(Qp(),"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 tm().catch(()=>{})}}return zn}).finally(()=>Yp=null),Yp)}async function tm(){let t=JSON.stringify({tickets:zn},null,2),e=`${Qp()}.${process.pid}.tmp`;await $a.mkdir(Kx(),{recursive:!0}),await $a.writeFile(e,t),await $a.rename(e,Qp())}async function Jn(t=null){if(Xp=Xp.then(tm,tm),await Xp.catch(()=>{}),!t)return;let e=zn?.[t];e?qt("tickets",{id:t,updatedAt:Date.now(),...e},{trackId:t}).catch(()=>{}):we("tickets",t).catch(()=>{})}async function He(t){return(await Ca())[t]??null}async function Vx(){return{...await Ca()}}async function zx(){return(await nm()).length>0}async function Xo(t,e,{source:n="api"}={}){let r=await nm();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 Ca())[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 Oa(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 Ra(c,`**Bostrat** \u2014 Track **${c.track.name}** linked${l.length?` (${l.join(", ")})`:""}.`),await Xx(t.id,c,"linked"),c}async function om(t){let e=await Ca();return e[t]?(delete e[t],await Jn(t),!0):!1}var em=t=>`$${t>=100?Math.round(t):t.toFixed(2)}`;async function Jx(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 lP(t){let e=Object.entries(t.byProvider).sort((r,o)=>o[1].usd-r[1].usd).map(([r,o])=>`${r} ${em(o.usd)}`).join(" \xB7 "),n=Object.keys(t.byBox).length;return`${em(t.totalUsd)}${e?` (${e})`:""}${n>1?` across ${n} boxes`:""}`}function uP(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(em(e.totalUsd)),n.join(" \xB7 ")||"linked"}async function Oa(t,e){let n=await Hr(e);if(!n)return;let r=await Jx(e,t).catch(()=>null);await n.api.upsertCard(n.cfg,e,{url:el(t),title:`Bostrat Track: ${e.track.name}`,subtitle:uP(e,r)})}function nl(t){let e=new URL(Gx());return`${e.protocol}//${t}.${e.host}/`}var dP={linked:"linked",opened:"prOpened",merged:"prMerged"};function fP(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 Yx(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 Xx(t,e,n){let r=await Hr(e);if(!r)return;let o=r.cfg.ticketFlow?.[dP[n]]??"prompt";if(o==="off")return;let{current:s,states:a}=await r.api.issueStates(r.cfg,e),i=rm(s,a),c=fP(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 Yx(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:Wx(),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 Zx(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=rm(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 sm(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=rm(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 Yx(t,r,{from:l,to:c.name,mode:n}),{key:r.key,from:l,to:c.name,moved:!0})}async function Qx(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 tS(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 sm(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 jx=50;async function eS(){let t=await Lr();if(!t)throw new Error("no ticketing integration configured");return Yo(t)}function pP(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>jx)throw new Error(`too many issues (${n.length}); cap is ${jx} per proposal`);return{epic:r,issues:n,team:e.team?String(e.team).trim():null,linkCurrentTrack:e.linkCurrentTrack===!0}}async function mP(t,e,n,r){let o=r??await Yo(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 nS(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=pP(e),o=await Yo(n),s=await mP(n,r,t,o),a=s?{id:s.id,key:s.key,name:s.name}:null,i=Wx();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 rS(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(p=>p.type==="ticket.create.offered"&&p.payload?.proposalId===e);if(!s)throw new Error("unknown proposal");if(o.some(p=>p.type==="ticket.create.answered"&&p.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 p=(await Yo(a)).find(w=>w.id===r);if(!p)throw new Error("unknown team");c={id:p.id,key:p.key,name:p.name}}if(!c)throw new Error("a team is required to create \u2014 pick one");let l=[],u=[],d=null;if(i.epic){let p=await Vp(a,{teamId:c.id,name:i.epic.name,description:i.epic.description});d=p.id,l.push({kind:"epic",title:p.name,url:p.url})}for(let p of i.issues||[])try{let w=await zp(a,{teamId:c.id,title:p.title,description:p.description,projectId:d,priority:p.priority});l.push({kind:"issue",key:w.key,title:w.title,url:w.url})}catch(w){u.push({title:p.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(p=>p.kind==="issue"),h=null;return i.linkCurrentTrack&&f.length===1&&!await He(t.id)&&(h=await Xo(t,f[0].key,{source:"created"}).catch(()=>null)),{proposalId:e,action:"created",created:l,failed:u,linked:h?h.key:null}}async function Ra(t,e){let n=await Hr(t);n&&await n.api.createComment(n.cfg,t,e)}async function hP(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 $a.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 Lx=()=>Number(process.env.BOSTRAT_TICKET_COST_SYNC_MS??12e4),Zp=new Map;function wP(t,e){if(Lx()<=0)return Oa(t,e);if(Zp.has(t))return;let n=setTimeout(()=>{Zp.delete(t),He(t).then(r=>r?Oa(t,r):null).catch(()=>{})},Lx());n.unref?.(),Zp.set(t,n)}var Fx=new Map;async function Ux(t,e,n){let r=Fx.get(t)??0;Date.now()-r<600*1e3||(Fx.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 gP(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 nm())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 Xo(s,o,{source:"chat"})}catch(a){await Ux(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 Oa(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 Oa(t.trackId,n),r.change==="opened"||r.change==="merged"){let o=r.change==="merged"?await Jx(n,t.trackId).catch(()=>null):null;await Ra(n,`**Bostrat** \u2014 PR ${r.change} for **${n.track.name}**${r.url?`: ${r.url}`:r.number?` (#${r.number})`:""}`+(o?`
492
+ }`,{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 LP(t,e){let n=await He(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 FP(t,e,n){if(!(await He(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 rs(t){return((await He(t,"query { teams(first: 100) { nodes { id key name } } }")).teams?.nodes??[]).map(n=>({id:n.id,key:n.key,name:n.name}))}var iv=255;async function am(t,{teamId:e,name:n,description:r}){let o=r||null,s=!!o&&o.length>iv,a=s?`${o.slice(0,iv-1).trimEnd()}\u2026`:o,i=await He(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 im(t,{teamId:e,title:n,description:r,projectId:o,priority:s}){let a=await He(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 mv={linear:{api:cm,config:qr},jira:{api:om,config:ll}};async function hm(){let t=[];for(let[e,{api:n,config:r}]of Object.entries(mv)){let o=await r();o&&t.push({name:e,api:n,cfg:o})}return t}async function Vr(t){let e=mv[t?.provider];if(!e)return null;let n=await e.config();return n?{name:t.provider,api:e.api,cfg:n}:null}function wm(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 hv=()=>process.env.BOSTRAT_STATE_DIR||fv.join(process.env.HOME||UP.tmpdir(),".bostrat"),fm=()=>fv.join(hv(),"tickets.json"),wv=()=>(process.env.BOSTRAT_PUBLIC_URL||"http://bostrat.globopi").replace(/\/$/,""),dl=t=>`${wv()}/track/${t}`,Xn=null,lm=null,um=Promise.resolve();async function Ua(){return Xn||(lm??=La.readFile(fm(),"utf8").then(t=>({tickets:JSON.parse(t)?.tickets??{},existed:!0})).catch(()=>({tickets:{},existed:!1})).then(async({tickets:t,existed:e})=>{if(Xn=t,!e&&kt()){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;Xn[s]=i}Object.keys(Xn).length&&await pm().catch(()=>{})}}return Xn}).finally(()=>lm=null),lm)}async function pm(){let t=JSON.stringify({tickets:Xn},null,2),e=`${fm()}.${process.pid}.tmp`;await La.mkdir(hv(),{recursive:!0}),await La.writeFile(e,t),await La.rename(e,fm())}async function Zn(t=null){if(um=um.then(pm,pm),await um.catch(()=>{}),!t)return;let e=Xn?.[t];e?Kt("tickets",{id:t,updatedAt:Date.now(),...e},{trackId:t}).catch(()=>{}):ye("tickets",t).catch(()=>{})}async function We(t){return(await Ua())[t]??null}async function gv(){return{...await Ua()}}async function yv(){return(await hm()).length>0}async function os(t,e,{source:n="api"}={}){let r=await hm();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 Ua())[t.id]=c,await Zn(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 Fa(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 ja(c,`**Bostrat** \u2014 Track **${c.track.name}** linked${l.length?` (${l.join(", ")})`:""}.`),await xv(t.id,c,"linked"),c}async function gm(t){let e=await Ua();return e[t]?(delete e[t],await Zn(t),!0):!1}var mm=t=>`$${t>=100?Math.round(t):t.toFixed(2)}`;async function bv(t,e){if(!t.track?.cwd)return null;let n=Pn(await B({id:e,cwd:t.track.cwd}));return!n.totalUsd||n.totalUsd<.01?null:n}function HP(t){let e=Object.entries(t.byProvider).sort((r,o)=>o[1].usd-r[1].usd).map(([r,o])=>`${r} ${mm(o.usd)}`).join(" \xB7 "),n=Object.keys(t.byBox).length;return`${mm(t.totalUsd)}${e?` (${e})`:""}${n>1?` across ${n} boxes`:""}`}function WP(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(mm(e.totalUsd)),n.join(" \xB7 ")||"linked"}async function Fa(t,e){let n=await Vr(e);if(!n)return;let r=await bv(e,t).catch(()=>null);await n.api.upsertCard(n.cfg,e,{url:dl(t),title:`Bostrat Track: ${e.track.name}`,subtitle:WP(e,r)})}function fl(t){let e=new URL(wv());return`${e.protocol}//${t}.${e.host}/`}var qP={linked:"linked",opened:"prOpened",merged:"prMerged"};function KP(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 kv(t,e,{from:n,to:r,mode:o,phase:s=null,actor:a="user"}){e.state=r,await Zn(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 xv(t,e,n){let r=await Vr(e);if(!r)return;let o=r.cfg.ticketFlow?.[qP[n]]??"prompt";if(o==="off")return;let{current:s,states:a}=await r.api.issueStates(r.cfg,e),i=wm(s,a),c=KP(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 kv(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:pv(),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 vv(t){let e=await We(t);if(!e)throw new Error("no ticket linked to this Track");let n=await Vr(e);if(!n)throw new Error("no ticketing integration configured");let{current:r,states:o}=await n.api.issueStates(n.cfg,e),s=wm(r,o);return s?.name&&e.state!==s.name&&(e.state=s.name,await Zn(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 ym(t,e,{mode:n="manual"}={}){if(!e)throw new Error("stateId required");let r=await We(t);if(!r)throw new Error("no ticket linked to this Track");let o=await Vr(r);if(!o)throw new Error("no ticketing integration configured");let{current:s,states:a}=await o.api.issueStates(o.cfg,r),i=wm(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 Zn(t)),{key:r.key,from:l,to:c.name,moved:!1}):(await o.api.moveIssue(o.cfg,r,c.id),await kv(t,r,{from:l,to:c.name,mode:n}),{key:r.key,from:l,to:c.name,moved:!0})}async function Sv(t,e){let n=await We(t);if(!n)throw new Error("no ticket linked to this Track");let r=await Vr(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 Tv(t,e,n){if(!e)throw new Error("offerId required");let r=await B({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 ym(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 cv=50;async function Av(){let t=await qr();if(!t)throw new Error("no ticketing integration configured");return rs(t)}function GP(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>cv)throw new Error(`too many issues (${n.length}); cap is ${cv} 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 rs(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 We(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 Ev(t,e){let n=await qr();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=GP(e),o=await rs(n),s=await VP(n,r,t,o),a=s?{id:s.id,key:s.key,name:s.name}:null,i=pv();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 _v(t,e,n,{teamId:r=null}={}){if(!e)throw new Error("proposalId required");let o=await B({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 qr();if(!a)throw new Error("no ticketing integration configured");let i=s.payload,c=i.team??null;if(!c&&r){let h=(await rs(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=[],d=null;if(i.epic){let h=await am(a,{teamId:c.id,name:i.epic.name,description:i.epic.description});d=h.id,l.push({kind:"epic",title:h.name,url:h.url})}for(let h of i.issues||[])try{let w=await im(a,{teamId:c.id,title:h.title,description:h.description,projectId:d,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 f=l.filter(h=>h.kind==="issue"),p=null;return i.linkCurrentTrack&&f.length===1&&!await We(t.id)&&(p=await os(t,f[0].key,{source:"created"}).catch(()=>null)),{proposalId:e,action:"created",created:l,failed:u,linked:p?p.key:null}}async function ja(t,e){let n=await Vr(t);n&&await n.api.createComment(n.cfg,t,e)}async function zP(t,e,n){let r=await Vr(t);if(!r)return null;let o=await an(e);if(!o)return null;let s=Te(o,n);if(!s)return null;let a=await La.readFile(me(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 lv=()=>Number(process.env.BOSTRAT_TICKET_COST_SYNC_MS??12e4),dm=new Map;function JP(t,e){if(lv()<=0)return Fa(t,e);if(dm.has(t))return;let n=setTimeout(()=>{dm.delete(t),We(t).then(r=>r?Fa(t,r):null).catch(()=>{})},lv());n.unref?.(),dm.set(t,n)}var uv=new Map;async function dv(t,e,n){let r=uv.get(t)??0;Date.now()-r<600*1e3||(uv.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 YP(t,{resolveTrack:e=null}={}){let n=await We(t.trackId),r=t.payload||{};if(!n){if(t.type!=="turn.user"||t.actor!=="user")return;let o=null;for(let a of await hm())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 os(s,o,{source:"chat"})}catch(a){await dv(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 Zn(t.trackId))}try{switch(t.type){case"handoff.done":n.track.leadAgent=r.toAgent??n.track.leadAgent,await Zn(t.trackId),await Fa(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 Zn(t.trackId),await Fa(t.trackId,n),r.change==="opened"||r.change==="merged"){let o=r.change==="merged"?await bv(n,t.trackId).catch(()=>null):null;await ja(n,`**Bostrat** \u2014 PR ${r.change} for **${n.track.name}**${r.url?`: ${r.url}`:r.number?` (#${r.number})`:""}`+(o?`
492
493
 
493
- Agent cost for this Track: ${lP(o)}.`:"")),await Xx(t.trackId,n,r.change)}break}case"mock.state.changed":{if(r.change==="ready"&&r.mockId){let o=await hP(n,r.mockId,r.version??null);if(!o)break;let s=(r.version??1)>1?` revised (v${r.version})`:"";await Ra(n,`**Bostrat** \u2014 mock **${r.name}**${s}${r.group?` (group \`${r.group}\`)`:""}:
494
+ Agent cost for this Track: ${HP(o)}.`:"")),await xv(t.trackId,n,r.change)}break}case"mock.state.changed":{if(r.change==="ready"&&r.mockId){let o=await zP(n,r.mockId,r.version??null);if(!o)break;let s=(r.version??1)>1?` revised (v${r.version})`:"";await ja(n,`**Bostrat** \u2014 mock **${r.name}**${s}${r.group?` (group \`${r.group}\`)`:""}:
494
495
 
495
- ![${r.name}](${o})`)}else if(r.change==="picked"){let o=(r.siblings??[]).map(s=>`**${s.name}**`).join(", ");await Ra(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 Ra(n,`**Bostrat** \u2014 live preview **${r.name}**: ${nl(r.slug)}
496
- _(runs on the Track's branch; reachable on the operator's private network only)_`);break}case"cost.recorded":await wP(t.trackId,n);break;default:break}}catch(o){let s=e?await e(t.trackId).catch(()=>null):null;await Ux(t.trackId,s?.cwd??null,o)}}function oS({resolveTrack:t}){Zt.on("event",e=>{gP(e,{resolveTrack:t}).catch(()=>{})})}async function sS(){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 Ca(),r=0;for(let[o,s]of Object.entries(n))await qt("tickets",{id:o,updatedAt:Date.now(),...s},{trackId:o}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}Eo();Bo();import yP from"ws";var aS=()=>process.env.BOSTRAT_SLACK_API_BASE||"https://slack.com/api";async function rl(t,e,n={}){let r=await fetch(`${aS()}/${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 am=(t,e)=>rl("chat.postMessage",t,e),Wr=(t,e)=>rl("chat.update",t,e);async function zt(t,e){await fetch(t,{method:"POST",headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify(e)}).catch(()=>{})}async function bP(t,e,n={}){let r=await fetch(`${aS()}/${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 iS(t,{filename:e,buffer:n,title:r,channelId:o,threadTs:s,initialComment:a}){let{upload_url:i,file_id:c}=await bP("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 rl("files.completeUploadExternal",t,{files:[{id:c,title:r}],channel_id:o,thread_ts:s,...a?{initial_comment:a}:{}})}var kP=2200;function cS({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 rl("apps.connections.open",u))}catch(u){return n(`connections.open failed: ${u?.message||u}`),c()}o=new yP(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{}},h=!1,p=setTimeout(()=>{h=!0,f()},kP);Promise.resolve().then(()=>e(d)).then(w=>{clearTimeout(p),!h&&(h=!0,f(d.accepts_response_payload?w:void 0))},w=>{clearTimeout(p),h||(h=!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 dS=()=>process.env.BOSTRAT_STATE_DIR||sl.join(process.env.HOME||SP.tmpdir(),".bostrat"),dm=()=>sl.join(dS(),"slack.json"),ol=null,im=null,cm=Promise.resolve();async function pm(){return ol||(im??=Ma.readFile(dm(),"utf8").then(t=>JSON.parse(t)?.threads??{}).catch(()=>({})).then(t=>ol=t).finally(()=>im=null),im)}async function lS(){let t=JSON.stringify({threads:ol},null,2),e=`${dm()}.${process.pid}.tmp`;await Ma.mkdir(dS(),{recursive:!0}),await Ma.writeFile(e,t),await Ma.rename(e,dm())}async function Te(){cm=cm.then(lS,lS),await cm.catch(()=>{})}async function mm(t){return(await pm())[t]??null}async function vP(t,e){let n=await pm();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 Na(t,e){let n=String(t??"").trim();return n.length<=e?n:`${n.slice(0,e-1).trimEnd()}\u2026`}function TP(t,e=500){let n=String(t??"").trim().split(/\n\s*\n/)[0]??"";return Na(n.replace(/\n+/g," "),e)}function fS(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(Na(t.kickoff,300))}`:"_no kickoff yet \u2014 reply in this thread to steer the lead_";return[{type:"section",text:{type:"mrkdwn",text:`${e}
497
- ${n}`}},{type:"section",text:{type:"mrkdwn",text:r}},{type:"context",elements:[{type:"mrkdwn",text:`<${el(t.trackId)}|open the Track> \xB7 reachable on the operator's private network only`}]}]}async function fm(t,e){await Wr(t.botToken,{channel:e.channel,ts:e.ts,text:`Track: ${e.name}`,blocks:fS(e)})}async function Xn(t,e,n,r=void 0){return am(t.botToken,{channel:e.channel,thread_ts:e.ts,text:n,...r?{blocks:r}:{},unfurl_links:!1})}var uS=new Set;function Yn(t){uS.add(t),t.catch(()=>{}).finally(()=>uS.delete(t))}var St=t=>({response_type:"ephemeral",text:t}),AP="*/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._",EP=["claude","cursor","codex"];function lm(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 um=(t,e)=>St(`No live Track matches \u201C${Q(e)}\u201D. Live: ${t.map(n=>`\`${Q(n.name)}\``).join(" \xB7 ")||"none"}`);async function pS(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 zt(o,{...St(`At capacity \u2014 ${a.length} live Tracks (limit ${e.maxConcurrent}). Archive or stop something first.`),replace_original:!0});return}if(!e.channel){await zt(o,{...St("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?sl.basename(c.base):"fresh workspace"),lead:"claude"},u=await am(e.botToken,{channel:e.channel,text:`Track started: ${l.name}`,blocks:fS(l),unfurl_links:!1});l.ts=u.ts,(await pm())[i.id]=l,await Te(),await zt(o,{...St(`\u2713 *${Q(l.name)}* started \u2014 root message posted.`),replace_original:!0})}catch(a){await zt(o,{...St(`Start failed: ${a?.message||a}`),replace_original:!0})}}async function _P(t,e,{track:n,responseUrl:r}){let o=t.deps;try{await o.archiveTrack(n.id);let s=await mm(n.id);s&&(s.archivedAt=Date.now(),await Te(),await fm(e,s).catch(()=>{})),await zt(r,{...St(`\u2713 *${Q(n.name)}* archived.`),replace_original:!0})}catch(s){await zt(r,{...St(`Archive failed: ${s?.message||s}`),replace_original:!0})}}async function IP(t,e,{track:n,agent:r,responseUrl:o}){try{await t.deps.startLeadHandoff(n.id,r),await zt(o,{...St(`\u2713 Handing *${Q(n.name)}* to ${Q(r)} \u2014 the root message updates when the baton lands.`),replace_original:!0})}catch(s){await zt(o,{...St(`Handoff failed: ${s?.message||s}`),replace_original:!0})}}async function RP(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 zt(r,{...St(`\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 zt(r,{...St(`Stop failed: ${s?.message||s}`),replace_original:!0})}}function $P(t,e){let n=[...e.slice(0,99).map(r=>({text:{type:"plain_text",text:Na(`${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 OP(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?sl.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(`
496
+ ![${r.name}](${o})`)}else if(r.change==="picked"){let o=(r.siblings??[]).map(s=>`**${s.name}**`).join(", ");await ja(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 ja(n,`**Bostrat** \u2014 live preview **${r.name}**: ${fl(r.slug)}
497
+ _(runs on the Track's branch; reachable on the operator's private network only)_`);break}case"cost.recorded":await JP(t.trackId,n);break;default:break}}catch(o){let s=e?await e(t.trackId).catch(()=>null):null;await dv(t.trackId,s?.cwd??null,o)}}function Iv({resolveTrack:t}){Qt.on("event",e=>{YP(e,{resolveTrack:t}).catch(()=>{})})}async function Rv(){if(!kt())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 Ua(),r=0;for(let[o,s]of Object.entries(n))await Kt("tickets",{id:o,updatedAt:Date.now(),...s},{trackId:o}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}Ro();Ho();import XP from"ws";var $v=()=>process.env.BOSTRAT_SLACK_API_BASE||"https://slack.com/api";async function pl(t,e,n={}){let r=await fetch(`${$v()}/${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 bm=(t,e)=>pl("chat.postMessage",t,e),zr=(t,e)=>pl("chat.update",t,e);async function Jt(t,e){await fetch(t,{method:"POST",headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify(e)}).catch(()=>{})}async function ZP(t,e,n={}){let r=await fetch(`${$v()}/${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 Ov(t,{filename:e,buffer:n,title:r,channelId:o,threadTs:s,initialComment:a}){let{upload_url:i,file_id:c}=await ZP("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 pl("files.completeUploadExternal",t,{files:[{id:c,title:r}],channel_id:o,thread_ts:s,...a?{initial_comment:a}:{}})}var QP=2200;function Cv({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 pl("apps.connections.open",u))}catch(u){return n(`connections.open failed: ${u?.message||u}`),c()}o=new XP(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,h=setTimeout(()=>{p=!0,f()},QP);Promise.resolve().then(()=>e(d)).then(w=>{clearTimeout(h),!p&&(p=!0,f(d.accepts_response_payload?w:void 0))},w=>{clearTimeout(h),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 Pv=()=>process.env.BOSTRAT_STATE_DIR||hl.join(process.env.HOME||eB.tmpdir(),".bostrat"),Tm=()=>hl.join(Pv(),"slack.json"),ml=null,km=null,xm=Promise.resolve();async function Em(){return ml||(km??=Ha.readFile(Tm(),"utf8").then(t=>JSON.parse(t)?.threads??{}).catch(()=>({})).then(t=>ml=t).finally(()=>km=null),km)}async function Mv(){let t=JSON.stringify({threads:ml},null,2),e=`${Tm()}.${process.pid}.tmp`;await Ha.mkdir(Pv(),{recursive:!0}),await Ha.writeFile(e,t),await Ha.rename(e,Tm())}async function Ae(){xm=xm.then(Mv,Mv),await xm.catch(()=>{})}async function _m(t){return(await Em())[t]??null}async function nB(t,e){let n=await Em();for(let[r,o]of Object.entries(n))if(o.channel===t&&o.ts===e)return{trackId:r,rec:o};return null}var tt=t=>String(t??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");function Wa(t,e){let n=String(t??"").trim();return n.length<=e?n:`${n.slice(0,e-1).trimEnd()}\u2026`}function rB(t,e=500){let n=String(t??"").trim().split(/\n\s*\n/)[0]??"";return Wa(n.replace(/\n+/g," "),e)}function Bv(t){let e=`*${tt(t.name)}*${t.archivedAt?" \xB7 _archived_":""}`,n=`${tt(t.repoLabel)} \xB7 \`${tt(t.branch||"?")}\` \xB7 lead *${tt(t.lead)}*`,r=t.kickoff?`> ${tt(Wa(t.kickoff,300))}`:"_no kickoff yet \u2014 reply in this thread to steer the lead_";return[{type:"section",text:{type:"mrkdwn",text:`${e}
498
+ ${n}`}},{type:"section",text:{type:"mrkdwn",text:r}},{type:"context",elements:[{type:"mrkdwn",text:`<${dl(t.trackId)}|open the Track> \xB7 reachable on the operator's private network only`}]}]}async function Am(t,e){await zr(t.botToken,{channel:e.channel,ts:e.ts,text:`Track: ${e.name}`,blocks:Bv(e)})}async function tr(t,e,n,r=void 0){return bm(t.botToken,{channel:e.channel,thread_ts:e.ts,text:n,...r?{blocks:r}:{},unfurl_links:!1})}var Nv=new Set;function Qn(t){Nv.add(t),t.catch(()=>{}).finally(()=>Nv.delete(t))}var bt=t=>({response_type:"ephemeral",text:t}),oB="*/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._",sB=["claude","cursor","codex"];function vm(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 Sm=(t,e)=>bt(`No live Track matches \u201C${tt(e)}\u201D. Live: ${t.map(n=>`\`${tt(n.name)}\``).join(" \xB7 ")||"none"}`);async function Dv(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 Jt(o,{...bt(`At capacity \u2014 ${a.length} live Tracks (limit ${e.maxConcurrent}). Archive or stop something first.`),replace_original:!0});return}if(!e.channel){await Jt(o,{...bt("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?hl.basename(c.base):"fresh workspace"),lead:"claude"},u=await bm(e.botToken,{channel:e.channel,text:`Track started: ${l.name}`,blocks:Bv(l),unfurl_links:!1});l.ts=u.ts,(await Em())[i.id]=l,await Ae(),await Jt(o,{...bt(`\u2713 *${tt(l.name)}* started \u2014 root message posted.`),replace_original:!0})}catch(a){await Jt(o,{...bt(`Start failed: ${a?.message||a}`),replace_original:!0})}}async function aB(t,e,{track:n,responseUrl:r}){let o=t.deps;try{await o.archiveTrack(n.id);let s=await _m(n.id);s&&(s.archivedAt=Date.now(),await Ae(),await Am(e,s).catch(()=>{})),await Jt(r,{...bt(`\u2713 *${tt(n.name)}* archived.`),replace_original:!0})}catch(s){await Jt(r,{...bt(`Archive failed: ${s?.message||s}`),replace_original:!0})}}async function iB(t,e,{track:n,agent:r,responseUrl:o}){try{await t.deps.startLeadHandoff(n.id,r),await Jt(o,{...bt(`\u2713 Handing *${tt(n.name)}* to ${tt(r)} \u2014 the root message updates when the baton lands.`),replace_original:!0})}catch(s){await Jt(o,{...bt(`Handoff failed: ${s?.message||s}`),replace_original:!0})}}async function cB(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 Jt(r,{...bt(`\u2713 Stopped *${tt(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 Jt(r,{...bt(`Stop failed: ${s?.message||s}`),replace_original:!0})}}function lB(t,e){let n=[...e.slice(0,99).map(r=>({text:{type:"plain_text",text:Wa(`${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 *${tt(t)}*:`},accessory:{type:"static_select",action_id:"bostrat-start-repo",placeholder:{type:"plain_text",text:"Choose a repo"},options:n}}]}async function uB(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?hl.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 *${tt(s.name)}* \u2014 ${tt(i)}${a.branch?` \`${tt(a.branch)}\``:""} \xB7 lead ${tt(c)} \xB7 ${l}`}),o=e.length-n.length;return r.join(`
498
499
  `)+(o?`
499
- _${o} archived_`:"")}async function CP(t,e){let n=await Fr();if(!n)return St("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 St("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?(Yn(pS(t,n,{name:u,repo:l.path,responseUrl:e.response_url})),St(`Starting *${Q(u)}* on ${Q(l.name)}\u2026`)):{response_type:"ephemeral",text:`Pick a repo for \u201C${u}\u201D`,blocks:$P(u,i)}}case"archive":{if(!a.length)return St("Usage: `/bostrat archive <track>`");let{match:i,live:c}=lm(await r.listTracks(),a.join(" "));return i?(Yn(_P(t,n,{track:i,responseUrl:e.response_url})),St(`Archiving *${Q(i.name)}*\u2026`)):um(c,a.join(" "))}case"handoff":{let i=r.knownAgents??EP,c=a.at(-1)?.toLowerCase();if(a.length<2||!i.includes(c))return St(`Usage: \`/bostrat handoff <track> <${i.join("|")}>\``);let l=a.slice(0,-1).join(" "),{match:u,live:d}=lm(await r.listTracks(),l);return u?(Yn(IP(t,n,{track:u,agent:c,responseUrl:e.response_url})),St(`Handing *${Q(u.name)}* to ${Q(c)}\u2026`)):um(d,l)}case"stop":{if(!a.length)return St("Usage: `/bostrat stop <track>`");let{match:i,live:c}=lm(await r.listTracks(),a.join(" "));return i?(Yn(RP(t,n,{track:i,responseUrl:e.response_url})),St(`Stopping *${Q(i.name)}*\u2026`)):um(c,a.join(" "))}case"list":return St(await OP(r));default:return St(AP)}}async function MP(t,e,n,r){let{trackId:o,promptId:s,label:a}=r,i=await mm(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")}~
500
- \u2713 *${Q(a)}*`}}]}).catch(()=>{})}}catch(c){await zt(n.response_url,St(`Couldn't answer: ${c?.message||c}`))}}async function NP(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,Ao(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 zt(n.response_url,St(`Couldn't act on the offer: ${c?.message||c}`))}}async function PP(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 zt(n.response_url,St(`Couldn't act on the offer: ${i?.message||i}`))}}async function BP(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 zt(e.response_url,{...St(`Starting *${Q(s)}*\u2026`),replace_original:!0}),Yn(pS(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(MP(t,r,e,o)):n.action_id==="bostrat-ship"?Yn(NP(t,r,e,o)):n.action_id==="bostrat-pr-exists"&&Yn(PP(t,r,e,o))}async function DP(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 vP(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 jP(t){return async e=>{if(e.type==="slash_commands")return CP(t,e.payload);if(e.type==="interactive"){await BP(t,e.payload);return}if(e.type==="events_api"){await DP(t,e.payload?.event);return}}}var LP=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 FP(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:Na(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 UP(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",FP(n.trackId,r));e.prompt={promptId:r.promptId,ts:o.ts,question:r.question||null},await Te()}async function HP(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")}~
501
- \u2713 _answered_`}}]})}async function WP(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(Na(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 qP(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 KP(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 GP(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 VP(t,e,n,r){let o=n.payload||{};if(o.change==="ready"&&o.mockId){let s=await(r.readMockPng??zP)(o.mockId,o.version??null);if(!s)return;let a=(o.version??1)>1?` (v${o.version})`:"";await iS(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 zP(t,e){let n=await rn(t);if(!n)return null;let r=ve(n,e);if(!r)return null;let o=await Ma.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 JP(t,e){if(!LP.has(e.type))return;let n=await mm(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 fm(r,n);return;case"turn.agent":{if(!o.text)return;let s=TP(o.text);if(!s)return;await Xn(r,n,s,[{type:"section",text:{type:"mrkdwn",text:Q(s)}},{type:"context",elements:[{type:"mrkdwn",text:`<${el(e.trackId)}|full turn \u2192>`}]}]);return}case"prompt.raised":return UP(r,n,e);case"prompt.answered":return HP(r,n,e);case"pr.offered":return WP(r,n,e);case"pr.offer.answered":return qP(r,n,e);case"pr.exists.offered":return KP(r,n,e);case"pr.exists.answered":return GP(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 fm(r,n);return;case"view.state.changed":{if(o.change!=="created"||o.restarted||!o.slug)return;await Xn(r,n,`Live preview ${o.name}: ${nl(o.slug)}`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F50D} live preview *${Q(o.name)}*: ${nl(o.slug)}
502
- _runs on the Track's branch; reachable on the operator's private network only_`}}]);return}case"mock.state.changed":return VP(r,n,e,t.deps)}}function mS(t){let e={deps:t};Zt.on("event",s=>{JP(e,s).catch(()=>{})});let n=null,r=null,o=async()=>{n||!await Fr()||(r&&clearInterval(r),r=null,n=cS({getToken:async()=>(await Fr())?.appToken,onEnvelope:jP(e),log:s=>console.log(`[slack] ${s}`)}))};return r=setInterval(()=>o().catch(()=>{}),3e4),r.unref?.(),o().catch(()=>{}),()=>{r&&clearInterval(r),n?.()}}ye();ot();Ke();zd();Ds();import YP from"node:fs/promises";function XP(t){let e=new Map;for(let n of String(t||"").split(`
503
- `)){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 ZP(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 QP=new Set(["Write","Edit","NotebookEdit"]),tB=220,eB=160;function nB(t,e){let n=t?.tool_name??null,r={tool:n},o=t?.tool_input;if(!o||typeof o!="object")return r;if(QP.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,tB)}else n==="Bash"&&typeof o.command=="string"&&o.command.trim()&&(r.head=lr(o.command.trim().replace(/\s+/g," ")).slice(0,eB));return r}function rB(t,e){return t?.transcript_path?t.transcript_path:e?.cwd&&e?.sessionId?Ge(e.cwd,e.sessionId):e?.cwd?iu(e.cwd):null}async function hS(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=fc(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:nB(t,o)});break;case"Stop":await oB(r,o,t,i);break;default:break}return a}async function oB(t,e,n,r){let o=[],s=rB(n,e);if(s)try{o=XP(await YP.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=ZP(await F(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",h=u.get(f)||{tokens:{input:0,output:0,cacheWrite:0,cacheRead:0},messageIds:[]};for(let p of Object.keys(h.tokens))h.tokens[p]+=d.tokens[p];h.messageIds.push(d.messageId),u.set(f,h)}for(let[d,f]of u)await r({type:"cost.recorded",actor:"system",source:"transcript",payload:{model:d,usd:Cn(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}})}ls();ot();Yi();import iB from"node:fs";import wm from"node:fs/promises";import cB from"node:http";import Zo from"node:path";import cl from"node:os";import{createRequire as lB}from"node:module";import gm from"ws";import sB from"node:path";import aB from"node:os";var Pa=process.env.BOSTRAT_STATE_DIR||sB.join(process.env.HOME||aB.tmpdir(),".bostrat");function hm(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 wS(t=process.env){if(!t.BOSTRAT_PLANE_URL)return null;let e=hm(t);return e==="127.0.0.1"||e==="::1"||e==="localhost"?null:{host:e}}function gS(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 al=(()=>{try{return lB(import.meta.url)("../package.json").version||null}catch{return null}})(),uB=process.env.BOSTRAT_STATE_DIR||Zo.join(process.env.HOME||cl.tmpdir(),".bostrat");function dB(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 fB({home:t=process.env.HOME||cl.homedir(),env:e=process.env}={}){let n=r=>{try{return iB.statSync(r),!0}catch{return!1}};return{claude:n(Zo.join(t,".claude",".credentials.json")),codex:n(Zo.join(e.CODEX_HOME||Zo.join(t,".codex"),"auth.json"))}}var Dt=1,yS=1e3,pB=3e4,mB=6e4,hB=1500,wB=500,il=100,gB=2e3,yB=25e3,bB=6e4,kB=6e4,xB=6e4;function bS({url:t,token:e,nodeId:n=cl.hostname(),name:r=cl.hostname(),listTracks:o,detectAgents:s=null,onTracksTransferred:a=null,sampleMetrics:i=null,metricsMs:c=kB,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=gS(t);let d=l.replace(/^http/,"ws"),f=new Map,h=new Map,p=Zo.join(uB,"plane-link","cursor.json"),w={},y={},k=new Map,x=null,E=!1,$=!1,G=yS,C=null,N=null,T=null,B=null,j=null,at=!1,rt=0;async function A(){try{w=JSON.parse(await wm.readFile(p,"utf8"))}catch{w={}}}function D(){at=!0,!T&&(T=setTimeout(async()=>{if(T=null,!!at){at=!1;try{await wm.mkdir(Zo.dirname(p),{recursive:!0}),await wm.writeFile(p,JSON.stringify(w))}catch(b){u.error("[plane-link] cursor flush failed:",b?.message||b)}}},gB),T.unref?.())}function X(b){return!x||x.readyState!==gm.OPEN?!1:(x.send(JSON.stringify(b)),!0)}function bt(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:Dt,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 kt(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,D())}function xt(){if(!E)return;let b=Date.now(),_=[...k.values()].filter(R=>R.event&&b-R.sentAt>=bB);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+=il){let P=_.slice(R,R+il).map(wt=>({trackId:wt.trackId,event:wt.event}));if(!bt(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:Dt,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:Dt,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+=il){let Ht=wt.slice(ht,ht+il).map(ce=>({trackId:_.id,event:ce}));if(!bt(Ht))return}}}function O(b){!E||!b?.trackId||typeof b.id!="string"||bt([{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:Dt,ch:"control",type:"http_head",reqId:_,status:Ee.status,headers:wn}),Ee.body){for await(let le of Ee.body)if(!X({v:Dt,ch:"control",type:"http_data",reqId:_,data:Buffer.from(le).toString("base64")}))break}X({v:Dt,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=cB.request({host:ce.hostname,port:ce.port,method:wt,path:ht,headers:{..._,host:b.host},signal:R.signal},le=>{let{connection:vj,"keep-alive":Tj,"transfer-encoding":Aj,upgrade:Ej,...pT}=le.headers;X({v:Dt,ch:"control",type:"http_head",reqId:P,status:le.statusCode||502,headers:pT}),le.on("data",mT=>{X({v:Dt,ch:"control",type:"http_data",reqId:P,data:Buffer.from(mT).toString("base64")})||le.destroy()}),le.on("end",()=>{X({v:Dt,ch:"control",type:"http_end",reqId:P,error:null}),Ee()}),le.on("error",()=>{X({v:Dt,ch:"control",type:"http_end",reqId:P,error:"view upstream error"}),Ee()})});wn.on("error",le=>{X({v:Dt,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($)return;x=new gm(t,{headers:{authorization:`Bearer ${e}`}}),x.on("open",async()=>{let _=null;try{_=await s?.()||null}catch{_=null}X({v:Dt,ch:"ctl",type:"hello",nodeId:n,name:r,platform:process.platform,version:al,providers:fB(),..._?{agents:_}:{}})}),x.on("message",_=>{let R;try{R=JSON.parse(_)}catch{return}if(R.ch==="ctl"&&R.type==="hello_ok"){E=!0,G=yS,C=null,u.log(`[plane-link] connected to plane as ${n}`),R.minNodeVersion&&al&&dB(al,R.minNodeVersion)&&u.error(`[plane-link] this node is bostrat-node ${al}; the plane asks for \u2265${R.minNodeVersion} \u2014 update with: npm install -g bostrat-node`),B&&clearInterval(B),B=setInterval(()=>{X({v:Dt,ch:"ctl",type:"ping"}),xt()},yB),B.unref?.(),m(),v().catch(P=>u.error("[plane-link] backfill failed:",P?.message||P));return}if(R.ch==="ctl"&&R.type==="usage_caps"){Ji(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)kt(wt);return}if(R.ch==="control"&&R.type==="http_open"){ct(R).catch(P=>X({v:Dt,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 gm(d+R.path,Array.isArray(R.protocols)?R.protocols:[],R.host?{headers:{host:R.host}}:void 0);f.set(R.streamId,P),h.set(R.streamId,[]),P.on("open",()=>{let ht=h.get(R.streamId)||[];h.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:Dt,ch:"attach",type:"data",streamId:R.streamId,data:ce.toString("base64"),...Ht?{bin:!0}:{}})});let wt=()=>{h.delete(R.streamId),f.delete(R.streamId)&&X({v:Dt,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=f.get(R.streamId);if(!P)return;let wt=Buffer.from(R.data,"base64"),ht=R.bin===!0,Ht=h.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=f.get(R.streamId);f.delete(R.streamId),h.delete(R.streamId),P?.close();return}});let b=()=>{E&&u.log("[plane-link] disconnected from plane"),E=!1,B&&(clearInterval(B),B=null),j&&(clearInterval(j),j=null),k.clear(),y={};for(let P of f.values())P.close();f.clear(),h.clear();for(let P of it.values())P.abort();if(it.clear(),$||N)return;C==null&&(C=Date.now());let _=Date.now()-C<mB,R=_?hB+Math.random()*wB:G;N=setTimeout(()=>{N=null,sr()},R),N.unref?.(),_||(G=Math.min(G*2,pB))};x.on("close",b),x.on("error",_=>{let R=/Unexpected server response: (\d+)/.exec(_?.message||"")?.[1];(R==="401"||R==="403")&&Date.now()-rt>=xB&&(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",O),A().then(sr),{stop:()=>{$=!0,Zt.off("event",O),N&&clearTimeout(N),T&&clearTimeout(T),B&&clearInterval(B),j&&clearInterval(j),X({v:Dt,ch:"ctl",type:"bye",reason:"shutdown"}),x?.close()},status:()=>({connected:E,nodeId:n,cursor:{...w},inflight:k.size})}}import SB from"node:fs";import kS from"node:fs/promises";import Ba from"node:os";import vB from"node:path";Rf();Kt();var TB=1024*1024,ll=t=>Math.round(t/TB);async function AB(t){try{let e=await kS.statfs(t),n=e.blocks*e.bsize,r=n-e.bavail*e.bsize;return{diskUsedMb:ll(r),diskTotalMb:ll(n)}}catch{return{diskUsedMb:null,diskTotalMb:null}}}async function EB(){try{return(await ge()).filter(e=>e.isBostrat).length}catch{return null}}async function _B(){let t=0,e=!1;for(let n of["workspaces","worktrees"])try{let r=await kS.readdir(vB.join(Pa,n),{withFileTypes:!0});t+=r.filter(o=>o.isDirectory()).length,e=!0}catch{}return e?t:null}async function xS({stateDir:t=Pa,now:e=Date.now}={}){let n=Ba.totalmem(),[r,o,s,a]=await Promise.all([Ec().catch(()=>null),AB(SB.existsSync(t)?t:Ba.tmpdir()),EB(),_B()]),i=Ba.cpus()?.length||null,c=Ba.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?ll(n-r):null,memTotalMb:ll(n),...o,boxes:s,worktrees:a,procUptimeS:Math.round(process.uptime()),osUptimeS:Math.round(Ba.uptime())}}ot();bu();li();ot();wr();function ym(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 SS=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),vS=(t,e)=>{for(let n of Object.keys(t))t[n]+=e?.[n]||0},ul=t=>Math.round(t*1e4)/1e4;async function TS(t){let e=[],n={},r={},o=0,s=0,a=0,i=0,c=0,l=new Set,u=SS(),d=0,f=[];for(let h of t||[]){let p=await F(h),w=Mn(p,{boxLabels:ym(h)});if(w.turns===0){h.archivedAt?d++:f.push(h.name||h.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);vS(u,w.totalTokens);for(let[y,k]of Object.entries(w.byModel))n[y]||={usd:0,events:0,tokens:SS()},n[y].usd=ul(n[y].usd+k.usd),n[y].events+=k.events,vS(n[y].tokens,k.tokens);for(let[y,k]of Object.entries(w.byProvider))r[y]||={usd:0,events:0},r[y].usd=ul(r[y].usd+k.usd),r[y].events+=k.events;e.push({id:h.id,name:h.name,usd:w.totalUsd,rollup:w})}return e.sort((h,p)=>p.usd-h.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",fleet:{totalUsd:ul(o),asRecordedUsd:ul(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 Zn=t=>`$${t.toFixed(4)}`,Qo=(t,e)=>String(t).padEnd(e);function AS(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(` ${Qo(a,26)} ${Qo(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(` ${Qo(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(` ${Qo(c.label,40)} ${Qo(Zn(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))}${Qo(Zn(u.usd),10)} ${u.models.join(",")||"?"}`)}return r.join(`
504
- `)}ef();Yi();ot();Dd();import CB from"node:fs/promises";import MB from"node:path";yu();wr();var dl=t=>t.payload?.ts??t.ts,IB=12e4,Qn=t=>Math.round(t*1e4)/1e4,RB=()=>({usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},byTrack:new Map});function $B(t,{since:e}){let{track:n,events:r,brief:o}=t,s=x=>dl(x)>=e,a=pr([Rs(n?.name),Rs(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}),d=[...r].sort((x,E)=>dl(x)-dl(E)),f=0,h=0,p=0,w={turns:0};for(let x of d){let E=l(x.boxId),$=E.segments[E.segments.length-1],G=dl(x);switch(E.lastTs!=null&&G>E.lastTs&&s(x)&&($.activeMs+=Math.min(G-E.lastTs,IB)),E.lastTs=G,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&&($.tools[C]=($.tools[C]||0)+1),s(x)&&($.toolCalls+=1);break}case"cost.recorded":{if(!s(x))break;let{usd:C,tokens:N,model:T,unpriced:B}=Ve(x);B&&(w.turns+=1),$.usd+=C,N&&($.tokens.input+=N.input,$.tokens.output+=N.output,$.tokens.cacheRead+=N.cacheRead,$.tokens.cacheWrite+=N.cacheWrite),$.models[T]=($.models[T]||0)+C,x.provider&&($.provider=x.provider);break}case"handoff.done":s(x)&&(f+=1);break;case"subtask.merged":s(x)&&(h+=1);break;case"error":s(x)&&x.payload?.kind==="subtask-failed"&&(p+=1);break;default:break}}let y=new Map,k=!1;for(let[x,E]of c)for(let $ of E.segments){if(!($.usd>0||$.activeMs>0||$.turns>0||$.toolCalls>0))continue;let C=$.textCat?.category??i.get(x)?.category??ww($.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+=$.usd,N.activeMs+=$.activeMs,N.turns+=$.turns,N.toolCalls+=$.toolCalls;for(let[B,j]of Object.entries($.models))N.models[B]=(N.models[B]||0)+j;let T=$.provider||E.provider;T&&(N.providers[T]=(N.providers[T]||0)+$.usd),T==="cursor"&&$.usd===0&&(k=!0)}return{perCategory:y,handoffs:f,merged:h,failed:p,sawCursorActivity:k,unpricedTurns:w.turns}}function _S(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:$,failed:G,sawCursorActivity:C,unpricedTurns:N}=$B(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:$,subtasksFailed:G};for(let[B,j]of x){T.usd+=j.usd,T.activeMs+=j.activeMs,T.turns+=j.turns,T.categories[B]={usd:Qn(j.usd),activeMs:j.activeMs};for(let[A,D]of Object.entries(j.models))T.models[A]=Qn((T.models[A]||0)+D);for(let[A,D]of Object.entries(j.providers))T.providers[A]=Qn((T.providers[A]||0)+D);o.has(B)||o.set(B,RB());let at=o.get(B);at.usd+=j.usd,at.activeMs+=j.activeMs,at.turns+=j.turns,at.toolCalls+=j.toolCalls;for(let[A,D]of Object.entries(j.models))at.models[A]=(at.models[A]||0)+D;for(let[A,D]of Object.entries(j.providers))at.providers[A]=(at.providers[A]||0)+D;let rt=at.byTrack.get(y?.id)||{usd:0,activeMs:0};rt.usd+=j.usd,rt.activeMs+=j.activeMs,at.byTrack.set(y?.id,rt)}(T.usd>0||T.activeMs>0||T.turns>0)&&(T.usd=Qn(T.usd),T.dominantCategory=OB(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),d=l>0?"usd":"time",f=d==="usd"?l:u,h=new Map((t||[]).map(w=>[w.track?.id,w.track?.name||w.track?.id])),p=[...o.entries()].map(([w,y])=>({category:w,sharePct:f>0?Math.round((d==="usd"?y.usd:y.activeMs)/f*100):0,shareBasis:d,usd:Qn(y.usd),activeMs:y.activeMs,turns:y.turns,toolCalls:y.toolCalls,models:ES(y.models),providers:ES(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:h.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:p,workstreams:s,gaps:{tracksWithoutEvents:a,cursorCostUnknown:i,unpricedTurns:c}}}var OB=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},ES=t=>Object.fromEntries(Object.entries(t).map(([e,n])=>[e,Qn(n)]));var ts={"24h":24*36e5,"7d":168*36e5,"30d":720*36e5,all:null};function NB(t){let e=String(t||"7d");return e in ts?{key:e,ms:ts[e]}:{key:"7d",ms:ts["7d"]}}function PB(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=Qi(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 BB(t){if(!t?.cwd)return null;try{let n=(await CB.readFile(MB.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 IS(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}:NB(e),d=[];for(let f of t||[]){let h=await F(f),p=PB(f,h);i&&c<o&&(p=p.filter(w=>(w.ts??0)<=c)),d.push({track:f,events:p,brief:await BB(f)})}return{window:l,..._S(d,{windowMs:u,now:c})}}ot();wr();var tr=36e5,CS=24*tr,DB=400,jB=12,es=t=>Math.round(t*1e4)/1e4;function LB({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 ts?String(t||"7d"):"7d",i=ts[a];return{key:a,since:i==null?null:r-i,until:r}}var FB=(t,e)=>t!=null&&e-t<=48*tr?tr:CS;function RS(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 UB(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}),OS=(t,e)=>{for(let n of Object.keys(t))t[n]+=e?.[n]||0},HB=t=>Object.fromEntries(Object.entries(t).map(([e,n])=>[e,es(n)]));async function MS(t,e={}){let n=e.now??Date.now(),r=LB({...e,now:n}),o=r.since==null?CS:FB(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(),d=0,f=0,h=0,p=0,w=0,y=new Set,k=new Map,x=[],E=[],$=[],G=null;for(let T of t||[]){let j=(await F(T)).filter(A=>A.type==="cost.recorded");if(!j.length){T.archivedAt||$.push(T.name||T.id);continue}let at=[];for(let A of j){let D=A.ts??0;s(D)?at.push(A):i(D)&&(w+=Ve(A).usd)}if(!at.length)continue;let rt=Mn(at,{boxLabels:ym(T)});d+=rt.totalUsd,f+=rt.turns,h+=rt.repricedTurns||0,p+=rt.unpricedTurns||0;for(let A of rt.unpricedModels||[])y.add(A);OS(u,rt.totalTokens);for(let[A,D]of Object.entries(rt.byModel))c[A]||={usd:0,events:0,tokens:$S()},c[A].usd=es(c[A].usd+D.usd),c[A].events+=D.events,OS(c[A].tokens,D.tokens);for(let[A,D]of Object.entries(rt.byProvider))l[A]||={usd:0,events:0},l[A].usd=es(l[A].usd+D.usd),l[A].events+=D.events;for(let A of at){let{usd:D}=Ve(A);if(!D)continue;let X=RS(A.ts??0,o),bt=k.get(X)??{t:X,total:0,byProvider:{}};bt.total+=D;let dt=A.provider||"unknown";bt.byProvider[dt]=(bt.byProvider[dt]||0)+D,k.set(X,bt),(G==null||X<G)&&(G=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,D]of Object.entries(rt.byBox))E.push({trackId:T.id,trackName:T.name||T.id,boxId:A,...D})}let C=r.since!=null?RS(r.since,o):G,N=[];for(let T=C,B=0;T!=null&&T<r.until&&B<DB;T=UB(T,o),B++){let j=k.get(T);N.push(j?{t:T,total:es(j.total),byProvider:HB(j.byProvider)}:{t:T,total:0,byProvider:{}})}return x.sort((T,B)=>B.usd-T.usd),E.sort((T,B)=>B.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:es(d),turns:f,repricedTurns:h,unpricedTurns:p,unpricedModels:[...y],totalTokens:u,byModel:c,byProvider:l,tracksWithCost:x.length,tracksSilentLive:$},prior:a!=null?{totalUsd:es(w),since:r.since-a,until:r.since}:null,tracks:x.slice(0,50),boxes:E.slice(0,jB)}}Wt();import ns from"node:fs/promises";import WB from"node:fs";import Ft from"node:path";import qB from"node:os";import{execFile as KB}from"node:child_process";import{promisify as GB}from"node:util";var VB=GB(KB),NS=process.env.BOSTRAT_STATE_DIR||Ft.join(process.env.HOME||qB.tmpdir(),".bostrat"),fl=!1,bm=null;async function km(t,e){let n=await ns.stat(t).catch(()=>null);if(!n?.isFile())return!1;let r=await ns.stat(e).catch(()=>null);return r&&r.size===n.size&&r.mtimeMs>=n.mtimeMs?!1:(await ns.mkdir(Ft.dirname(e),{recursive:!0}),await ns.copyFile(t,e),!0)}var zB=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 pl(t,e,{skip:n=null}={}){let r=0,o=await ns.readdir(t,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(zB.has(s.name)||n?.has(s.name))continue;let a=Ft.join(t,s.name);s.isDirectory()?r+=await pl(a,Ft.join(e,s.name)):s.isFile()&&(r+=await km(a,Ft.join(e,s.name))?1:0)}return r}async function PS({stateDir:t=NS,dest:e=process.env.BOSTRAT_SYNC_DIR||`${NS}-sync`,remote:n=process.env.BOSTRAT_STATE_REMOTE||null,tracks:r=null}={}){try{await ns.mkdir(e,{recursive:!0});let o=0;o+=await km(Ft.join(t,"tracks.json"),Ft.join(e,"tracks.json"))?1:0,o+=await km(Ft.join(t,"events.jsonl"),Ft.join(e,"events.jsonl"))?1:0,o+=await pl(Ft.join(t,"events"),Ft.join(e,"events")),o+=await pl(Ft.join(t,"memory"),Ft.join(e,"memory"));let s=new Set(["mocks"]);for(let u of r||[])!u?.cwd||!u?.id||(o+=await pl(Ft.join(u.cwd,".bostrat"),Ft.join(e,"workspaces",u.id,".bostrat"),{skip:s}));let a=(...u)=>VB("git",["-C",e,...u]);WB.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 Ll(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||fl))try{await a("push","-q",n,"HEAD:refs/heads/main"),l=!0,fl&&console.log("[state-sync] push recovered \u2014 off-box copy is current again"),fl=!1,bm=null}catch(u){fl=!0;let d=(u?.stderr||u?.message||String(u)).trim().split(`
505
- `).slice(-3).join(" | ").slice(0,300);d!==bm&&(bm=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)}}}zf();ye();uo();Kt();us();import{execFile as JB}from"node:child_process";import{promisify as YB}from"node:util";import{randomUUID as XB}from"node:crypto";import ZB from"node:fs";import QB from"node:os";import tD from"node:path";var nr=YB(JB),ml=t=>new Promise(e=>setTimeout(e,t)),rr=eu,xm=process.env.BOSTRAT_USAGE_PROBE_CWD||tD.join(QB.homedir(),".bostrat","usage-probe"),eD=Number(process.env.BOSTRAT_USAGE_IDLE_REAP_MS)||5*6e4,nD=Number(process.env.BOSTRAT_USAGE_PANEL_TIMEOUT_MS)||15e3,rD=Number(process.env.BOSTRAT_USAGE_READY_TIMEOUT_MS)||45e3,BS=Number(process.env.BOSTRAT_USAGE_CACHE_MS)||2e4,er=null,Da=null,ja=null;async function oD(){try{return await nr(L,U("has-session","-t",rr)),!0}catch{return!1}}function sD(){er&&clearTimeout(er),er=setTimeout(()=>aD().catch(()=>{}),eD),er.unref&&er.unref()}async function aD(){er&&(clearTimeout(er),er=null);try{await nr(L,U("kill-session","-t",rr))}catch{}}async function iD(){let t=Date.now()+rD;for(;;){let e=await Sm().catch(()=>"");if(/for agents|for shortcuts|bypass permissions on/i.test(e)){await ml(500);return}if(Date.now()>t)throw new Error("usage probe didn't reach the prompt (trust/onboarding may be blocking)");await ml(500)}}async function cD(){if(await oD())return;if(!await Tn())throw new Error("host tmux server not running \u2014 start globo-tmux.service");ZB.mkdirSync(xm,{recursive:!0}),await gn(xm);let t=XB();await nr(L,U("new-session","-d","-s",rr,"-c",xm,"-x","200","-y","60",...tu()));let e=`${Ql} --session-id ${t}`;await nr(L,U("send-keys","-t",rr,e,"Enter")),await iD()}async function Sm(){let{stdout:t}=await nr(L,U("capture-pane","-t",rr,"-p"));return t}async function lD(){await cD(),await nr(L,U("send-keys","-t",rr,"-l","/usage")),await nr(L,U("send-keys","-t",rr,"Enter"));let t=Date.now()+nD,e="";for(;await ml(400),e=await Sm(),!(/Current\s+(session|week)/i.test(e)||/\d+%\s*used/i.test(e)||Date.now()>t););return await ml(900),e=await Sm(),await nr(L,U("send-keys","-t",rr,"Escape")).catch(()=>{}),sD(),e}function uD(t){let e=String(t||"").split(`
506
- `).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 dD(t){let e=String(t||"").split(`
507
- `).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&&Da&&Date.now()-Da.at<BS?Da.data:ja||(ja=(async()=>{try{let e=await lD(),n=uD(e),r={...n,contributors:dD(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()-(BS-3e3),data:n},n}finally{ja=null}})(),ja)}var fD=262144;function pD(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 mD=new Set([300]),hD=new Set([10080]);function wD(t){let e=Number(t);return!Number.isFinite(e)||e<=0?null:mD.has(e)?"session":hD.has(e)?"week":"other"}function gD(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 yD(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?pD((o-n)/1e3):null,resetsAt:o}}var La=t=>({session:null,week:null,other:null,planType:null,credits:null,limitReached:null,sawTokenCount:t});function bD(t,e=Date.now()){let n=String(t||"").split(`
508
- `),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 La(r);if(c.primary||c.secondary){let l=Date.parse(a.timestamp)||null,u=La(r);[c.primary,c.secondary].forEach((h,p)=>{let w=yD(h,l,e);if(!w)return;let y=wD(h.window_minutes);y===null&&(y=p===0?"session":"week"),y==="session"&&!u.session?u.session=w:y==="week"&&!u.week?u.week=w:(u.other??=[]).push({label:gD(h.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{...La(r),session:l(c.primary_used_percent),week:l(c.secondary_used_percent)}}return La(r)}return La(r)}async function vm(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,fD),o=bD(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 jS(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 hl({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 vm(i);if(c.subscription){a=c;break}(!a||a.error&&!c.error)&&(a=c)}r.push(a||await vm(null))}return n.has("cursor")&&r.push(await hl({agent:"cursor"})),{providers:r,capturedAt:Date.now()}}async function hl(t,{fresh:e=!1}={}){let n=t?.agent||"claude";return n==="codex"?vm(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})}}ar();Wt();Wt();function kD(t=process.env){return!!(gt(t)&&t.BOSTRAT_PLANE_TOKEN)}var xD=t=>({authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`}),wl=(t,e)=>Object.assign(new Error(t),{status:e});async function LS(t,e){if(!kD(e))throw wl("node is not plane-linked \u2014 Gmail unavailable",503);let n;try{n=await fetch(`${gt(e)}${t}`,{headers:xD(e)})}catch(o){throw wl(`plane unreachable \u2014 Gmail unavailable (${o?.message||o})`,503)}let r=await n.json().catch(()=>({}));if(!n.ok)throw wl(r?.error||`plane replied ${n.status}`,n.status);return r}async function FS(t,{max:e=10,env:n=process.env}={}){let r=new URLSearchParams({q:t||""});return e&&r.set("max",String(e)),(await LS(`/v1/gmail/messages?${r.toString()}`,n)).messages||[]}async function US(t,{env:e=process.env}={}){if(!t)throw wl("message id required",400);return(await LS(`/v1/gmail/messages/${encodeURIComponent(t)}`,e)).message}Hs();Sc();function Tm(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 SD(t){let[e,n]=t.split("/"),r=Tm(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 HS(t){return(t||"").split(",").map(e=>e.trim()).filter(Boolean).map(SD).filter(Boolean)}function vD(t){let e=t.headers["fly-client-ip"];return typeof e=="string"&&e.trim()?e.trim():(t.socket&&t.socket.remoteAddress||"").replace(/^::ffff:/,"")}function WS(t){let e=HS(t),n=String(t||"").trim().toLowerCase()==="open";return{open:n,clientIp:vD,allowed(r){if(n)return!0;let o=Tm((r||"").replace(/^::ffff:/,""));return o==null?!1:e.some(s=>s(o))}}}function qS(t,e){let n=HS(t);return{active:n.length>0,allows(r){if(!n.length)return!1;let o=(r.socket&&r.socket.remoteAddress||"").replace(/^::ffff:/,""),s=Tm(o);if(s==null||!n.some(i=>i(s)))return!1;let a=e(r);return!!(a&&a.view)}}}import KS from"node:crypto";import gl from"node:fs";import TD from"node:path";function GS(t=process.env,{stateDir:e=Pa,log:n=console}={}){let r=String(t.BOSTRAT_NODE_API_TOKEN||"").trim();if(r)return r;let o=TD.join(e,"api-token");try{let a=gl.readFileSync(o,"utf8").trim();if(a)return a}catch{}let s=KS.randomBytes(32).toString("base64url");try{gl.mkdirSync(e,{recursive:!0}),gl.writeFileSync(o,s+`
509
- `,{mode:384}),gl.chmodSync(o,384)}catch(a){n.error?.(`[bostrat-agent] could not persist the node API token: ${a?.message||a}`)}return s}function Fa(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 VS(t,e){if(!t||!e)return!1;let n=Buffer.from(String(t)),r=Buffer.from(String(e));return n.length!==r.length?!1:KS.timingSafeEqual(n,r)}function zS(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 AD=[/^\/api\/github\/token\b/,/^\/api\/gmail\b/],ED=t=>AD.some(e=>e.test(t));function JS({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=zS(o);return VS(c,t)?a():ED(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||Fa(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 YS(t,e,{enforce:n=!0}={}){return!n||VS(zS(t),e)?!0:Fa(t)}Ke();bc();bc();import _D from"node:http";import ID from"node:net";function yl(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 bl(t){let e=yl(t.headers.host);return e?{slug:e,view:hf(e)}:null}var RD=t=>String(t??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;"),$D=t=>{let e=RD(t.name);return`<!doctype html><meta charset="utf-8">
500
+ _${o} archived_`:"")}async function dB(t,e){let n=await Kr();if(!n)return bt("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 bt("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(Dv(t,n,{name:u,repo:l.path,responseUrl:e.response_url})),bt(`Starting *${tt(u)}* on ${tt(l.name)}\u2026`)):{response_type:"ephemeral",text:`Pick a repo for \u201C${u}\u201D`,blocks:lB(u,i)}}case"archive":{if(!a.length)return bt("Usage: `/bostrat archive <track>`");let{match:i,live:c}=vm(await r.listTracks(),a.join(" "));return i?(Qn(aB(t,n,{track:i,responseUrl:e.response_url})),bt(`Archiving *${tt(i.name)}*\u2026`)):Sm(c,a.join(" "))}case"handoff":{let i=r.knownAgents??sB,c=a.at(-1)?.toLowerCase();if(a.length<2||!i.includes(c))return bt(`Usage: \`/bostrat handoff <track> <${i.join("|")}>\``);let l=a.slice(0,-1).join(" "),{match:u,live:d}=vm(await r.listTracks(),l);return u?(Qn(iB(t,n,{track:u,agent:c,responseUrl:e.response_url})),bt(`Handing *${tt(u.name)}* to ${tt(c)}\u2026`)):Sm(d,l)}case"stop":{if(!a.length)return bt("Usage: `/bostrat stop <track>`");let{match:i,live:c}=vm(await r.listTracks(),a.join(" "));return i?(Qn(cB(t,n,{track:i,responseUrl:e.response_url})),bt(`Stopping *${tt(i.name)}*\u2026`)):Sm(c,a.join(" "))}case"list":return bt(await uB(r));default:return bt(oB)}}async function fB(t,e,n,r){let{trackId:o,promptId:s,label:a}=r,i=await _m(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 Ae(),await zr(e.botToken,{channel:i.channel,ts:c,text:`\u2713 ${a}`,blocks:[{type:"section",text:{type:"mrkdwn",text:`~${tt(l||"question")}~
501
+ \u2713 *${tt(a)}*`}}]}).catch(()=>{})}}catch(c){await Jt(n.response_url,bt(`Couldn't answer: ${c?.message||c}`))}}async function pB(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,Io(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 Jt(n.response_url,bt(`Couldn't act on the offer: ${c?.message||c}`))}}async function mB(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 Jt(n.response_url,bt(`Couldn't act on the offer: ${i?.message||i}`))}}async function hB(t,e){let n=e.actions?.[0];if(!n?.action_id)return;let r=await Kr();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 Jt(e.response_url,{...bt(`Starting *${tt(s)}*\u2026`),replace_original:!0}),Qn(Dv(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(fB(t,r,e,o)):n.action_id==="bostrat-ship"?Qn(pB(t,r,e,o)):n.action_id==="bostrat-pr-exists"&&Qn(mB(t,r,e,o))}async function wB(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 nB(e.channel,e.thread_ts);if(!n)return;let r=await Kr();if(r)try{await t.deps.sayToLead(n.trackId,e.text.trim())}catch(o){await tr(r,n.rec,`Couldn't deliver that to the lead: ${o?.message||o}`).catch(()=>{})}}function gB(t){return async e=>{if(e.type==="slash_commands")return dB(t,e.payload);if(e.type==="interactive"){await hB(t,e.payload);return}if(e.type==="events_api"){await wB(t,e.payload?.event);return}}}var yB=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 bB(t,e){let n=[{type:"section",text:{type:"mrkdwn",text:`\u2753 ${tt(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:Wa(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 kB(t,e,n){let r=n.payload||{};if(!r.promptId||e.prompt?.promptId===r.promptId)return;e.prompt&&await zr(t.botToken,{channel:e.channel,ts:e.prompt.ts,text:"superseded",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${tt(e.prompt.question||"question")}~ _superseded_`}}]}).catch(()=>{});let o=await tr(t,e,r.question||"The lead needs an answer",bB(n.trackId,r));e.prompt={promptId:r.promptId,ts:o.ts,question:r.question||null},await Ae()}async function xB(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 Ae(),await zr(t.botToken,{channel:e.channel,ts:o,text:"answered",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${tt(s||"question")}~
502
+ \u2713 _answered_`}}]})}async function vB(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 tr(t,e,r.excerpt||"Ship it?",[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${tt(Wa(r.excerpt||"The lead offered to ship.",300))}`}},{type:"actions",elements:s}]);e.offers=e.offers||{},e.offers[r.offerId]=a.ts,await Ae()}async function SB(t,e,n){let r=n.payload||{},o=e.offers?.[r.offerId];if(!o)return;delete e.offers[r.offerId],await Ae();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 zr(t.botToken,{channel:e.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function TB(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 tr(t,e,`PR ${o} already open \u2014 push or new PR?`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${o}${r.branch?` (${tt(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 Ae()}async function AB(t,e,n){let r=n.payload||{},o=e.offers?.[r.offerId];if(!o)return;delete e.offers[r.offerId],await Ae();let s=r.choice==="dismiss"?"dismissed":r.choice==="new"?"\u2713 opening a new PR":"\u2713 pushing to the open PR";await zr(t.botToken,{channel:e.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function EB(t,e,n,r){let o=n.payload||{};if(o.change==="ready"&&o.mockId){let s=await(r.readMockPng??_B)(o.mockId,o.version??null);if(!s)return;let a=(o.version??1)>1?` (v${o.version})`:"";await Ov(t.botToken,{filename:s.filename,buffer:s.buffer,title:`${o.name}${a}`,channelId:e.channel,threadTs:e.ts,initialComment:`\u{1F3A8} mock *${tt(o.name)}*${a}${o.group?` (group \`${tt(o.group)}\`)`:""}`})}else if(o.change==="picked"){let s=(o.siblings??[]).map(a=>`*${tt(a.name)}*`).join(", ");await tr(t,e,`Design decision: ${o.name} picked`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F3A8} design decision: *${tt(o.name)}* picked${s?` over ${s}`:""}`}}])}}async function _B(t,e){let n=await an(t);if(!n)return null;let r=Te(n,e);if(!r)return null;let o=await Ha.readFile(me(n,r.v).png).catch(()=>null);return o?{filename:`${n.name.replace(/[^\w.-]+/g,"-")}.v${r.v}.png`,buffer:o}:null}async function IB(t,e){if(!yB.has(e.type))return;let n=await _m(e.trackId);if(!n)return;let r=await Kr();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 Ae(),await Am(r,n);return;case"turn.agent":{if(!o.text)return;let s=rB(o.text);if(!s)return;await tr(r,n,s,[{type:"section",text:{type:"mrkdwn",text:tt(s)}},{type:"context",elements:[{type:"mrkdwn",text:`<${dl(e.trackId)}|full turn \u2192>`}]}]);return}case"prompt.raised":return kB(r,n,e);case"prompt.answered":return xB(r,n,e);case"pr.offered":return vB(r,n,e);case"pr.offer.answered":return SB(r,n,e);case"pr.exists.offered":return TB(r,n,e);case"pr.exists.answered":return AB(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 tr(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 Ae(),await Am(r,n);return;case"view.state.changed":{if(o.change!=="created"||o.restarted||!o.slug)return;await tr(r,n,`Live preview ${o.name}: ${fl(o.slug)}`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F50D} live preview *${tt(o.name)}*: ${fl(o.slug)}
503
+ _runs on the Track's branch; reachable on the operator's private network only_`}}]);return}case"mock.state.changed":return EB(r,n,e,t.deps)}}function jv(t){let e={deps:t};Qt.on("event",s=>{IB(e,s).catch(()=>{})});let n=null,r=null,o=async()=>{n||!await Kr()||(r&&clearInterval(r),r=null,n=Cv({getToken:async()=>(await Kr())?.appToken,onEnvelope:gB(e),log:s=>console.log(`[slack] ${s}`)}))};return r=setInterval(()=>o().catch(()=>{}),3e4),r.unref?.(),o().catch(()=>{}),()=>{r&&clearInterval(r),n?.()}}ke();st();Ge();rf();Vs();import RB from"node:fs/promises";function $B(t){let e=new Map;for(let n of String(t||"").split(`
504
+ `)){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 OB(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 CB=new Set(["Write","Edit","NotebookEdit"]),MB=220,NB=160;function PB(t,e){let n=t?.tool_name??null,r={tool:n},o=t?.tool_input;if(!o||typeof o!="object")return r;if(CB.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,MB)}else n==="Bash"&&typeof o.command=="string"&&o.command.trim()&&(r.head=dr(o.command.trim().replace(/\s+/g," ")).slice(0,NB));return r}function BB(t,e){return t?.transcript_path?t.transcript_path:e?.cwd&&e?.sessionId?ze(e.cwd,e.sessionId):e?.cwd?gu(e.cwd):null}async function Lv(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=bc(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:PB(t,o)});break;case"Stop":await DB(r,o,t,i);break;default:break}return a}async function DB(t,e,n,r){let o=[],s=BB(n,e);if(s)try{o=$B(await RB.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=OB(await B(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 h of Object.keys(p.tokens))p.tokens[h]+=d.tokens[h];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:Nn(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}})}ys();st();oc();import FB from"node:fs";import Rm from"node:fs/promises";import UB from"node:http";import ss from"node:path";import yl from"node:os";import{createRequire as HB}from"node:module";import $m from"ws";import jB from"node:path";import LB from"node:os";var qa=process.env.BOSTRAT_STATE_DIR||jB.join(process.env.HOME||LB.tmpdir(),".bostrat");function Im(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 Fv(t=process.env){if(!t.BOSTRAT_PLANE_URL)return null;let e=Im(t);return e==="127.0.0.1"||e==="::1"||e==="localhost"?null:{host:e}}function Uv(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 wl=(()=>{try{return HB(import.meta.url)("../package.json").version||null}catch{return null}})(),WB=process.env.BOSTRAT_STATE_DIR||ss.join(process.env.HOME||yl.tmpdir(),".bostrat");function qB(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 KB({home:t=process.env.HOME||yl.homedir(),env:e=process.env}={}){let n=r=>{try{return FB.statSync(r),!0}catch{return!1}};return{claude:n(ss.join(t,".claude",".credentials.json")),codex:n(ss.join(e.CODEX_HOME||ss.join(t,".codex"),"auth.json"))}}var jt=1,Hv=1e3,GB=3e4,VB=6e4,zB=1500,JB=500,gl=100,YB=2e3,XB=25e3,ZB=6e4,QB=6e4,tD=6e4;function Wv({url:t,token:e,nodeId:n=yl.hostname(),name:r=yl.hostname(),listTracks:o,detectAgents:s=null,onTracksTransferred:a=null,sampleMetrics:i=null,metricsMs:c=QB,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=Uv(t);let d=l.replace(/^http/,"ws"),f=new Map,p=new Map,h=ss.join(WB,"plane-link","cursor.json"),w={},y={},k=new Map,x=null,A=!1,R=!1,V=Hv,M=null,N=null,T=null,D=null,F=null,ct=!1,Q=0;async function _(){try{w=JSON.parse(await Rm.readFile(h,"utf8"))}catch{w={}}}function U(){ct=!0,!T&&(T=setTimeout(async()=>{if(T=null,!!ct){ct=!1;try{await Rm.mkdir(ss.dirname(h),{recursive:!0}),await Rm.writeFile(h,JSON.stringify(w))}catch(b){u.error("[plane-link] cursor flush failed:",b?.message||b)}}},YB),T.unref?.())}function j(b){return!x||x.readyState!==$m.OPEN?!1:(x.send(JSON.stringify(b)),!0)}function at(b){let E=Date.now();for(let{trackId:O,event:P}of b){let wt=k.get(P.id);k.set(P.id,{trackId:O,seq:P.seq,event:P,sentAt:E,tries:(wt?.tries??0)+1})}return j({v:jt,ch:"events",type:"append",events:b})}function Et(b){let E=null;for(let O of k.values())O.trackId===b&&(E==null||O.seq<E)&&(E=O.seq);return E}function Lt(b){let E=y[b];if(E==null)return;let O=Et(b),P=O==null?E:Math.min(E,O-1);P>(w[b]??0)&&(w[b]=P,U())}function it(){if(!A)return;let b=Date.now(),E=[...k.values()].filter(O=>O.event&&b-O.sentAt>=ZB);if(E.length){E.sort((O,P)=>O.trackId===P.trackId?O.seq-P.seq:O.trackId<P.trackId?-1:1),u.log(`[plane-link] re-sending ${E.length} unacked event(s) the plane never confirmed`);for(let O=0;O<E.length;O+=gl){let P=E.slice(O,O+gl).map(wt=>({trackId:wt.trackId,event:wt.event}));if(!at(P))return}}}async function g(){if(!i)return;let b;try{b=await i()}catch(E){u.error("[plane-link] metrics sample failed:",E?.message||E);return}b&&j({v:jt,ch:"ctl",type:"metrics",metrics:b})}function m(){i&&(F&&clearInterval(F),g(),F=setInterval(g,c),F.unref?.())}async function S(){let b;try{b=await o()}catch(E){u.error("[plane-link] backfill listTracks failed:",E?.message||E);return}j({v:jt,ch:"ctl",type:"tracks",ids:b.filter(E=>!E.transferredTo).map(E=>E.id).filter(E=>typeof E=="string")});for(let E of b){if(!A)return;let O;try{O=await B(E)}catch{continue}let P=w[E.id]??0,wt=O.filter(mt=>mt.seq>P&&typeof mt.id=="string");for(let mt=0;mt<wt.length;mt+=gl){let Wt=wt.slice(mt,mt+gl).map(le=>({trackId:E.id,event:le}));if(!at(Wt))return}}}function $(b){!A||!b?.trackId||typeof b.id!="string"||at([{trackId:b.trackId,event:b}])}let lt=new Map;async function ht(b){let{reqId:E,method:O,path:P,headers:wt={},body:mt}=b,Wt=Object.fromEntries(Object.entries(wt).filter(([,_e])=>_e!=null)),le=new AbortController;lt.set(E,le);try{if(b.host){await vt(b,Wt,le);return}let _e=await fetch(l+P,{method:O,headers:Wt,body:mt?Buffer.from(mt,"base64"):void 0,signal:le.signal}),bn=Object.fromEntries(_e.headers);for(let ue of["connection","keep-alive","transfer-encoding","upgrade","content-encoding","content-length"])delete bn[ue];if(bn["content-type"]||(bn["content-type"]="application/octet-stream"),j({v:jt,ch:"control",type:"http_head",reqId:E,status:_e.status,headers:bn}),_e.body){for await(let ue of _e.body)if(!j({v:jt,ch:"control",type:"http_data",reqId:E,data:Buffer.from(ue).toString("base64")}))break}j({v:jt,ch:"control",type:"http_end",reqId:E,error:null})}finally{lt.delete(E)}}function vt(b,E,O){let{reqId:P,method:wt,path:mt,body:Wt}=b,le=new URL(l);return new Promise(_e=>{let bn=UB.request({host:le.hostname,port:le.port,method:wt,path:mt,headers:{...E,host:b.host},signal:O.signal},ue=>{let{connection:sL,"keep-alive":aL,"transfer-encoding":iL,upgrade:cL,...NT}=ue.headers;j({v:jt,ch:"control",type:"http_head",reqId:P,status:ue.statusCode||502,headers:NT}),ue.on("data",PT=>{j({v:jt,ch:"control",type:"http_data",reqId:P,data:Buffer.from(PT).toString("base64")})||ue.destroy()}),ue.on("end",()=>{j({v:jt,ch:"control",type:"http_end",reqId:P,error:null}),_e()}),ue.on("error",()=>{j({v:jt,ch:"control",type:"http_end",reqId:P,error:"view upstream error"}),_e()})});bn.on("error",ue=>{j({v:jt,ch:"control",type:"http_end",reqId:P,error:ue?.message||"view request failed"}),_e()}),Wt&&bn.write(Buffer.from(Wt,"base64")),bn.end()})}function Ct(){if(R)return;x=new $m(t,{headers:{authorization:`Bearer ${e}`}}),x.on("open",async()=>{let E=null;try{E=await s?.()||null}catch{E=null}j({v:jt,ch:"ctl",type:"hello",nodeId:n,name:r,platform:process.platform,version:wl,providers:KB(),...E?{agents:E}:{}})}),x.on("message",E=>{let O;try{O=JSON.parse(E)}catch{return}if(O.ch==="ctl"&&O.type==="hello_ok"){A=!0,V=Hv,M=null,u.log(`[plane-link] connected to plane as ${n}`),O.minNodeVersion&&wl&&qB(wl,O.minNodeVersion)&&u.error(`[plane-link] this node is bostrat-node ${wl}; the plane asks for \u2265${O.minNodeVersion} \u2014 update with: npm install -g bostrat-node`),D&&clearInterval(D),D=setInterval(()=>{j({v:jt,ch:"ctl",type:"ping"}),it()},XB),D.unref?.(),m(),S().catch(P=>u.error("[plane-link] backfill failed:",P?.message||P));return}if(O.ch==="ctl"&&O.type==="usage_caps"){rc(O.caps??{},{source:"plane",updatedAt:O.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(O.ch==="ctl"&&O.type==="transferred"&&Array.isArray(O.tracks)){Promise.resolve().then(()=>a?.(O.tracks)).catch(P=>u.error("[plane-link] transfer notice failed:",P?.message||P));return}if(O.ch==="events"&&O.type==="ack"&&Array.isArray(O.ids)){let P=new Set;for(let wt of O.ids){let mt=k.get(wt);mt&&(k.delete(wt),(y[mt.trackId]??0)<mt.seq&&(y[mt.trackId]=mt.seq),P.add(mt.trackId))}for(let wt of P)Lt(wt);return}if(O.ch==="control"&&O.type==="http_open"){ht(O).catch(P=>j({v:jt,ch:"control",type:"http_end",reqId:O.reqId,error:P?.message||"tunnel error"}));return}if(O.ch==="control"&&O.type==="http_cancel"){lt.get(O.reqId)?.abort();return}if(O.ch==="attach"&&O.type==="open"){let P=new $m(d+O.path,Array.isArray(O.protocols)?O.protocols:[],O.host?{headers:{host:O.host}}:void 0);f.set(O.streamId,P),p.set(O.streamId,[]),P.on("open",()=>{let mt=p.get(O.streamId)||[];p.delete(O.streamId);for(let{buf:Wt,bin:le}of mt)P.send(Wt,{binary:le})}),P.on("message",(mt,Wt)=>{let le=Wt?mt:Buffer.from(String(mt));j({v:jt,ch:"attach",type:"data",streamId:O.streamId,data:le.toString("base64"),...Wt?{bin:!0}:{}})});let wt=()=>{p.delete(O.streamId),f.delete(O.streamId)&&j({v:jt,ch:"attach",type:"close",streamId:O.streamId})};P.on("close",wt),P.on("error",wt);return}if(O.ch==="attach"&&O.type==="data"){let P=f.get(O.streamId);if(!P)return;let wt=Buffer.from(O.data,"base64"),mt=O.bin===!0,Wt=p.get(O.streamId);Wt?Wt.push({buf:wt,bin:mt}):P.send(wt,{binary:mt});return}if(O.ch==="attach"&&O.type==="close"){let P=f.get(O.streamId);f.delete(O.streamId),p.delete(O.streamId),P?.close();return}});let b=()=>{A&&u.log("[plane-link] disconnected from plane"),A=!1,D&&(clearInterval(D),D=null),F&&(clearInterval(F),F=null),k.clear(),y={};for(let P of f.values())P.close();f.clear(),p.clear();for(let P of lt.values())P.abort();if(lt.clear(),R||N)return;M==null&&(M=Date.now());let E=Date.now()-M<VB,O=E?zB+Math.random()*JB:V;N=setTimeout(()=>{N=null,Ct()},O),N.unref?.(),E||(V=Math.min(V*2,GB))};x.on("close",b),x.on("error",E=>{let O=/Unexpected server response: (\d+)/.exec(E?.message||"")?.[1];(O==="401"||O==="403")&&Date.now()-Q>=tD&&(Q=Date.now(),u.error(`[plane-link] plane refused this node's credentials (HTTP ${O}) \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 Qt.on("event",$),_().then(Ct),{stop:()=>{R=!0,Qt.off("event",$),N&&clearTimeout(N),T&&clearTimeout(T),D&&clearInterval(D),F&&clearInterval(F),j({v:jt,ch:"ctl",type:"bye",reason:"shutdown"}),x?.close()},status:()=>({connected:A,nodeId:n,cursor:{...w},inflight:k.size})}}import eD from"node:fs";import qv from"node:fs/promises";import Ka from"node:os";import nD from"node:path";Uf();Gt();var rD=1024*1024,bl=t=>Math.round(t/rD);async function oD(t){try{let e=await qv.statfs(t),n=e.blocks*e.bsize,r=n-e.bavail*e.bsize;return{diskUsedMb:bl(r),diskTotalMb:bl(n)}}catch{return{diskUsedMb:null,diskTotalMb:null}}}async function sD(){try{return(await be()).filter(e=>e.isBostrat).length}catch{return null}}async function aD(){let t=0,e=!1;for(let n of["workspaces","worktrees"])try{let r=await qv.readdir(nD.join(qa,n),{withFileTypes:!0});t+=r.filter(o=>o.isDirectory()).length,e=!0}catch{}return e?t:null}async function Kv({stateDir:t=qa,now:e=Date.now}={}){let n=Ka.totalmem(),[r,o,s,a]=await Promise.all([Pc().catch(()=>null),oD(eD.existsSync(t)?t:Ka.tmpdir()),sD(),aD()]),i=Ka.cpus()?.length||null,c=Ka.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?bl(n-r):null,memTotalMb:bl(n),...o,boxes:s,worktrees:a,procUptimeS:Math.round(process.uptime()),osUptimeS:Math.round(Ka.uptime())}}st();ju();wi();st();kr();function Om(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 Gv=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),Vv=(t,e)=>{for(let n of Object.keys(t))t[n]+=e?.[n]||0},kl=t=>Math.round(t*1e4)/1e4;async function zv(t){let e=[],n={},r={},o=0,s=0,a=0,i=0,c=0,l=new Set,u=Gv(),d=0,f=[];for(let p of t||[]){let h=await B(p),w=Pn(h,{boxLabels:Om(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);Vv(u,w.totalTokens);for(let[y,k]of Object.entries(w.byModel))n[y]||={usd:0,events:0,tokens:Gv()},n[y].usd=kl(n[y].usd+k.usd),n[y].events+=k.events,Vv(n[y].tokens,k.tokens);for(let[y,k]of Object.entries(w.byProvider))r[y]||={usd:0,events:0},r[y].usd=kl(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:kl(o),asRecordedUsd:kl(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 er=t=>`$${t.toFixed(4)}`,as=(t,e)=>String(t).padEnd(e);function Jv(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 ${er(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 ${er(e.asRecordedUsd)} \xB7 current-rates total ${er(e.totalUsd)} (${e.totalUsd>=e.asRecordedUsd?"+":""}${er(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(` ${as(a,26)} ${as(er(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(` ${as(a.name||a.id,30)} ${er(a.usd)}`);let i=Object.values(a.rollup.byBox).sort((c,l)=>l.usd-c.usd);for(let c of i)if(r.push(` ${as(c.label,40)} ${as(er(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))}${as(er(u.usd),10)} ${u.models.join(",")||"?"}`)}return r.join(`
505
+ `)}mf();oc();st();Gd();import dD from"node:fs/promises";import fD from"node:path";Du();kr();var xl=t=>t.payload?.ts??t.ts,iD=12e4,nr=t=>Math.round(t*1e4)/1e4,cD=()=>({usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},byTrack:new Map});function lD(t,{since:e}){let{track:n,events:r,brief:o}=t,s=x=>xl(x)>=e,a=yr([Hs(n?.name),Hs(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 A=yr(x.payload.task);A&&i.set(x.boxId,A)}let c=new Map,l=x=>{let A=x||"unattributed";return c.has(A)||c.set(A,{segments:[u(null)],lastTs:null,provider:null}),c.get(A)},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}),d=[...r].sort((x,A)=>xl(x)-xl(A)),f=0,p=0,h=0,w={turns:0};for(let x of d){let A=l(x.boxId),R=A.segments[A.segments.length-1],V=xl(x);switch(A.lastTs!=null&&V>A.lastTs&&s(x)&&(R.activeMs+=Math.min(V-A.lastTs,iD)),A.lastTs=V,x.provider&&(A.provider=x.provider),x.type){case"turn.user":{let M=x.payload?.text;if(x.source==="hook"||!String(M||"").trim())break;let N=u(yr(M));A.segments.push(N),s(x)&&(N.turns+=1);break}case"peer.message":{let M=x.payload?.text;if(!String(M||"").trim())break;let N=u(yr(M));A.segments.push(N),s(x)&&(N.turns+=1);break}case"tool.called":{if(x.source==="transcript")break;let M=x.payload?.tool;M&&(R.tools[M]=(R.tools[M]||0)+1),s(x)&&(R.toolCalls+=1);break}case"cost.recorded":{if(!s(x))break;let{usd:M,tokens:N,model:T,unpriced:D}=Je(x);D&&(w.turns+=1),R.usd+=M,N&&(R.tokens.input+=N.input,R.tokens.output+=N.output,R.tokens.cacheRead+=N.cacheRead,R.tokens.cacheWrite+=N.cacheWrite),R.models[T]=(R.models[T]||0)+M,x.provider&&(R.provider=x.provider);break}case"handoff.done":s(x)&&(f+=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,A]of c)for(let R of A.segments){if(!(R.usd>0||R.activeMs>0||R.turns>0||R.toolCalls>0))continue;let M=R.textCat?.category??i.get(x)?.category??Ww(R.tools)?.category??a?.category??"uncategorized";y.has(M)||y.set(M,{usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{}});let N=y.get(M);N.usd+=R.usd,N.activeMs+=R.activeMs,N.turns+=R.turns,N.toolCalls+=R.toolCalls;for(let[D,F]of Object.entries(R.models))N.models[D]=(N.models[D]||0)+F;let T=R.provider||A.provider;T&&(N.providers[T]=(N.providers[T]||0)+R.usd),T==="cursor"&&R.usd===0&&(k=!0)}return{perCategory:y,handoffs:f,merged:p,failed:h,sawCursorActivity:k,unpricedTurns:w.turns}}function Xv(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:A,merged:R,failed:V,sawCursorActivity:M,unpricedTurns:N}=lD(w,{since:r});M&&(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:A,subtasksMerged:R,subtasksFailed:V};for(let[D,F]of x){T.usd+=F.usd,T.activeMs+=F.activeMs,T.turns+=F.turns,T.categories[D]={usd:nr(F.usd),activeMs:F.activeMs};for(let[_,U]of Object.entries(F.models))T.models[_]=nr((T.models[_]||0)+U);for(let[_,U]of Object.entries(F.providers))T.providers[_]=nr((T.providers[_]||0)+U);o.has(D)||o.set(D,cD());let ct=o.get(D);ct.usd+=F.usd,ct.activeMs+=F.activeMs,ct.turns+=F.turns,ct.toolCalls+=F.toolCalls;for(let[_,U]of Object.entries(F.models))ct.models[_]=(ct.models[_]||0)+U;for(let[_,U]of Object.entries(F.providers))ct.providers[_]=(ct.providers[_]||0)+U;let Q=ct.byTrack.get(y?.id)||{usd:0,activeMs:0};Q.usd+=F.usd,Q.activeMs+=F.activeMs,ct.byTrack.set(y?.id,Q)}(T.usd>0||T.activeMs>0||T.turns>0)&&(T.usd=nr(T.usd),T.dominantCategory=uD(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),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])),h=[...o.entries()].map(([w,y])=>({category:w,sharePct:f>0?Math.round((d==="usd"?y.usd:y.activeMs)/f*100):0,shareBasis:d,usd:nr(y.usd),activeMs:y.activeMs,turns:y.turns,toolCalls:y.toolCalls,models:Yv(y.models),providers:Yv(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:nr(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:nr(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 uD=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},Yv=t=>Object.fromEntries(Object.entries(t).map(([e,n])=>[e,nr(n)]));var is={"24h":24*36e5,"7d":168*36e5,"30d":720*36e5,all:null};function pD(t){let e=String(t||"7d");return e in is?{key:e,ms:is[e]}:{key:"7d",ms:is["7d"]}}function mD(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=ic(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 hD(t){if(!t?.cwd)return null;try{let n=(await dD.readFile(fD.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 Zv(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}:pD(e),d=[];for(let f of t||[]){let p=await B(f),h=mD(f,p);i&&c<o&&(h=h.filter(w=>(w.ts??0)<=c)),d.push({track:f,events:h,brief:await hD(f)})}return{window:l,...Xv(d,{windowMs:u,now:c})}}st();kr();var rr=36e5,nS=24*rr,wD=400,gD=12,cs=t=>Math.round(t*1e4)/1e4;function yD({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 is?String(t||"7d"):"7d",i=is[a];return{key:a,since:i==null?null:r-i,until:r}}var bD=(t,e)=>t!=null&&e-t<=48*rr?rr:nS;function Qv(t,e){if(e===rr)return Math.floor(t/rr)*rr;let n=new Date(t);return n.setHours(0,0,0,0),n.getTime()}function kD(t,e){if(e===rr)return t+rr;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},xD=t=>Object.fromEntries(Object.entries(t).map(([e,n])=>[e,cs(n)]));async function rS(t,e={}){let n=e.now??Date.now(),r=yD({...e,now:n}),o=r.since==null?nS:bD(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=tS(),d=0,f=0,p=0,h=0,w=0,y=new Set,k=new Map,x=[],A=[],R=[],V=null;for(let T of t||[]){let F=(await B(T)).filter(_=>_.type==="cost.recorded");if(!F.length){T.archivedAt||R.push(T.name||T.id);continue}let ct=[];for(let _ of F){let U=_.ts??0;s(U)?ct.push(_):i(U)&&(w+=Je(_).usd)}if(!ct.length)continue;let Q=Pn(ct,{boxLabels:Om(T)});d+=Q.totalUsd,f+=Q.turns,p+=Q.repricedTurns||0,h+=Q.unpricedTurns||0;for(let _ of Q.unpricedModels||[])y.add(_);eS(u,Q.totalTokens);for(let[_,U]of Object.entries(Q.byModel))c[_]||={usd:0,events:0,tokens:tS()},c[_].usd=cs(c[_].usd+U.usd),c[_].events+=U.events,eS(c[_].tokens,U.tokens);for(let[_,U]of Object.entries(Q.byProvider))l[_]||={usd:0,events:0},l[_].usd=cs(l[_].usd+U.usd),l[_].events+=U.events;for(let _ of ct){let{usd:U}=Je(_);if(!U)continue;let j=Qv(_.ts??0,o),at=k.get(j)??{t:j,total:0,byProvider:{}};at.total+=U;let Et=_.provider||"unknown";at.byProvider[Et]=(at.byProvider[Et]||0)+U,k.set(j,at),(V==null||j<V)&&(V=j)}x.push({id:T.id,name:T.name||T.id,archived:!!T.archivedAt,usd:Q.totalUsd,turns:Q.turns,providers:Object.keys(Q.byProvider)});for(let[_,U]of Object.entries(Q.byBox))A.push({trackId:T.id,trackName:T.name||T.id,boxId:_,...U})}let M=r.since!=null?Qv(r.since,o):V,N=[];for(let T=M,D=0;T!=null&&T<r.until&&D<wD;T=kD(T,o),D++){let F=k.get(T);N.push(F?{t:T,total:cs(F.total),byProvider:xD(F.byProvider)}:{t:T,total:0,byProvider:{}})}return x.sort((T,D)=>D.usd-T.usd),A.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:cs(d),turns:f,repricedTurns:p,unpricedTurns:h,unpricedModels:[...y],totalTokens:u,byModel:c,byProvider:l,tracksWithCost:x.length,tracksSilentLive:R},prior:a!=null?{totalUsd:cs(w),since:r.since-a,until:r.since}:null,tracks:x.slice(0,50),boxes:A.slice(0,gD)}}qt();import ls from"node:fs/promises";import vD from"node:fs";import Ut from"node:path";import SD from"node:os";import{execFile as TD}from"node:child_process";import{promisify as AD}from"node:util";var ED=AD(TD),oS=process.env.BOSTRAT_STATE_DIR||Ut.join(process.env.HOME||SD.tmpdir(),".bostrat"),vl=!1,Cm=null;async function Mm(t,e){let n=await ls.stat(t).catch(()=>null);if(!n?.isFile())return!1;let r=await ls.stat(e).catch(()=>null);return r&&r.size===n.size&&r.mtimeMs>=n.mtimeMs?!1:(await ls.mkdir(Ut.dirname(e),{recursive:!0}),await ls.copyFile(t,e),!0)}var _D=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 Sl(t,e,{skip:n=null}={}){let r=0,o=await ls.readdir(t,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(_D.has(s.name)||n?.has(s.name))continue;let a=Ut.join(t,s.name);s.isDirectory()?r+=await Sl(a,Ut.join(e,s.name)):s.isFile()&&(r+=await Mm(a,Ut.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 ls.mkdir(e,{recursive:!0});let o=0;o+=await Mm(Ut.join(t,"tracks.json"),Ut.join(e,"tracks.json"))?1:0,o+=await Mm(Ut.join(t,"events.jsonl"),Ut.join(e,"events.jsonl"))?1:0,o+=await Sl(Ut.join(t,"events"),Ut.join(e,"events")),o+=await Sl(Ut.join(t,"memory"),Ut.join(e,"memory"));let s=new Set(["mocks"]);for(let u of r||[])!u?.cwd||!u?.id||(o+=await Sl(Ut.join(u.cwd,".bostrat"),Ut.join(e,"workspaces",u.id,".bostrat"),{skip:s}));let a=(...u)=>ED("git",["-C",e,...u]);vD.existsSync(Ut.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||vl))try{await a("push","-q",n,"HEAD:refs/heads/main"),l=!0,vl&&console.log("[state-sync] push recovered \u2014 off-box copy is current again"),vl=!1,Cm=null}catch(u){vl=!0;let d=(u?.stderr||u?.message||String(u)).trim().split(`
506
+ `).slice(-3).join(" | ").slice(0,300);d!==Cm&&(Cm=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)}}}ap();ke();wr();Gt();bs();import{execFile as ID}from"node:child_process";import{promisify as RD}from"node:util";import{randomUUID as $D}from"node:crypto";import OD from"node:fs";import CD from"node:os";import MD from"node:path";var sr=RD(ID),Tl=t=>new Promise(e=>setTimeout(e,t)),ar=du,Nm=process.env.BOSTRAT_USAGE_PROBE_CWD||MD.join(CD.homedir(),".bostrat","usage-probe"),ND=Number(process.env.BOSTRAT_USAGE_IDLE_REAP_MS)||5*6e4,PD=Number(process.env.BOSTRAT_USAGE_PANEL_TIMEOUT_MS)||15e3,BD=Number(process.env.BOSTRAT_USAGE_READY_TIMEOUT_MS)||45e3,aS=Number(process.env.BOSTRAT_USAGE_CACHE_MS)||2e4,or=null,Ga=null,Va=null;async function DD(){try{return await sr(L,H("has-session","-t",ar)),!0}catch{return!1}}function jD(){or&&clearTimeout(or),or=setTimeout(()=>LD().catch(()=>{}),ND),or.unref&&or.unref()}async function LD(){or&&(clearTimeout(or),or=null);try{await sr(L,H("kill-session","-t",ar))}catch{}}async function FD(){let t=Date.now()+BD;for(;;){let e=await Pm().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 UD(){if(await DD())return;if(!await _n())throw new Error("host tmux server not running \u2014 start globo-tmux.service");OD.mkdirSync(Nm,{recursive:!0}),await kn(Nm);let t=$D();await sr(L,H("new-session","-d","-s",ar,"-c",Nm,"-x","200","-y","60",...uu()));let e=`${lu} --session-id ${t}`;await sr(L,H("send-keys","-t",ar,e,"Enter")),await FD()}async function Pm(){let{stdout:t}=await sr(L,H("capture-pane","-t",ar,"-p"));return t}async function HD(){await UD(),await sr(L,H("send-keys","-t",ar,"-l","/usage")),await sr(L,H("send-keys","-t",ar,"Enter"));let t=Date.now()+PD,e="";for(;await Tl(400),e=await Pm(),!(/Current\s+(session|week)/i.test(e)||/\d+%\s*used/i.test(e)||Date.now()>t););return await Tl(900),e=await Pm(),await sr(L,H("send-keys","-t",ar,"Escape")).catch(()=>{}),jD(),e}function WD(t){let e=String(t||"").split(`
507
+ `).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 qD(t){let e=String(t||"").split(`
508
+ `).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 iS({fresh:t=!1}={}){return!t&&Ga&&Date.now()-Ga.at<aS?Ga.data:Va||(Va=(async()=>{try{let e=await HD(),n=WD(e),r={...n,contributors:qD(e),subscription:!!(n.session||n.week||n.weekModels),capturedAt:Date.now()};return Ga={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 Ga={at:Date.now()-(aS-3e3),data:n},n}finally{Va=null}})(),Va)}var KD=262144;function GD(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 VD=new Set([300]),zD=new Set([10080]);function JD(t){let e=Number(t);return!Number.isFinite(e)||e<=0?null:VD.has(e)?"session":zD.has(e)?"week":"other"}function YD(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 XD(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?GD((o-n)/1e3):null,resetsAt:o}}var za=t=>({session:null,week:null,other:null,planType:null,credits:null,limitReached:null,sawTokenCount:t});function ZD(t,e=Date.now()){let n=String(t||"").split(`
509
+ `),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 za(r);if(c.primary||c.secondary){let l=Date.parse(a.timestamp)||null,u=za(r);[c.primary,c.secondary].forEach((p,h)=>{let w=XD(p,l,e);if(!w)return;let y=JD(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:YD(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{...za(r),session:l(c.primary_used_percent),week:l(c.secondary_used_percent)}}return za(r)}return za(r)}async function Bm(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 Zt(n.file,KD),o=ZD(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 cS(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 Al({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 Bm(i);if(c.subscription){a=c;break}(!a||a.error&&!c.error)&&(a=c)}r.push(a||await Bm(null))}return n.has("cursor")&&r.push(await Al({agent:"cursor"})),{providers:r,capturedAt:Date.now()}}async function Al(t,{fresh:e=!1}={}){let n=t?.agent||"claude";return n==="codex"?Bm(t):n==="cursor"?{provider:"cursor",supported:!1,subscription:!1,session:null,week:null,contributors:null,capturedAt:Date.now()}:{provider:"claude",supported:!0,...await iS({fresh:e})}}cr();qt();qt();function QD(t=process.env){return!!(gt(t)&&t.BOSTRAT_PLANE_TOKEN)}var t1=t=>({authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`}),El=(t,e)=>Object.assign(new Error(t),{status:e});async function lS(t,e){if(!QD(e))throw El("node is not plane-linked \u2014 Gmail unavailable",503);let n;try{n=await fetch(`${gt(e)}${t}`,{headers:t1(e)})}catch(o){throw El(`plane unreachable \u2014 Gmail unavailable (${o?.message||o})`,503)}let r=await n.json().catch(()=>({}));if(!n.ok)throw El(r?.error||`plane replied ${n.status}`,n.status);return r}async function uS(t,{max:e=10,env:n=process.env}={}){let r=new URLSearchParams({q:t||""});return e&&r.set("max",String(e)),(await lS(`/v1/gmail/messages?${r.toString()}`,n)).messages||[]}async function dS(t,{env:e=process.env}={}){if(!t)throw El("message id required",400);return(await lS(`/v1/gmail/messages/${encodeURIComponent(t)}`,e)).message}Zs();Oc();function Dm(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 e1(t){let[e,n]=t.split("/"),r=Dm(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 fS(t){return(t||"").split(",").map(e=>e.trim()).filter(Boolean).map(e1).filter(Boolean)}function n1(t){let e=t.headers["fly-client-ip"];return typeof e=="string"&&e.trim()?e.trim():(t.socket&&t.socket.remoteAddress||"").replace(/^::ffff:/,"")}function pS(t){let e=fS(t),n=String(t||"").trim().toLowerCase()==="open";return{open:n,clientIp:n1,allowed(r){if(n)return!0;let o=Dm((r||"").replace(/^::ffff:/,""));return o==null?!1:e.some(s=>s(o))}}}function mS(t,e){let n=fS(t);return{active:n.length>0,allows(r){if(!n.length)return!1;let o=(r.socket&&r.socket.remoteAddress||"").replace(/^::ffff:/,""),s=Dm(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 _l from"node:fs";import r1 from"node:path";function wS(t=process.env,{stateDir:e=qa,log:n=console}={}){let r=String(t.BOSTRAT_NODE_API_TOKEN||"").trim();if(r)return r;let o=r1.join(e,"api-token");try{let a=_l.readFileSync(o,"utf8").trim();if(a)return a}catch{}let s=hS.randomBytes(32).toString("base64url");try{_l.mkdirSync(e,{recursive:!0}),_l.writeFileSync(o,s+`
510
+ `,{mode:384}),_l.chmodSync(o,384)}catch(a){n.error?.(`[bostrat-agent] could not persist the node API token: ${a?.message||a}`)}return s}function Ja(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 gS(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 yS(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 o1=[/^\/api\/github\/token\b/,/^\/api\/gmail\b/],s1=t=>o1.some(e=>e.test(t));function bS({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=yS(o);return gS(c,t)?a():s1(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||Ja(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 kS(t,e,{enforce:n=!0}={}){return!n||gS(yS(t),e)?!0:Ja(t)}Ge();Ic();Ic();import a1 from"node:http";import i1 from"node:net";function Il(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 Rl(t){let e=Il(t.headers.host);return e?{slug:e,view:_f(e)}:null}var c1=t=>String(t??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;"),l1=t=>{let e=c1(t.name);return`<!doctype html><meta charset="utf-8">
510
511
  <meta http-equiv="refresh" content="3">
511
512
  <title>${e} \u2014 starting</title>
512
513
  <body style="font-family:system-ui;background:#0b0e14;color:#dce3f0;display:grid;place-items:center;height:100vh;margin:0">
513
514
  <div style="text-align:center"><p style="font-size:2rem;margin:0">\u23F3</p>
514
- <p><b>${e}</b> is waking up\u2026</p><p style="opacity:.6">auto-refreshing</p></div>`};function XS(t,e,n){let r=bl(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($D(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=_D.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 ZS(t,e,n){let r=bl(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
515
+ <p><b>${e}</b> is waking up\u2026</p><p style="opacity:.6">auto-refreshing</p></div>`};function xS(t,e,n){let r=Rl(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(l1(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=a1.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 vS(t,e,n){let r=Rl(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
515
516
  \r
516
517
  bostrat: no live view "${s}"\r
517
- `),e.destroy(),!0;let a=ID.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
518
+ `),e.destroy(),!0;let a=i1.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
518
519
  `)+`\r
519
520
  \r
520
- `),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 QS(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}.${OD(n.host)}/`}function OD(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 yl(e)&&hf(n[0])?n.slice(1).join("."):e}Bo();Df();Oc();Wt();var tv=1e4,ev=(...t)=>fetch(...t);function nv(t=process.env){return!!(gt(t)&&t.BOSTRAT_PLANE_TOKEN)}async function rv({loopId:t,outcome:e,note:n=null,env:r=process.env}={}){if(!nv(r))return{ok:!1,source:"unconfigured"};let o=new AbortController,s=setTimeout(()=>o.abort(),tv);try{let a=await ev(`${gt(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 Am({env:t=process.env}={}){if(!nv(t))return{loops:[],source:"unconfigured"};let e=new AbortController,n=setTimeout(()=>e.abort(),tv);try{let r=await ev(`${gt(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)}}ot();import{randomUUID as CD}from"node:crypto";var ov=32768,sv=120,av=1e3,iv=new Set(["claude","codex","cursor"]),MD=new Set(["off","transition","nag"]),ND=[[0,59],[0,23],[1,31],[1,12],[0,6]];function PD(t){let e=String(t??"").trim().split(/\s+/);return e.length!==5?!1:e.every((n,r)=>{let[o,s]=ND[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 BD(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>sv)throw new Error(`name is too long (${r.length}); cap is ${sv}`);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(!PD(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>ov)throw new Error(`prompt is too long (${s.length} chars); cap is ${ov}`);let a=mn(n.expectation)||null;if(a&&a.length>av)throw new Error(`expectation is too long (${a.length}); cap is ${av}`);let i=mn(n.notify)||"off";if(!MD.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(!iv.has(l))throw new Error(`unknown provider "${l}" \u2014 one of ${[...iv].join(", ")}`);let u=typeof c=="object"&&c&&mn(c.model)||null,d=mn(e?.workspace?.repo)||mn(e?.workspace?.base)||null;if(!d)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:d}}async function cv(t,e){let n=BD(e,t),r=CD();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 lv(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();ot();Fn();Oc();var uv=10,dv=200,DD=120,jD=24,LD=/^\d{4}-\d{2}-\d{2}$/;function Em(t=process.env){return(t.CHANGELOG_REPOS||"globocodes/bostrat").split(",").map(e=>e.trim()).filter(Boolean)}var FD=(t=Date.now())=>new Date(t).toISOString().slice(0,10);function fv(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 UD=/^\*\*([^*]+?)\*\*\s*[:.]?\s*[—–-]?\s*(.*)$/;function HD(t){if(typeof t!="string"||!t.trim())throw new Error("md (markdown string) required");let e=ca(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(`
521
- `)){let s=o.trim();if(!s)continue;if(s.startsWith("#")){n==null&&(n=s.replace(/^#+\s*/,"").trim().slice(0,DD)||null);continue}let a=/^[-*]\s+(.*)$/.exec(s);if(!a)continue;let i=a[1].trim(),c=null,l=new RegExp(`^\\[([^\\]]{1,${jD}})\\]\\s+(.*)$`).exec(i);if(l&&(c=l[1].trim(),i=l[2].trim()),!i)continue;let u=UD.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>dv)throw new Error(`bullet ${r.length+1} is ${i.length} chars \u2014 over the ${dv}-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>uv)throw new Error(`${r.length} bullets \u2014 over the ${uv}-bullet cap; group related changes into one line`);return{title:n||null,bullets:r}}async function pv(t,{repos:e=Em()}={}){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 mv(t,{md:e,day:n=null}){let r=HD(e),o=n==null||n===""?FD():String(n);if(!LD.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}}oa();Fn();ot();oa();Wt();Rr();Fn();Hs();Sc();import{execFile as WD}from"node:child_process";import{promisify as qD}from"node:util";var Im=qD(WD),hv=3e4,KD=30*6e4,GD=hv,VD=10*6e4,zD=10080*6e4,JD=60*6e4,YD=8,XD=1440*6e4,ZD=3,wv="number,url,title,headRefName,headRefOid,state,mergedAt,closedAt",_m=60*6e4,QD=15*6e4,kl=new Map,xl=new Map,t1=/could not resolve|not found|no pull requests?/i,e1=t=>t1.test(String(t?.message||t||""));function n1(t,e){return[t.ciFix?.delegatedAt,t.reconcile?.delegatedAt,t.ciFixAwait?.since,t.reconcileAwait?.since].some(n=>n&&e-n<_m)}var gv={fast:GD,slow:VD,decay:JD};function yv(t,e){return t.armedAt&&e-t.armedAt<KD||n1(t,e)?"fast":e-(t.firstSeen||0)>zD?"decay":"slow"}function r1(t,e){return gv[yv(t,e)]}function qa(t,e,n,r){let o=t.lanes?.get(z(e.repo,e.number))||{};return xc({change:n,repo:e.repo,number:Number(e.number),githubAt:r||null,lane:o.lane||null,intervalMs:o.intervalMs||null,source:"watch"})}async function o1(t,e){Ye("watch");try{let{stdout:n}=await Im("gh",["pr","view",String(e),"--repo",t,"--json",wv],{timeout:3e4,maxBuffer:4194304,env:{...process.env,...await _e({slug:t})}});return JSON.parse(n||"null")}catch(n){throw Bn(n)&&Dn(n),n}}async function s1(t){Ye("watch");try{let{stdout:e}=await Im("gh",["pr","list","--repo",t,"--state","all","--limit","100","--json",wv],{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 Bn(e)&&Dn(e),e}}async function a1(){let t=new Map;for(let e of await nt().catch(()=>[]))t.set(e.id,e);return t}async function i1(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 c1(t,e){let n=await Or(t);return n?Co(n,e):null}async function l1(t,e,n){let r=await Or(t);if(!r)throw new Error(`no local checkout for ${t}`);return Mo(r,e,{method:n})}async function u1(t,e){let n=await Or(t);if(!n)throw new Error(`no local checkout for ${t}`);return ra(n,e)}async function d1(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 rs(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 f1=10*6e4;async function p1(t,e,n){let r=t.autoMerge?.armedAt||0;if(r&&(n.now??Date.now())-r>XD){await rs(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 rs(t,o,e,n,`check${o.checks.failed===1?"":"s"} failed: ${a}`);return}if(o.mergeable==="CONFLICTING"){await rs(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<f1)return;await rs(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 rs(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 rs(t,o,e,n,String(a?.message||a).trim()||"merge failed");return}await bv(t,{...o,state:"MERGED"},e,n,{change:"auto-merged",githubAt:o.checks.settledAt||null})}}async function Ua(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 m1(t,e){try{return await Im("git",["-C",t.cwd,"cat-file","-e",`${e}^{commit}`],{timeout:1e4}),!0}catch{return!1}}async function Ha(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 Wa=(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 h1(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 sc(t.repo,t.number,{headSha:s}).catch(()=>{}),t.reconcile?.headSha&&s!==t.reconcile.headSha&&await ic(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<QD;await _b(t.repo,t.number,s).catch(()=>{}),t.baseFoldAt&&await Eb(t.repo,t.number).catch(()=>{}),!i&&!c&&!l&&a&&!await r.localHasCommit(a,s).catch(()=>!1)&&!await Ha(a,"pushed",t.number,d=>d.payload?.sha===s)&&await Ua(a,"pushed",{...Wa(t,e),sha:s}).catch(()=>{})}if(t.ciFixAwait)if(o-(t.ciFixAwait.since||0)>_m)await ac(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 ac(t.repo,t.number).catch(()=>{});else if(i.checks.total>0&&i.checks.pending===0){let c=qa(r,t,"ci-fixed",i.checks.settledAt||null),l=t.ciFixAwait.since||0;a&&!await Ha(a,"ci-fixed",t.number,u=>(u.payload?.ts||0)>=l)&&await Ua(a,"ci-fixed",{...Wa(t,e),passed:i.checks.passed,githubAt:c.githubAt,latencyMs:c.latencyMs,lane:c.lane}).catch(()=>{}),await ac(t.repo,t.number).catch(()=>{})}}}if(t.reconcileAwait)if(o-(t.reconcileAwait.since||0)>_m)await cc(t.repo,t.number).catch(()=>{});else{let i=await r.detail(t.repo,t.number).catch(()=>null);if(i){if(i.mergeable==="CONFLICTING")await cc(t.repo,t.number).catch(()=>{});else if(i.mergeable==="MERGEABLE"){qa(r,t,"reconciled",null);let c=t.reconcileAwait.since||0;a&&!await Ha(a,"reconciled",t.number,l=>(l.payload?.ts||0)>=c)&&await Ua(a,"reconciled",{...Wa(t,e),base:i.baseRefName||null}).catch(()=>{}),await cc(t.repo,t.number).catch(()=>{})}}}}async function w1(t,e,n,r){let o=qa(r,t,"closed",Date.parse(e?.closedAt||"")||null),s=n.get(t.trackId);s&&!await Ha(s,"closed",t.number)&&await Ua(s,"closed",{...Wa(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 g1(t,e,n){qa(n,t,"lost",null);let r=e.get(t.trackId);r&&!await Ha(r,"lost",t.number)&&await Ua(r,"lost",Wa(t,null)).catch(()=>{}),await n.notifyIfResolved(t.repo,t.number,"lost").catch(()=>{}),await n.mark(t.repo,t.number,"lost").catch(()=>{})}async function bv(t,e,n,r,o={}){let s=qa(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 y1(t={}){let{now:e=Date.now(),auth:n=kf,view:r=o1,list:o=s1,links:s=Rb,trackMap:a=a1,emitMerged:i=i1,mark:c=Ln,archiveIfArmed:l=Xe,notifyIfArmed:u=Ze,notifyIfResolved:d=Uc,batchThreshold:f=ZD,detail:h=c1,merge:p=l1,updateBranch:w=u1,lookup:y=Gt,disarm:k=Gs,emitDisarmed:x=d1,localHasCommit:E=m1}=t;if(!(await n().catch(()=>null))?.authenticated||rc()>0)return 0;let C=(await s().catch(()=>[])).filter(A=>e-(kl.get(z(A.repo,A.number))||0)>=r1(A,e));if(!C.length)return 0;let N=Date.now(),T=new Map,B=new Map;for(let A of C){let D=yv(A,e);T.set(z(A.repo,A.number),{lane:D,intervalMs:gv[D]}),kl.set(z(A.repo,A.number),e),B.has(A.repo)||B.set(A.repo,[]),B.get(A.repo).push(A)}let j=await a().catch(()=>new Map),at={now:e,lanes:T,emitMerged:i,mark:c,archiveIfArmed:l,notifyIfArmed:u,notifyIfResolved:d,detail:h,merge:p,updateBranch:w,lookup:y,disarm:k,emitDisarmed:x,localHasCommit:E};for(let[A,D]of B){let X,bt=new Set;if(D.length>f)X=await o(A).catch(()=>null);else{X=new Map;for(let dt of D)try{let kt=await r(A,dt.number);kt?.number!=null&&X.set(Number(kt.number),kt)}catch(kt){e1(kt)&&bt.add(z(dt.repo,dt.number))}}if(X)for(let dt of D){let kt=z(dt.repo,dt.number),xt=X.get(Number(dt.number));if(!xt){if(bt.has(kt)){let g=(xl.get(kt)||0)+1;xl.set(kt,g),g>=YD&&(await g1(dt,j,at),xl.delete(kt),kl.delete(kt))}continue}xl.delete(kt),xt.state==="MERGED"||xt.state==="CLOSED"?(xt.state==="MERGED"?await bv(dt,xt,j,at):await w1(dt,xt,j,at),kl.delete(kt)):(await h1(dt,xt,j,at).catch(()=>{}),dt.autoMerge&&await p1(dt,j,at).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,D])=>`${A} ${D}`).join(", ")}) in ${Date.now()-N}ms`),C.length}function kv(){let t=!1;setInterval(async()=>{if(!t){t=!0;try{await y1()}catch{}finally{t=!1}}},hv)}Kt();ot();Rr();import{randomUUID as b1}from"node:crypto";var k1=2e4,xv=3,os=new Map,Rm=new Set;async function Sv(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 x1(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 d=(u.boxes||[]).find(h=>h.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 h=(os.get(d.name)||0)+1;os.set(d.name,h),h===xv&&(Rm.add(d.name),await Sv(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:b1(),box:d.name,agent:d.agent}}).catch(()=>{}))}else{let h=(os.get(d.name)||0)>=xv;if(os.delete(d.name),h||!Rm.has(d.name)){Rm.add(d.name);let p=await Sv(u,d.name,o);p&&await r(u,{type:"box.fullscreen.answered",actor:"system",source:"orchestrator",boxId:d.name,provider:d.agent,payload:{ts:s,offerId:p,action:"cleared"}}).catch(()=>{})}}}for(let u of[...os.keys()])l.has(u)||os.delete(u)}var Ka=null,$m=!1;function vv(){return Ka?()=>{}:(Ka=setInterval(()=>{$m||($m=!0,x1().catch(()=>{}).finally(()=>{$m=!1}))},k1),Ka.unref?.(),()=>{clearInterval(Ka),Ka=null})}Eo();_f();ot();oa();Eo();import{randomUUID as S1}from"node:crypto";async function v1(){let t=await Promise.resolve().then(()=>(Rr(),vx));return{sayToLead:t.sayToLead,queueShipCompleteNotify:t.queueShipCompleteNotify}}var Om={listRepoPrs:$r,readEvents:F,appendEvent:I,sayDeps:v1};async function T1(t,e=Om){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 Cm(t,e,{actions:n,notify:r=!1}={},o=Om){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 T1(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=S1();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 Mm(t,{offerId:e,choice:n}={},r=Om){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=tc.filter(d=>d!=="pr"&&(i.includes(d)||d==="push")),c=await u(t.id,Ao(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,ib(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 ss from"node:path";import $v from"node:os";import Tv from"node:fs/promises";import Sl from"node:path";import{execFile as A1}from"node:child_process";import{promisify as E1}from"node:util";import{fileURLToPath as _1}from"node:url";var I1=E1(A1),Ev=Sl.dirname(_1(import.meta.url)),R1=Sl.resolve(Ev,"..","..","client","dist"),$1="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",O1=new Map([...$1].map((t,e)=>[t,e]));function C1(t){let e=[],n=0,r=0;for(let o of t){let s=O1.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 M1(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=C1(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 N1(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 Av=new Map;async function P1(t){let e;try{e=await Tv.stat(t)}catch{return null}let n=Av.get(t);if(n&&n.mtimeMs===e.mtimeMs)return n;try{let r=JSON.parse(await Tv.readFile(t,"utf8")),o={mtimeMs:e.mtimeMs,sources:r.sources||[],lines:M1(r.mappings||"")};return Av.set(t,o),o}catch{return null}}var Nm=null;function B1(){return Nm||(Nm=process.env.BOSTRAT_RELEASE?Promise.resolve(process.env.BOSTRAT_RELEASE):I1("git",["rev-parse","--short","HEAD"],{cwd:Sl.resolve(Ev,"..","..")}).then(t=>t.stdout.trim()).catch(()=>null)),Nm}var D1=/(?:https?:\/\/[^\s()]*)?\/assets\/([^\s()/]+\.js):(\d+):(\d+)/g;async function j1(t,{distDir:e=R1}={}){let n=[],r=0,o=!1;for(let s of t.matchAll(D1)){let[a,i,c,l]=s,u=await P1(Sl.join(e,"assets",`${i}.map`)),d=u?N1(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 _v(t,e={}){try{if(!t?.error?.stack||!t.release||t.release==="unknown")return t;let n=e.release??await B1();if(!n||t.release!==n)return t;let{stack:r,symbolicated:o}=await j1(t.error.stack,e);o&&(t.error.stack=r,t.error.symbolicated=!0)}catch{}return t}var L1=()=>process.env.BOSTRAT_STATE_DIR||ss.join(process.env.HOME||$v.tmpdir(),".bostrat"),or=()=>ss.join(L1(),"telemetry"),Ov=()=>ss.join(or(),".relay-offsets.json"),F1=50,U1=14,H1=3e4,Iv=500,ie=(t,e)=>typeof t=="string"?t.slice(0,e):"";function W1(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 Cv=t=>new Date(t).toISOString().slice(0,10),Rv=0;async function Mv(t,e=Date.now()){let r=(Array.isArray(t?.events)?t.events.slice(0,F1):[]).map(s=>W1(s,e)).filter(Boolean);if(!r.length)return 0;for(let s of r)s.error?.stack&&await _v(s);await hn.mkdir(or(),{recursive:!0});let o=ss.join(or(),`${Cv(e)}.ndjson`);return await hn.appendFile(o,r.map(s=>JSON.stringify(s)+`
522
- `).join(""),"utf8"),e-Rv>6*3600*1e3&&(Rv=e,q1(e).catch(()=>{})),r.length}async function q1(t=Date.now()){let e=Cv(t-U1*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(ss.join(or(),s),{force:!0});let o=await Pv();for(let s of r)delete o[s];await Bv(o)}var vl=new Map;function Nv(t,e=Date.now()){let n=t||"unknown",r=vl.get(n);return r||(vl.size>512&&vl.clear(),r={tokens:40,at:e},vl.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 Pv(){try{return JSON.parse(await hn.readFile(Ov(),"utf8"))||{}}catch{return{}}}async function Bv(t){await hn.mkdir(or(),{recursive:!0}),await hn.writeFile(Ov(),JSON.stringify(t),"utf8")}function K1(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 G1({fetchImpl:t=fetch}={}){let e=await Mx();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 Pv(),o=0;for(let s of n){let a=ss.join(or(),s),i=r[s]||0,c;try{let f=await hn.open(a,"r");try{let h=(await f.stat()).size;if(h<=i)continue;c=Buffer.alloc(h-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(`
523
- `).filter(Boolean),d=[];for(let f of u)try{d.push(JSON.parse(f))}catch{}for(let f=0;f<d.length;f+=Iv){let h=d.slice(f,f+Iv).map(w=>K1(w)),p=await t(`${e.url.replace(/\/$/,"")}/v1/logs`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${e.ingestKey}`},body:JSON.stringify({events:h})}).catch(()=>null);if(!p||!p.ok)return{sent:o,disabled:!1};o+=h.length}r[s]=i+l+1,await Bv(r)}return{sent:o,disabled:!1}}var Pm=null,Bm=!1;function Dv(){Pm||(Pm=setInterval(async()=>{if(!Bm){Bm=!0;try{await G1()}catch(t){console.error("[telemetry] relay failed:",t?.message||t)}finally{Bm=!1}}},H1),Pm.unref?.())}import Al from"node:fs/promises";import Hv from"node:path";import V1 from"node:os";var Wv=()=>process.env.BOSTRAT_STATE_DIR||Hv.join(process.env.HOME||V1.tmpdir(),".bostrat"),qv=()=>Hv.join(Wv(),"dictation-glossary.json"),z1=100,J1=500,Y1=["bostrat","globopi","codex","tmux","worktree","Deepgram","Linear","Firecracker","Tigris","WireGuard","misous","postyx","cedar","gerbil","Anthropic","Opus","Haiku","Sonnet","keyterm","monorepo","dogfood"],El=null,Dm=null,jm=Promise.resolve();function jv(){let t={},e=Date.now();for(let n of Y1)t[n.toLowerCase()]={term:n,count:1,lastUsed:e,source:"seed"};return t}async function Kv(){return El||(Dm??=Al.readFile(qv(),"utf8").then(t=>JSON.parse(t)?.terms??jv()).catch(()=>jv()).then(t=>El=t).finally(()=>Dm=null),Dm)}async function Lv(){let t=JSON.stringify({terms:El},null,2),e=qv(),n=`${e}.${process.pid}.tmp`;await Al.mkdir(Wv(),{recursive:!0}),await Al.writeFile(n,t),await Al.rename(n,e)}function X1(){return jm=jm.then(Lv,Lv),jm.catch(()=>{})}async function Lm(){return Object.values(await Kv()).sort((e,n)=>n.count-e.count||n.lastUsed-e.lastUsed)}var Z1=t=>Math.max(1,Math.ceil(t.length/4));async function Q1(){let t=[],e=0;for(let{term:n}of await Lm()){let r=Z1(n);if(!(e+r>J1)&&(t.push(n),e+=r,t.length>=z1))break}return t}async function tj(t,e){let n=await Kv(),r=t.toLowerCase(),o=n[r];n[r]={term:t,count:(o?.count??0)+1,lastUsed:Date.now(),source:o?.source??e}}var Fv=t=>(t||"").split(/\s+/).map(e=>e.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"")).filter(Boolean),Tl=t=>t.toLowerCase();function Uv(t){return!new RegExp("\\p{L}","u").test(t)||t.length<3?!1:/^[a-z]+$/.test(t)?t.length>=4:!0}async function Gv(t,e){let n=Fv(t),r=Fv(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]=Tl(n[u])===Tl(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;)Tl(n[c])===Tl(r[l])?(c++,l++):a[c+1][l]>=a[c][l+1]?c++:(Uv(r[l])&&i.add(r[l]),l++);for(;l<s;l++)Uv(r[l])&&i.add(r[l]);if(!i.size)return[];for(let u of i)await tj(u,"learned");return await X1(),[...i]}var Ga=null;function ej(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 Vv(){if(!Ga)return null;let t=await Ia();if(!t||t.apiKey.slice(-6)!==Ga.keyTail)return null;let{keyTail:e,...n}=Ga;return n}async function zv(t,e){let n=await Ia();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 Q1())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=ej(o.status,i);c.persistent&&(Ga={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 Ga=null,{transcript:(await o.json())?.results?.channels?.[0]?.alternatives?.[0]?.transcript??""}}ot();var Fm={"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 nj(t){if(!t)return null;let e=String(t).trim();if(Fm[e])return e;let n=null;for(let r of Object.keys(Fm))e.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function rj(t,e={}){let n=Fm[nj(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 oj(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 Va=null;async function sj(){if(!Va)return null;let t=await tl();if(!t||t.apiKey.slice(-6)!==Va.keyTail)return null;let{keyTail:e,...n}=Va;return n}async function aj(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=oj(e.status,o);s.persistent&&(Va={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}Va=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 ij={openai:aj};async function Jv(){let t=await tl();return t?{configured:!0,provider:t.provider,model:t.model,voice:t.voice,problem:await sj()}:{configured:!1}}async function Yv(){let t=await tl();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 ij[t.provider](t);return{provider:t.provider,model:t.model,voice:t.voice,...e}}async function Xv(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=rj(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 rT=ut.dirname(lj(import.meta.url)),Zv=Number(process.env.PORT)||3362,_l=hm(process.env),oT=Number(process.env.BOSTRAT_AUTO_TRIGGER_PCT)||80,as=WS(process.env.BOSTRAT_ALLOW_IPS),Km=qS(process.env.BOSTRAT_VIEW_FRONT_CIDRS,bl),sT=GS(),aT=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"),yl(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(Fa(t)||as.allowed(as.clientIp(t))||Km.allows(t))return n();e.status(403).type("text/plain").send("bostrat: access restricted to the allowlist")});S.use(XS);S.use(JS({token:sT,enforce:aT}));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:oT})});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 vs(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 _g(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=Li(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 Qv=10;S.get("/api/idle-guard",async(t,e)=>{try{e.json(Tx({tracks:await nt(),views:await mf(),queuedOf:n=>Wo(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>Qv){let s=new Set([...r].sort((a,i)=>(i.archivedAt||0)-(a.archivedAt||0)).slice(0,Qv).map(a=>a.id));o=n.filter(a=>!a.archivedAt||a.archiving||s.has(a.id))}e.json({tracks:o,archivedTotal:r.length,agents:xa,agentAvailability:await Bc(),tickets:await Vx()})});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 TS(n);if(r.cursorUsage=tf(),t.query.format==="text")return e.type("text/plain").send(AS(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 IS(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 MS(await nt(),{window:t.query.window,from:t.query.from,to:t.query.to});n.cursorUsage=tf(),n.subscriptionMonthlyUsd=Number(process.env.BOSTRAT_SUBSCRIPTION_MONTHLY_USD)||null,n.caps=Fs(),e.json(n)}catch(n){e.status(500).json({error:n?.message||String(n)})}});S.get("/api/usage/caps",(t,e)=>{e.json(Fs())});S.post("/api/usage/caps",async(t,e)=>{try{e.json(await Ji(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 jS(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 Jm(t.get(Za),{byToken:lp,legacy:()=>Js(t.body?.session_id,t.body?.cwd)});if(n==="refused")return cs("refused",{reason:"unknown-token",hook:t.body?.hook_event_name}),e.json({ok:!1,error:"unknown hook token"});if(n==="legacy-denied")return cs("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&&cs("mismatch",{track:r.track.id,box:r.box.name}),cs(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 hS(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(!Nv(as.clientIp(t)))return e.json({ok:!0,dropped:!0});let n=await Mv(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 ps()).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 oi(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:ri(),calls:bb(),latency:Sk()})});S.post("/api/github/refresh",(t,e)=>{sh(),e.json({ok:!0})});S.get("/api/gmail/search",async(t,e)=>{try{let n=await FS(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 US(String(t.params.id))})}catch(n){e.status(n?.status||502).json({error:n?.message||String(n)})}});function Gm(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 Il({repo:t=null,number:e=null,branch:n=null}){let r=t?await lt(t):null;if(r&&e!=null){let s=await Gt(r,e),a=s&&await Y(s.trackId);if(a)return a}return n?(await nt()).find(s=>s.workspace?.branch===n&&Gm(s,t,r))??null:null}async function iT({repo:t=null,number:e=null,branch:n=null}){let r=await Il({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&&Gm(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 Il({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 pj(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 Gt(r,o.number))continue;let s=e.find(a=>a.workspace?.branch===o.headRefName&&Gm(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 Rk();await pj(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:d}=t.body||{};try{if(s){let w=o||"merge";if(!na.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 Il({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 ra(n,y),await oe({repo:k,number:y,trackId:x.id,url:d,headRef:l,title:u,source:"matched"}).catch(()=>{}),!await qs(k,y,{merge:{method:w}}))throw new Error("couldn't record the auto-merge arm");return await _r(k,y,i===!0),await Ks(k,y,c===!0&&i!==!0),Pe(),await Ae("auto-armed",{number:y,url:d,title:u,branch:l,repo:n,track:x,...a?{extra:{updated:!0}}:{}}),e.json({ok:!0,number:y,auto:!0})}let f=await Mo(n,r,{method:o||"squash"});await Ae("merged",{number:f.number,url:d,title:u,branch:l,repo:n});let h=await lt(n).catch(()=>null),p=!1;if(h&&(i===!0&&await _r(h,f.number,!0).catch(()=>{}),c===!0&&i!==!0&&await Ks(h,f.number,!0).catch(()=>{}),await Ze(h,f.number).catch(()=>{}),p=await Xe(h,f.number).catch(()=>!1),await Ln(h,f.number,"merged").catch(()=>{})),i===!0&&!p){let w=await Il({repo:n,number:f.number,branch:l}).catch(()=>null);w&&!w.archivedAt&&await Dr(w.id).catch(()=>{})}e.json(f)}catch(f){let h=f?.message||String(f),p=/invalid|unknown repo|required|needs a Track|no GitHub remote/i.test(h)?400:502;e.status(p).json({error:h})}});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 Gs(c,i).catch(()=>null):null;try{await vf(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 Mk(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:Ck()})});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(!na.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(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 _r(f.repo,f.number,o===!0).catch(()=>{}),await Ks(f.repo,f.number,s===!0&&o!==!0).catch(()=>{});let u=[],d=[];for(let f of l){let h={repo:f.repo,number:f.number,ok:!0,action:"armed"};u.push(h);try{let p=await Or(f.repo);if(!p)throw new Error(`no local checkout for ${f.repo}`);let w=await Co(p,f.number);d.push({r:h,l:f,repoPath:p,pr:w,plan:$k(w,{update:r!==!1})})}catch(p){h.ok=!1,h.action="failed",h.reason=p?.message||String(p)}}for(let{r:f,l:h,repoPath:p,pr:w,plan:y}of Ok(d))try{if(y.action==="skip")f.action="skipped",f.reason=y.reason;else if(y.action==="merge")await Mo(p,h.number,{method:i}),await Ae("merged",{number:h.number,url:w.url,title:w.title,branch:w.headRefName,repo:p,track:c}),await Ze(h.repo,h.number).catch(()=>{}),await Xe(h.repo,h.number).catch(()=>{}),await Ln(h.repo,h.number,"merged").catch(()=>{}),f.action="merged";else{if(y.action==="update-arm"&&(await ra(p,h.number).catch(()=>{}),f.action="updated-armed"),!await qs(h.repo,h.number,{merge:{method:i}}))throw new Error("couldn't record the auto-merge arm");await Ae("auto-armed",{number:h.number,url:w.url,title:w.title,branch:w.headRefName,repo:p,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 _r(f.repo,f.number,!1).catch(()=>{});if(s===!0&&o!==!0)for(let f of l)await Ks(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})}});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 Gs(a.repo,a.number).catch(()=>null),c=await Or(a.repo).catch(()=>null);c&&await vf(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),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 Io(i),!d.length)return e.status(409).json({error:"no tagged repo has work to ship"});let h=[];for(let w of d)try{let y=await Af(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}}),h.push({repo:w.name,slug:k??null,ok:!0,url:y.url,number:y.number})}catch(y){h.push({repo:w.name,slug:w.repo??null,ok:!1,error:y?.message||String(y)})}let p=h.filter(w=>w.ok);return p.length?e.json({ok:!0,multi:!0,results:h,url:p[0].url,number:p[0].number}):e.status(502).json({error:h.map(w=>`${w.repo}: ${w.error}`).join("; "),results:h})}let c=await Af(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 Io(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 bp(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 kp(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 Co(n,r),s=await lt(n).catch(()=>null),a=await iT({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 Nk(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 Ut.promises.mkdir(d,{recursive:!0}),await Ut.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
521
+ `),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 SS(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}.${u1(n.host)}/`}function u1(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 Il(e)&&_f(n[0])?n.slice(1).join("."):e}Ho();Jf();Fc();af();st();import{randomUUID as d1}from"node:crypto";var TS=32768,AS=120,ES=1e3,_S=new Set(["claude","codex","cursor"]),f1=new Set(["off","transition","nag"]),p1=[[0,59],[0,23],[1,31],[1,12],[0,6]];function m1(t){let e=String(t??"").trim().split(/\s+/);return e.length!==5?!1:e.every((n,r)=>{let[o,s]=p1[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 gn=t=>String(t??"").trim();function h1(t,e){let n=t&&typeof t=="object"?t:{},r=gn(n.name);if(!r)throw new Error("a loop plan needs a name");if(r.length>AS)throw new Error(`name is too long (${r.length}); cap is ${AS}`);let o=gn(n.schedule);if(!o)throw new Error('a loop plan needs a schedule (5-field UTC crontab, e.g. "0 7 * * *")');if(!m1(o))throw new Error(`invalid cron schedule: "${o}" \u2014 5 UTC fields, e.g. "0 7 * * *"`);let s=gn(n.prompt);if(!s)throw new Error("a loop plan needs a prompt \u2014 it is what the run does");if(s.length>TS)throw new Error(`prompt is too long (${s.length} chars); cap is ${TS}`);let a=gn(n.expectation)||null;if(a&&a.length>ES)throw new Error(`expectation is too long (${a.length}); cap is ${ES}`);let i=gn(n.notify)||"off";if(!f1.has(i))throw new Error(`notify must be one of off | transition | nag, got "${n.notify}"`);let c=n.assignment??null,l=gn(typeof c=="string"?c:c?.provider)||"claude";if(!_S.has(l))throw new Error(`unknown provider "${l}" \u2014 one of ${[..._S].join(", ")}`);let u=typeof c=="object"&&c&&gn(c.model)||null,d=gn(e?.workspace?.repo)||gn(e?.workspace?.base)||null;if(!d)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:d}}async function IS(t,e){let n=h1(e,t),r=d1();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 RS(t,e,n,{loopId:r=null,nextFireAt:o=null}={}){if(!e)throw new Error("proposalId required");let s=await B({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)}}An();st();Wn();Fc();var $S=10,OS=200,w1=120,g1=24,y1=/^\d{4}-\d{2}-\d{2}$/;function jm(t=process.env){return(t.CHANGELOG_REPOS||"globocodes/bostrat").split(",").map(e=>e.trim()).filter(Boolean)}var b1=(t=Date.now())=>new Date(t).toISOString().slice(0,10);function CS(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 k1=/^\*\*([^*]+?)\*\*\s*[:.]?\s*[—–-]?\s*(.*)$/;function x1(t){if(typeof t!="string"||!t.trim())throw new Error("md (markdown string) required");let e=ya(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(`
522
+ `)){let s=o.trim();if(!s)continue;if(s.startsWith("#")){n==null&&(n=s.replace(/^#+\s*/,"").trim().slice(0,w1)||null);continue}let a=/^[-*]\s+(.*)$/.exec(s);if(!a)continue;let i=a[1].trim(),c=null,l=new RegExp(`^\\[([^\\]]{1,${g1}})\\]\\s+(.*)$`).exec(i);if(l&&(c=l[1].trim(),i=l[2].trim()),!i)continue;let u=k1.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>OS)throw new Error(`bullet ${r.length+1} is ${i.length} chars \u2014 over the ${OS}-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>$S)throw new Error(`${r.length} bullets \u2014 over the ${$S}-bullet cap; group related changes into one line`);return{title:n||null,bullets:r}}async function MS(t,{repos:e=jm()}={}){let n=new Set(e);return(await Cr()).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 NS(t,{md:e,day:n=null}){let r=x1(e),o=n==null||n===""?b1():String(n);if(!y1.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}}ma();Wn();Mo();st();ma();qt();Nr();Wn();Zs();Oc();ra();import{execFile as v1}from"node:child_process";import{promisify as S1}from"node:util";var Fm=S1(v1),PS=3e4,T1=30*6e4,A1=PS,E1=10*6e4,_1=10080*6e4,I1=60*6e4,R1=8,$1=1440*6e4,O1=3,BS="number,url,title,headRefName,headRefOid,state,mergedAt,closedAt",Lm=60*6e4,C1=15*6e4,M1=9e4,N1=1440*6e4,$l=new Map,Ol=new Map,P1=/could not resolve|not found|no pull requests?/i,B1=t=>P1.test(String(t?.message||t||""));function D1(t,e){return[t.ciFix?.delegatedAt,t.reconcile?.delegatedAt,t.ciFixAwait?.since,t.reconcileAwait?.since].some(n=>n&&e-n<Lm)}var DS={fast:A1,slow:E1,decay:I1};function jS(t,e){return t.armedAt&&e-t.armedAt<T1||D1(t,e)||LS(t,e,{grace:0})?"fast":e-(t.firstSeen||0)>_1?"decay":"slow"}function j1(t,e){return DS[jS(t,e)]}function Xa(t,e,n,r){let o=t.lanes?.get(J(e.repo,e.number))||{};return $c({change:n,repo:e.repo,number:Number(e.number),githubAt:r||null,lane:o.lane||null,intervalMs:o.intervalMs||null,source:"watch"})}async function L1(t,e){Ze("watch");try{let{stdout:n}=await Fm("gh",["pr","view",String(e),"--repo",t,"--json",BS],{timeout:3e4,maxBuffer:4194304,env:{...process.env,...await Ie({slug:t})}});return JSON.parse(n||"null")}catch(n){throw Ln(n)&&Fn(n),n}}async function F1(t){Ze("watch");try{let{stdout:e}=await Fm("gh",["pr","list","--repo",t,"--state","all","--limit","100","--json",BS],{timeout:3e4,maxBuffer:8388608,env:{...process.env,...await Ie({slug:t})}}),n=new Map;for(let r of JSON.parse(e||"[]"))n.set(Number(r.number),r);return n}catch(e){throw Ln(e)&&Fn(e),e}}async function U1(){let t=new Map;for(let e of await ot().catch(()=>[]))t.set(e.id,e);return t}async function H1(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 W1(t,e){let n=await Br(t);return n?jo(n,e):null}async function q1(t,e,n){let r=await Br(t);if(!r)throw new Error(`no local checkout for ${t}`);return Lo(r,e,{method:n})}async function K1(t,e){let n=await Br(t);if(!n)throw new Error(`no local checkout for ${t}`);return pa(n,e)}async function G1(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 us(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 V1=10*6e4;async function z1(t,e,n){let r=t.autoMerge?.armedAt||0;if(r&&(n.now??Date.now())-r>$1){await us(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 us(t,o,e,n,`check${o.checks.failed===1?"":"s"} failed: ${a}`);return}if(o.mergeable==="CONFLICTING"){await us(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<V1)return;await us(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 us(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 us(t,o,e,n,String(a?.message||a).trim()||"merge failed");return}await FS(t,{...o,state:"MERGED"},e,n,{change:"auto-merged",githubAt:o.checks.settledAt||null})}}async function ds(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 J1(t,e){try{return await Fm("git",["-C",t.cwd,"cat-file","-e",`${e}^{commit}`],{timeout:1e4}),!0}catch{return!1}}async function Ya(t,e,n,r=()=>!0){return(await B(t).catch(()=>[])).some(s=>s.type==="pr.state.changed"&&s.payload?.change===e&&s.payload?.number===Number(n)&&r(s))}var fs=(t,e)=>({number:Number(t.number),url:e?.url||t.url,title:e?.title||t.title,branch:e?.headRefName||t.headRef,repo:t.repo});function LS(t,e,{grace:n=M1}={}){if(t.announced!==!1)return!1;let r=e-(t.firstSeen||0);return r>=n&&r<=N1}async function Y1(t,e,n,r){let o=r.now??Date.now();if(!LS(t,o))return!1;let s=n.get(t.trackId)||null;if(!s||s.archivedAt||s.transferredTo)return!1;let a=(s.boxes||[]).find(d=>d.name===s.leadBox);return await(r.midTurn??Mr)(s.leadBox,a?.agent).catch(()=>!1)?!1:(await B(s).catch(()=>[])).some(d=>d.type==="pr.state.changed"&&d.payload?.number===Number(t.number))?(await(r.claim??Qe)(t.repo,t.number).catch(()=>null),!1):await(r.claim??Qe)(t.repo,t.number).catch(()=>null)?(await ds(s,"opened",{...fs(t,e),announcedBy:"watch"}).catch(()=>{}),console.log(`[pr-watch] announced passive link ${t.repo}#${t.number} \u2192 track ${s.id} (no active door claimed it)`),!0):!1}async function X1(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 pc(t.repo,t.number,{headSha:s}).catch(()=>{}),t.reconcile?.headSha&&s!==t.reconcile.headSha&&await hc(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<C1;await Hb(t.repo,t.number,s).catch(()=>{}),t.baseFoldAt&&await Ub(t.repo,t.number).catch(()=>{}),!i&&!c&&!l&&a&&!await r.localHasCommit(a,s).catch(()=>!1)&&!await Ya(a,"pushed",t.number,d=>d.payload?.sha===s)&&await ds(a,"pushed",{...fs(t,e),sha:s}).catch(()=>{})}if(t.ciFixAwait)if(o-(t.ciFixAwait.since||0)>Lm)await mc(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 mc(t.repo,t.number).catch(()=>{});else if(i.checks.total>0&&i.checks.pending===0){let c=Xa(r,t,"ci-fixed",i.checks.settledAt||null),l=t.ciFixAwait.since||0;a&&!await Ya(a,"ci-fixed",t.number,u=>(u.payload?.ts||0)>=l)&&await ds(a,"ci-fixed",{...fs(t,e),passed:i.checks.passed,githubAt:c.githubAt,latencyMs:c.latencyMs,lane:c.lane}).catch(()=>{}),await mc(t.repo,t.number).catch(()=>{})}}}if(t.reconcileAwait)if(o-(t.reconcileAwait.since||0)>Lm)await wc(t.repo,t.number).catch(()=>{});else{let i=await r.detail(t.repo,t.number).catch(()=>null);if(i){if(i.mergeable==="CONFLICTING")await wc(t.repo,t.number).catch(()=>{});else if(i.mergeable==="MERGEABLE"){Xa(r,t,"reconciled",null);let c=t.reconcileAwait.since||0;a&&!await Ya(a,"reconciled",t.number,l=>(l.payload?.ts||0)>=c)&&await ds(a,"reconciled",{...fs(t,e),base:i.baseRefName||null}).catch(()=>{}),await wc(t.repo,t.number).catch(()=>{})}}}}async function Z1(t,e,n,r){let o=Xa(r,t,"closed",Date.parse(e?.closedAt||"")||null),s=n.get(t.trackId);s&&!await Ya(s,"closed",t.number)&&await ds(s,"closed",{...fs(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 Q1(t,e,n){Xa(n,t,"lost",null);let r=e.get(t.trackId);r&&!await Ya(r,"lost",t.number)&&await ds(r,"lost",fs(t,null)).catch(()=>{}),await n.notifyIfResolved(t.repo,t.number,"lost").catch(()=>{}),await n.mark(t.repo,t.number,"lost").catch(()=>{})}async function FS(t,e,n,r,o={}){let s=Xa(r,t,o.change||"merged",o.githubAt??(Date.parse(e.mergedAt||"")||null)),a=n.get(t.trackId);a&&((await B(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 tj(t={}){let{now:e=Date.now(),auth:n=Cf,view:r=L1,list:o=F1,links:s=qb,trackMap:a=U1,emitMerged:i=H1,mark:c=Hn,archiveIfArmed:l=tn,notifyIfArmed:u=en,notifyIfResolved:d=Xc,batchThreshold:f=O1,detail:p=W1,merge:h=q1,updateBranch:w=K1,lookup:y=Vt,disarm:k=ea,emitDisarmed:x=G1,localHasCommit:A=J1,claim:R=Qe,midTurn:V=Mr}=t;if(!(await n().catch(()=>null))?.authenticated||dc()>0)return 0;let T=(await s().catch(()=>[])).filter(j=>e-($l.get(J(j.repo,j.number))||0)>=j1(j,e));if(!T.length)return 0;let D=Date.now(),F=new Map,ct=new Map;for(let j of T){let at=jS(j,e);F.set(J(j.repo,j.number),{lane:at,intervalMs:DS[at]}),$l.set(J(j.repo,j.number),e),ct.has(j.repo)||ct.set(j.repo,[]),ct.get(j.repo).push(j)}let Q=await a().catch(()=>new Map),_={now:e,lanes:F,emitMerged:i,mark:c,archiveIfArmed:l,notifyIfArmed:u,notifyIfResolved:d,detail:p,merge:h,updateBranch:w,lookup:y,disarm:k,emitDisarmed:x,localHasCommit:A,claim:R,midTurn:V};for(let[j,at]of ct){let Et,Lt=new Set;if(at.length>f)Et=await o(j).catch(()=>null);else{Et=new Map;for(let it of at)try{let g=await r(j,it.number);g?.number!=null&&Et.set(Number(g.number),g)}catch(g){B1(g)&&Lt.add(J(it.repo,it.number))}}if(Et)for(let it of at){let g=J(it.repo,it.number),m=Et.get(Number(it.number));if(!m){if(Lt.has(g)){let S=(Ol.get(g)||0)+1;Ol.set(g,S),S>=R1&&(await Q1(it,Q,_),Ol.delete(g),$l.delete(g))}continue}Ol.delete(g),m.state==="MERGED"||m.state==="CLOSED"?(m.state==="MERGED"?await FS(it,m,Q,_):await Z1(it,m,Q,_),$l.delete(g)):(await Y1(it,m,Q,_).catch(()=>{}),await X1(it,m,Q,_).catch(()=>{}),it.autoMerge&&await z1(it,Q,_).catch(()=>{}))}}let U={};for(let{lane:j}of F.values())U[j]=(U[j]||0)+1;return console.log(`[pr-watch] probed ${T.length} link(s) (${Object.entries(U).map(([j,at])=>`${j} ${at}`).join(", ")}) in ${Date.now()-D}ms`),T.length}function US(){let t=!1;setInterval(async()=>{if(!t){t=!0;try{await tj()}catch{}finally{t=!1}}},PS)}Gt();st();Nr();import{randomUUID as ej}from"node:crypto";var nj=2e4,HS=3,ps=new Map,Um=new Set;async function WS(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 rj(t={}){let{sessions:e=null,tracks:n=null,append:r=I,read:o=B,now:s=Date.now()}=t;if(process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1")return;let a,i;try{a=e??await be(),i=n??await ot()}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 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=(ps.get(d.name)||0)+1;ps.set(d.name,p),p===HS&&(Um.add(d.name),await WS(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:ej(),box:d.name,agent:d.agent}}).catch(()=>{}))}else{let p=(ps.get(d.name)||0)>=HS;if(ps.delete(d.name),p||!Um.has(d.name)){Um.add(d.name);let h=await WS(u,d.name,o);h&&await r(u,{type:"box.fullscreen.answered",actor:"system",source:"orchestrator",boxId:d.name,provider:d.agent,payload:{ts:s,offerId:h,action:"cleared"}}).catch(()=>{})}}}for(let u of[...ps.keys()])l.has(u)||ps.delete(u)}var Za=null,Hm=!1;function qS(){return Za?()=>{}:(Za=setInterval(()=>{Hm||(Hm=!0,rj().catch(()=>{}).finally(()=>{Hm=!1}))},nj),Za.unref?.(),()=>{clearInterval(Za),Za=null})}Ro();Lf();st();ma();Mo();Ro();import{randomUUID as oj}from"node:crypto";async function sj(){let t=await Promise.resolve().then(()=>(Nr(),V0));return{sayToLead:t.sayToLead,queueShipCompleteNotify:t.queueShipCompleteNotify}}var Wm={listRepoPrs:Pr,readEvents:B,appendEvent:I,sayDeps:sj,currentBranch:Oo};async function aj(t,e=Wm,{branch:n=null}={}){if(!t?.cwd)return null;let r=n||await(e.currentBranch??Oo)(t.workspace?.kind==="multi"?null:t.cwd).catch(()=>null)||t?.workspace?.branch;if(!r)return null;let o;try{o=await e.listRepoPrs(t.cwd,{caller:"pr-exists"})}catch{return null}let s=(o||[]).find(a=>a.headRefName===r);return s?{number:s.number,url:s.url??null,title:s.title??null}:null}async function qm(t,e,{actions:n,notify:r=!1}={},o=Wm){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 aj(t,o,{branch:s.branch});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=oj();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 Km(t,{offerId:e,choice:n}={},r=Wm){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=cc.filter(d=>d!=="pr"&&(i.includes(d)||d==="push")),c=await u(t.id,Io(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,vb(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 yn from"node:fs/promises";import ms from"node:path";import XS from"node:os";import KS from"node:fs/promises";import Cl from"node:path";import{execFile as ij}from"node:child_process";import{promisify as cj}from"node:util";import{fileURLToPath as lj}from"node:url";var uj=cj(ij),VS=Cl.dirname(lj(import.meta.url)),dj=Cl.resolve(VS,"..","..","client","dist"),fj="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",pj=new Map([...fj].map((t,e)=>[t,e]));function mj(t){let e=[],n=0,r=0;for(let o of t){let s=pj.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 hj(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=mj(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 wj(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 GS=new Map;async function gj(t){let e;try{e=await KS.stat(t)}catch{return null}let n=GS.get(t);if(n&&n.mtimeMs===e.mtimeMs)return n;try{let r=JSON.parse(await KS.readFile(t,"utf8")),o={mtimeMs:e.mtimeMs,sources:r.sources||[],lines:hj(r.mappings||"")};return GS.set(t,o),o}catch{return null}}var Gm=null;function yj(){return Gm||(Gm=process.env.BOSTRAT_RELEASE?Promise.resolve(process.env.BOSTRAT_RELEASE):uj("git",["rev-parse","--short","HEAD"],{cwd:Cl.resolve(VS,"..","..")}).then(t=>t.stdout.trim()).catch(()=>null)),Gm}var bj=/(?:https?:\/\/[^\s()]*)?\/assets\/([^\s()/]+\.js):(\d+):(\d+)/g;async function kj(t,{distDir:e=dj}={}){let n=[],r=0,o=!1;for(let s of t.matchAll(bj)){let[a,i,c,l]=s,u=await gj(Cl.join(e,"assets",`${i}.map`)),d=u?wj(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 zS(t,e={}){try{if(!t?.error?.stack||!t.release||t.release==="unknown")return t;let n=e.release??await yj();if(!n||t.release!==n)return t;let{stack:r,symbolicated:o}=await kj(t.error.stack,e);o&&(t.error.stack=r,t.error.symbolicated=!0)}catch{}return t}var xj=()=>process.env.BOSTRAT_STATE_DIR||ms.join(process.env.HOME||XS.tmpdir(),".bostrat"),ir=()=>ms.join(xj(),"telemetry"),ZS=()=>ms.join(ir(),".relay-offsets.json"),vj=50,Sj=14,Tj=3e4,JS=500,ce=(t,e)=>typeof t=="string"?t.slice(0,e):"";function Aj(t,e){if(!t||typeof t!="object")return null;let n=ce(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:ce(t.anonId,64),sessionId:ce(t.sessionId,64),userId:ce(t.userId,64),release:ce(t.release,64),appVersion:ce(t.appVersion,32),route:ce(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:ce(t.error.kind,256),message:ce(t.error.message,8192),stack:ce(t.error.stack,32768),fingerprint:ce(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:ce(s?.n,64),r:ce(s?.r,128)}))),o}var QS=t=>new Date(t).toISOString().slice(0,10),YS=0;async function tT(t,e=Date.now()){let r=(Array.isArray(t?.events)?t.events.slice(0,vj):[]).map(s=>Aj(s,e)).filter(Boolean);if(!r.length)return 0;for(let s of r)s.error?.stack&&await zS(s);await yn.mkdir(ir(),{recursive:!0});let o=ms.join(ir(),`${QS(e)}.ndjson`);return await yn.appendFile(o,r.map(s=>JSON.stringify(s)+`
523
+ `).join(""),"utf8"),e-YS>6*3600*1e3&&(YS=e,Ej(e).catch(()=>{})),r.length}async function Ej(t=Date.now()){let e=QS(t-Sj*24*3600*1e3),n=[];try{n=await yn.readdir(ir())}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 yn.rm(ms.join(ir(),s),{force:!0});let o=await nT();for(let s of r)delete o[s];await rT(o)}var Ml=new Map;function eT(t,e=Date.now()){let n=t||"unknown",r=Ml.get(n);return r||(Ml.size>512&&Ml.clear(),r={tokens:40,at:e},Ml.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 nT(){try{return JSON.parse(await yn.readFile(ZS(),"utf8"))||{}}catch{return{}}}async function rT(t){await yn.mkdir(ir(),{recursive:!0}),await yn.writeFile(ZS(),JSON.stringify(t),"utf8")}function _j(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||XS.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 Ij({fetchImpl:t=fetch}={}){let e=await rv();if(!e)return{sent:0,disabled:!0};let n;try{n=(await yn.readdir(ir())).filter(s=>s.endsWith(".ndjson")).sort()}catch{return{sent:0,disabled:!1}}let r=await nT(),o=0;for(let s of n){let a=ms.join(ir(),s),i=r[s]||0,c;try{let f=await yn.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(`
524
+ `).filter(Boolean),d=[];for(let f of u)try{d.push(JSON.parse(f))}catch{}for(let f=0;f<d.length;f+=JS){let p=d.slice(f,f+JS).map(w=>_j(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 rT(r)}return{sent:o,disabled:!1}}var Vm=null,zm=!1;function oT(){Vm||(Vm=setInterval(async()=>{if(!zm){zm=!0;try{await Ij()}catch(t){console.error("[telemetry] relay failed:",t?.message||t)}finally{zm=!1}}},Tj),Vm.unref?.())}import Pl from"node:fs/promises";import lT from"node:path";import Rj from"node:os";var uT=()=>process.env.BOSTRAT_STATE_DIR||lT.join(process.env.HOME||Rj.tmpdir(),".bostrat"),dT=()=>lT.join(uT(),"dictation-glossary.json"),$j=100,Oj=500,Cj=["bostrat","globopi","codex","tmux","worktree","Deepgram","Linear","Firecracker","Tigris","WireGuard","misous","postyx","cedar","gerbil","Anthropic","Opus","Haiku","Sonnet","keyterm","monorepo","dogfood"],Bl=null,Jm=null,Ym=Promise.resolve();function sT(){let t={},e=Date.now();for(let n of Cj)t[n.toLowerCase()]={term:n,count:1,lastUsed:e,source:"seed"};return t}async function fT(){return Bl||(Jm??=Pl.readFile(dT(),"utf8").then(t=>JSON.parse(t)?.terms??sT()).catch(()=>sT()).then(t=>Bl=t).finally(()=>Jm=null),Jm)}async function aT(){let t=JSON.stringify({terms:Bl},null,2),e=dT(),n=`${e}.${process.pid}.tmp`;await Pl.mkdir(uT(),{recursive:!0}),await Pl.writeFile(n,t),await Pl.rename(n,e)}function Mj(){return Ym=Ym.then(aT,aT),Ym.catch(()=>{})}async function Xm(){return Object.values(await fT()).sort((e,n)=>n.count-e.count||n.lastUsed-e.lastUsed)}var Nj=t=>Math.max(1,Math.ceil(t.length/4));async function Pj(){let t=[],e=0;for(let{term:n}of await Xm()){let r=Nj(n);if(!(e+r>Oj)&&(t.push(n),e+=r,t.length>=$j))break}return t}async function Bj(t,e){let n=await fT(),r=t.toLowerCase(),o=n[r];n[r]={term:t,count:(o?.count??0)+1,lastUsed:Date.now(),source:o?.source??e}}var iT=t=>(t||"").split(/\s+/).map(e=>e.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"")).filter(Boolean),Nl=t=>t.toLowerCase();function cT(t){return!new RegExp("\\p{L}","u").test(t)||t.length<3?!1:/^[a-z]+$/.test(t)?t.length>=4:!0}async function pT(t,e){let n=iT(t),r=iT(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]=Nl(n[u])===Nl(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;)Nl(n[c])===Nl(r[l])?(c++,l++):a[c+1][l]>=a[c][l+1]?c++:(cT(r[l])&&i.add(r[l]),l++);for(;l<s;l++)cT(r[l])&&i.add(r[l]);if(!i.size)return[];for(let u of i)await Bj(u,"learned");return await Mj(),[...i]}var Qa=null;function Dj(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 mT(){if(!Qa)return null;let t=await Da();if(!t||t.apiKey.slice(-6)!==Qa.keyTail)return null;let{keyTail:e,...n}=Qa;return n}async function hT(t,e){let n=await Da();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 Pj())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=Dj(o.status,i);c.persistent&&(Qa={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 Qa=null,{transcript:(await o.json())?.results?.channels?.[0]?.alternatives?.[0]?.transcript??""}}st();var Zm={"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 jj(t){if(!t)return null;let e=String(t).trim();if(Zm[e])return e;let n=null;for(let r of Object.keys(Zm))e.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function Lj(t,e={}){let n=Zm[jj(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 Fj(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 ti=null;async function Uj(){if(!ti)return null;let t=await ul();if(!t||t.apiKey.slice(-6)!==ti.keyTail)return null;let{keyTail:e,...n}=ti;return n}async function Hj(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=Fj(e.status,o);s.persistent&&(ti={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}ti=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 Wj={openai:Hj};async function wT(){let t=await ul();return t?{configured:!0,provider:t.provider,model:t.model,voice:t.voice,problem:await Uj()}:{configured:!1}}async function gT(){let t=await ul();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 Wj[t.provider](t);return{provider:t.provider,model:t.model,voice:t.voice,...e}}async function yT(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=Lj(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=dt.dirname(Kj(import.meta.url)),bT=Number(process.env.PORT)||3362,Dl=Im(process.env),AT=Number(process.env.BOSTRAT_AUTO_TRIGGER_PCT)||80,hs=pS(process.env.BOSTRAT_ALLOW_IPS),rh=mS(process.env.BOSTRAT_VIEW_FRONT_CIDRS,Rl),ET=wS(),_T=process.env.BOSTRAT_ALLOW_LAN_TOKENLESS!=="1",v=ge();v.disable("x-powered-by");v.use((t,e,n)=>{e.setHeader("x-content-type-options","nosniff"),Il(t.headers.host)||(e.setHeader("x-frame-options","DENY"),e.setHeader("referrer-policy","strict-origin-when-cross-origin")),n()});v.use((t,e,n)=>{if(Ja(t)||hs.allowed(hs.clientIp(t))||rh.allows(t))return n();e.status(403).type("text/plain").send("bostrat: access restricted to the allowlist")});v.use(xS);v.use(bS({token:ET,enforce:_T}));v.use("/api/mocks",ge.json({limit:"1mb"}));v.use("/api/mocks",ge.raw({type:"image/png",limit:"24mb"}));v.use("/api/mocks",ge.raw({type:["video/mp4","video/webm"],limit:"105mb"}));v.use("/api/runbooks",ge.json({limit:"1mb"}));v.use("/api/tracks/adopt",ge.json({limit:"1mb"}));v.use("/api/telemetry",ge.json({limit:"256kb"}));v.use("/api/hook",ge.json({limit:"2mb"}));v.use("/api/dictation",ge.raw({type:["audio/*","video/mp4","application/octet-stream"],limit:"32mb"}));v.use("/api/tracks/:id/upload",ge.raw({type:()=>!0,limit:"25mb"}));v.use(ge.json({limit:"64kb"}));v.get("/api/health",async(t,e)=>{e.json({ok:!0,tmuxSocket:re,hostTmuxAlive:await _n(),autoTriggerPct:AT})});v.get("/api/sessions",async(t,e)=>{e.json({sessions:await be()})});v.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 In(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})}});v.delete("/api/sessions/:name",async(t,e)=>{let n=decodeURIComponent(t.params.name);if(!St(n))return e.status(400).json({error:"invalid session name"});if(!await nt(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}`})}});v.get("/api/context/:name",async(t,e)=>{let n=decodeURIComponent(t.params.name);if(!St(n))return e.status(400).json({error:"invalid session name"});let r=await nt(n);if(!r)return e.status(404).json({error:"session not found"});let o=await Cs(r.cwd,r.sessionId);if(!o)return e.json({available:!1,cwd:r.cwd,sessionId:r.sessionId||null});e.json({available:!0,...o})});v.post("/api/handoff/:name",async(t,e)=>{let n=decodeURIComponent(t.params.name);if(!St(n))return e.status(400).json({error:"invalid session name"});try{let r=await Hg(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)})}});v.get("/api/handoff/:name",(t,e)=>{let n=decodeURIComponent(t.params.name),r=Vi(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 kT=10;v.get("/api/idle-guard",async(t,e)=>{try{e.json(z0({tracks:await ot(),views:await Ef(),queuedOf:n=>Jo(n)}))}catch{e.status(500).json({busy:!0,reasons:["error"]})}});v.get("/api/tracks",async(t,e)=>{let n=(await ot()).filter(s=>!s.transferredTo),r=n.filter(s=>s.archivedAt&&!s.archiving),o=n;if(t.query.archived!=="all"&&r.length>kT){let s=new Set([...r].sort((a,i)=>(i.archivedAt||0)-(a.archivedAt||0)).slice(0,kT).map(a=>a.id));o=n.filter(a=>!a.archivedAt||a.archiving||s.has(a.id))}e.json({tracks:o,archivedTotal:r.length,agents:$a,agentAvailability:await Kc(),tickets:await gv()})});v.get("/api/cost",async(t,e)=>{try{let n=await ot();t.query.track&&(n=n.filter(o=>o.id===t.query.track));let r=await zv(n);if(r.cursorUsage=pf(),t.query.format==="text")return e.type("text/plain").send(Jv(r));e.json(r)}catch(n){e.status(500).json({error:n?.message||String(n)})}});v.get("/api/usage/roundup",async(t,e)=>{try{e.json(await Zv(await ot(),{window:t.query.window,from:t.query.from,to:t.query.to}))}catch(n){e.status(500).json({error:n?.message||String(n)})}});v.get("/api/usage/spend",async(t,e)=>{try{let n=await rS(await ot(),{window:t.query.window,from:t.query.from,to:t.query.to});n.cursorUsage=pf(),n.subscriptionMonthlyUsd=Number(process.env.BOSTRAT_SUBSCRIPTION_MONTHLY_USD)||null,n.caps=Ys(),e.json(n)}catch(n){e.status(500).json({error:n?.message||String(n)})}});v.get("/api/usage/caps",(t,e)=>{e.json(Ys())});v.post("/api/usage/caps",async(t,e)=>{try{e.json(await rc(t.body?.caps??{},{source:"local"}))}catch(n){e.status(400).json({error:n?.message||String(n)})}});v.get("/api/usage/limits",async(t,e)=>{try{let n=t.query.fresh==="1"||t.query.fresh==="true";e.json(await cS(await ot(),{fresh:n}))}catch(n){e.status(500).json({error:n?.message||String(n)})}});v.post("/api/hook",async(t,e)=>{try{let{mode:n,target:r}=await ih(t.get(si),{byToken:vp,legacy:()=>sa(t.body?.session_id,t.body?.cwd)});if(n==="refused")return gs("refused",{reason:"unknown-token",hook:t.body?.hook_event_name}),e.json({ok:!1,error:"unknown hook token"});if(n==="legacy-denied")return gs("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&&gs("mismatch",{track:r.track.id,box:r.box.name}),gs(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 Lv(t.body||{},()=>r);e.json({ok:!0,events:o.length})}catch(n){e.json({ok:!1,error:n?.message||String(n)})}});v.post("/api/telemetry",async(t,e)=>{try{if(!eT(hs.clientIp(t)))return e.json({ok:!0,dropped:!0});let n=await tT(t.body||{});e.json({ok:!0,events:n})}catch(n){e.json({ok:!1,error:n?.message||String(n)})}});v.get("/api/repos",async(t,e)=>{try{let n=await qe(),r=new Set((await Promise.all(n.map(a=>ut(a.path)))).filter(Boolean).map(a=>a.toLowerCase())),s=((await vs()).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)})}});v.get("/api/github/token",async(t,e)=>{try{e.json(await di(String(t.query.repo||"")))}catch(n){e.status(n?.status||502).json({error:n?.message||String(n)})}});v.get("/api/github/status",(t,e)=>{e.json({configured:ui(),calls:Nb(),latency:Vk()})});v.post("/api/github/refresh",(t,e)=>{gh(),e.json({ok:!0})});v.get("/api/gmail/search",async(t,e)=>{try{let n=await uS(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)})}});v.get("/api/gmail/messages/:id",async(t,e)=>{try{e.json({message:await dS(String(t.params.id))})}catch(n){e.status(n?.status||502).json({error:n?.message||String(n)})}});function oh(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 jl({repo:t=null,number:e=null,branch:n=null}){let r=t?await ut(t):null;if(r&&e!=null){let s=await Vt(r,e),a=s&&await X(s.trackId);if(a)return a}if(!n)return null;let o=await ot();return yc(o,n,s=>oh(s,t,r))}async function IT({repo:t=null,number:e=null,branch:n=null}){let r=await jl({repo:t,number:e,branch:n}).catch(()=>null);if(r&&!r.archivedAt&&!r.transferredTo)return r;if(!n)return null;let o=t?await ut(t).catch(()=>null):null,s=await ot();return yc(s,n,a=>!a.archivedAt&&!a.transferredTo&&oh(a,t,o))}async function Ee(t,{number:e,url:n=null,title:r=null,branch:o=null,repo:s=null,track:a=null,extra:i={}}){let c=a||await jl({repo:s,number:e,branch:o}).catch(()=>null);if(!c)return;let l=i.repo??(s?await ut(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 Jj(t){let e=(await ot()).filter(n=>!n.archivedAt&&!n.transferredTo);for(let n of t??[]){if(!n.prs?.length)continue;let r=await ut(n.path);if(r)for(let o of n.prs){if(await Vt(r,o.number))continue;let s=await yc(e,o.headRefName,a=>oh(a,n.path,r));s&&await se({repo:r,number:o.number,trackId:s.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"})}}}v.get("/api/git/prs",async(t,e)=>{try{let n=await tx();await Jj(n.repos).catch(()=>{}),e.json(n)}catch(n){e.status(500).json({error:n?.message||String(n)})}});v.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(!fa.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 ut((await sn(n)).path);if(!k)throw new Error("repo has no GitHub remote");let x=await jl({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 pa(n,y),await se({repo:k,number:y,trackId:x.id,url:d,headRef:l,title:u,source:"matched"}).catch(()=>{}),!await Qs(k,y,{merge:{method:w}}))throw new Error("couldn't record the auto-merge arm");return await Or(k,y,i===!0),await ta(k,y,c===!0&&i!==!0),Be(),await Ee("auto-armed",{number:y,url:d,title:u,branch:l,repo:n,track:x,...a?{extra:{updated:!0}}:{}}),e.json({ok:!0,number:y,auto:!0})}let f=await Lo(n,r,{method:o||"squash"});await Ee("merged",{number:f.number,url:d,title:u,branch:l,repo:n});let p=await ut(n).catch(()=>null),h=!1;if(p&&(i===!0&&await Or(p,f.number,!0).catch(()=>{}),c===!0&&i!==!0&&await ta(p,f.number,!0).catch(()=>{}),await en(p,f.number).catch(()=>{}),h=await tn(p,f.number).catch(()=>!1),await Hn(p,f.number,"merged").catch(()=>{})),i===!0&&!h){let w=await jl({repo:n,number:f.number,branch:l}).catch(()=>null);w&&!w.archivedAt&&await Hr(w.id).catch(()=>{})}e.json(f)}catch(f){let p=f?.message||String(f),h=/invalid|unknown repo|required|needs a Track|no GitHub remote/i.test(p)?400:502;e.status(h).json({error:p})}});v.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 ut((await sn(n)).path).catch(()=>null),l=c?await ea(c,i).catch(()=>null):null;try{await Pf(n,i)}catch(u){if(!l)throw u}Be(),await Ee("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})}});v.post("/api/git/prs/merge-all",async(t,e)=>{let{repo:n,method:r}=t.body||{};try{let o=await ut(n).catch(()=>null),s=await ox(n,{method:r||"merge",onMerged:a=>{Ee("merged",{number:a.number,url:a.url,title:a.title,branch:a.headRefName,repo:n}),o&&en(o,a.number).catch(()=>{}).then(()=>tn(o,a.number)).catch(()=>{}).then(()=>Hn(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})}});v.get("/api/git/prs/merge-all",(t,e)=>{e.json({jobs:rx()})});v.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(!fa.has(i))throw new Error(`invalid merge method: ${i}`);if(!n)return e.status(400).json({error:"trackId required"});let c=await X(n);if(!c)return e.status(404).json({error:`Track ${n} isn't on this node`});let l=(await Cr()).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 Or(f.repo,f.number,o===!0).catch(()=>{}),await ta(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 h=await Br(f.repo);if(!h)throw new Error(`no local checkout for ${f.repo}`);let w=await jo(h,f.number);d.push({r:p,l:f,repoPath:h,pr:w,plan:ex(w,{update:r!==!1})})}catch(h){p.ok=!1,p.action="failed",p.reason=h?.message||String(h)}}for(let{r:f,l:p,repoPath:h,pr:w,plan:y}of nx(d))try{if(y.action==="skip")f.action="skipped",f.reason=y.reason;else if(y.action==="merge")await Lo(h,p.number,{method:i}),await Ee("merged",{number:p.number,url:w.url,title:w.title,branch:w.headRefName,repo:h,track:c}),await en(p.repo,p.number).catch(()=>{}),await tn(p.repo,p.number).catch(()=>{}),await Hn(p.repo,p.number,"merged").catch(()=>{}),f.action="merged";else{if(y.action==="update-arm"&&(await pa(h,p.number).catch(()=>{}),f.action="updated-armed"),!await Qs(p.repo,p.number,{merge:{method:i}}))throw new Error("couldn't record the auto-merge arm");await Ee("auto-armed",{number:p.number,url:w.url,title:w.title,branch:w.headRefName,repo:h,track:c,...f.action==="updated-armed"?{extra:{updated:!0}}:{}})}}catch(k){f.ok=!1,f.action="failed",f.reason=k?.message||String(k)}if(Be(),!u.some(f=>f.ok)){if(o===!0)for(let f of l)await Or(f.repo,f.number,!1).catch(()=>{});if(s===!0&&o!==!0)for(let f of l)await ta(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})}});v.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 X(n);if(!r)return e.status(404).json({error:`Track ${n} isn't on this node`});let o=(await Cr()).filter(a=>a.trackId===r.id&&a.state!=="merged"&&a.state!=="closed"),s=[];for(let a of o){let i=await ea(a.repo,a.number).catch(()=>null),c=await Br(a.repo).catch(()=>null);c&&await Pf(c,a.number).catch(()=>{}),i&&(await Ee("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}))}Be(),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})}});v.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 X(n);if(!i)return e.status(404).json({error:`Track ${n} isn't on this node`});if(i.workspace?.kind==="multi"){let u=ie(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 No(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 ut(w.dir).catch(()=>null);k&&y.number&&await se({repo:k,number:y.number,trackId:i.id,url:y.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await Ee("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 Df(i.cwd,{title:r,body:o,base:s}),l=await ut(i.cwd).catch(()=>null);l&&c.number&&await se({repo:l,number:c.number,trackId:i.id,url:c.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await Ee("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})}});v.get("/api/tracks/:id/repos",async(t,e)=>{try{let n=await X(t.params.id);if(!n)return e.status(404).json({error:"track not found"});let r=await No(n),o=new Map(r.map(a=>[a.base,a])),s=ie(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)})}});v.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 Cp(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})}});v.delete("/api/tracks/:id/repos/:name",async(t,e)=>{try{let n=await Mp(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})}});v.post("/api/git/prs/fix",async(t,e)=>{let{repo:n,number:r}=t.body||{};try{let o=await jo(n,r),s=await ut(n).catch(()=>null),a=await IT({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=ie(a.workspace).find(k=>k.base===n||s&&k.repo===s)??null,c=a.workspace?.kind==="multi",l=await sx(n,o.number);if(!l.length)return e.status(409).json({error:"no failing checks on this PR"});let u=c&&i?dt.join("ci",i.name):"ci",d=dt.join(a.cwd,".bostrat",u),f=dt.join(".bostrat",u,`pr-${o.number}-fail.log`);await Ht.promises.mkdir(d,{recursive:!0}),await Ht.promises.writeFile(dt.join(a.cwd,f),l.map(k=>`\u2550\u2550\u2550\u2550 ${k.name}${k.link?` \xB7 ${k.link}`:""} \u2550\u2550\u2550\u2550
524
525
  ${k.log??"(no fetchable log \u2014 see link)"}
525
526
  `).join(`
526
- `));let h=l.map(k=>k.name).join(", "),p=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}${p}. Failing check${l.length===1?"":"s"}: ${h}. 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 oe({repo:y,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await vb(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: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})}});S.post("/api/git/prs/reconcile",async(t,e)=>{let{repo:n,number:r}=t.body||{};try{let o=await Co(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 iT({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(d=>d.base===n||s&&d.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 Tb(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=tc.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 Y(t.params.id);if(!a)return e.status(404).json({error:"track not found"});let i=await F(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 Cm(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 me(a.id,Ao(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&&mp(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 Mm(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:QS(e,t.headers)});S.get("/api/views",async(t,e)=>{try{let n=await mf({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 pk(t.params.id);if(!n)return e.status(404).json({error:"view not found"});e.json({view:za(t)(n),session:Ro(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 wf({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 mk(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 hk(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 wk(t.params.id))}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:500).json({error:r})}});var mj=[["linear",Lr,Gp],["jira",Qc,qp]],Um=new Map;S.get("/api/integrations/ticketing",async(t,e)=>{try{let n=await Wp(),r={};for(let[o,s,a]of mj){let i=await s();if(!i){Um.delete(o),r[o]={configured:!1};continue}let c=Um.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},Um.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 Wp()})}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 Cx(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 qr=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 Lp()})}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 qr(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 zo(o);await Jc(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 qr(n,r);if(!o)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});await Jc(o,null,{source:"chat"}),e.json({ok:!0,trackId:o.id})}catch(o){e.status(502).json({error:o?.message||String(o)})}});var cT=async(t,e,n)=>{if(t)return{ref:t,track:await qr(e,n)};let r=await qr(e,n),o=r?await Up(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 cT(o,n,r),l=await Ax({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 cT(t.query.circuit,t.query.track,t.query.cwd);e.json(await Fp(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/decisions/record",async(t,e)=>{let{trackId:n,cwd:r,title:o,context:s,decision:a,alternatives:i,supersedesId:c}=t.body||{};try{let l=await qr(n,r);if(!l)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let u=await _x(l,{title:o,context:s,decision:a,alternatives:i,supersedesId:c});e.json({ok:!0,trackId:l.id,...u})}catch(l){let u=l?.message||String(l);e.status(/required/i.test(u)?400:502).json({error:u})}});S.get("/api/decisions",async(t,e)=>{try{let n=await qr(t.query.track,t.query.cwd);if(!n)return e.status(400).json({error:"run from inside a Track workspace"});e.json(await Ix(n.id))}catch(n){let r=n?.message||String(n);e.status(/no plane|required|run from inside/i.test(r)?400: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 qr(n,r);if(!a)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=await Up(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 Ex(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 Xo(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 zx(),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 Xo(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 om(t.params.id)})});var $l=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 Zx(t.params.id))}catch(n){let r=n?.message||String(n);e.status($l(r)).json({error:r})}});S.post("/api/tracks/:id/ticket/state",async(t,e)=>{try{e.json({ok:!0,...await sm(t.params.id,(t.body||{}).stateId)})}catch(n){let r=n?.message||String(n);e.status($l(r)).json({error:r})}});S.post("/api/tracks/:id/ticket/comment",async(t,e)=>{try{e.json({ok:!0,...await Qx(t.params.id,(t.body||{}).body)})}catch(n){let r=n?.message||String(n);e.status($l(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 tS(o,n,r===!0)})}catch(o){let s=o?.message||String(o);e.status($l(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 _p(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 nS(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 eS()})}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 rS(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 ia({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})});var Ja={dotfiles:"allow"};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=sa(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,Ja,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=sa(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,Ja,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,Ja,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&&_c(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 Y(a):null;if(!d&&c&&(d=(await nt()).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(p=>p.name===d.leadBox),h=await Vk({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:h})}catch(d){let f=d?.message||String(d);e.status(/required|invalid|must be/i.test(f)?400:500).json({error:f})}});S.post("/api/mocks/:id/update",async(t,e)=>{let n=Buffer.isBuffer(t.body)?t.body:null,r=n&&_c(n)?n:null;try{let o=await zk(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 Xk(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 h0(t.params.id)).map(r=>({id:r.id,name:r.name}));e.json({...await Zk(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 u0({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 d0(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 f0({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 p0(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 m0(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 v0({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 Lf(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 Lf(t.params.id);if(!n)return e.status(404).json({error:"runbook not found"});let r=x0(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 T0(n,r.v);return typeof o!="string"?e.status(404).json({error:"runbook artifact missing"}):e.send(o)}e.sendFile(cn(n,r.v),Ja,o=>{o&&!e.headersSent&&e.status(404).json({error:"runbook artifact missing"})})});S.get("/api/loops",async(t,e)=>{e.json(await Am())});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 Am();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 rv({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 cv(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 lv(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 A0({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 E0(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 _0(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 I0(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=fv(t.query.since||null);e.json({since:n,repos:Em(),prs:await pv(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 mv(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 hj=120,Hm=400,Rl=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>Hm)return e.status(400).json({error:`message is ${i.length} chars \u2014 over the ${Hm} cap; a notification is a nudge, put the detail in chat`});let c=ca(`${n||""}
527
- ${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(p=>p.cwd&&(s===p.cwd||s.startsWith(p.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(h=>h.name===l.leadBox),d=(h,p)=>String(h).replace(/\s+/g," ").trim().slice(0,p),f={title:n?d(n,hj):l.name,body:d(i,Hm),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:Rl?Rl.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 zv(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 Ia(),terms:await Lm(),problem:await Vv()})});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 Gv(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 Jv())});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 Yv())}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 Xv(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 Fc({name:n,cwd:r,repo:o,repos:s,agent:a,skipPermissions:i!==!1}),d=null;if(c)try{await Xo(u,c,{source:"create"})}catch(h){d=h?.message||String(h)}let f=null;if(l)try{await Jc(u,await zo(l),{source:"picker"})}catch(h){f=h?.message||String(h)}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})}});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:lT(Vo(t.params.id)),subtasks:jr(t.params.id).map(Ya)})});S.delete("/api/tracks/:id",async(t,e)=>{try{let n=await Tp(t.params.id,{cascadeMocks:t.query.mocks!=="0",cascadeRunbooks:t.query.runbooks==="1"});await om(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 Dr(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 Ap(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}
527
+ `));let p=l.map(k=>k.name).join(", "),h=c&&i?` in the ${i.name}/ checkout`:"",w=await we(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 ${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 se({repo:y,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await jb(y,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await Ee("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})}});v.post("/api/git/prs/reconcile",async(t,e)=>{let{repo:n,number:r}=t.body||{};try{let o=await jo(n,r);if(o.mergeable!=="CONFLICTING")return e.status(409).json({error:"this PR does not conflict with its base branch"});let s=await ut(n).catch(()=>null),a=await IT({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=ie(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 we(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 se({repo:u,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await Lb(u,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await Ee("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})}});v.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=cc.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 X(t.params.id);if(!a)return e.status(404).json({error:"track not found"});let i=await B(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 qm(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 we(a.id,Io(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&&_p(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})}});v.post("/api/tracks/:id/pr-exists",async(t,e)=>{let{offerId:n,choice:r}=t.body||{};try{let o=await X(t.params.id);if(!o)return e.status(404).json({error:"track not found"});let{say:s}=await Km(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 ei=t=>e=>({...e,url:SS(e,t.headers)});v.get("/api/views",async(t,e)=>{try{let n=await Ef({trackId:t.query.track||void 0});e.json({views:n.map(ei(t)),maxLive:Gn})}catch(n){e.status(500).json({error:n?.message||String(n)})}});v.get("/api/views/:id",async(t,e)=>{let n=await jk(t.params.id);if(!n)return e.status(404).json({error:"view not found"});e.json({view:ei(t)(n),session:Po(n.slug)})});v.post("/api/views",async(t,e)=>{let{trackId:n,name:r,cmd:o,cwd:s,port:a}=t.body||{};try{let i=n?await X(n):null;if(!i&&s&&(i=(await ot()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+dt.sep)))||null),!i)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let c=await If({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:ei(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})}});v.post("/api/views/:id/stop",async(t,e)=>{try{e.json({ok:!0,view:ei(t)(await Lk(t.params.id))})}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:500).json({error:r})}});v.post("/api/views/:id/restart",async(t,e)=>{try{e.json({ok:!0,view:ei(t)(await Fk(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})}});v.delete("/api/views/:id",async(t,e)=>{try{e.json(await Uk(t.params.id))}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:500).json({error:r})}});var Yj=[["linear",qr,sm],["jira",ll,rm]],Qm=new Map;v.get("/api/integrations/ticketing",async(t,e)=>{try{let n=await nm(),r={};for(let[o,s,a]of Yj){let i=await s();if(!i){Qm.delete(o),r[o]={configured:!1};continue}let c=Qm.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},Qm.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)})}});v.get("/api/tickets/flow",async(t,e)=>{try{e.json({flow:await nm()})}catch(n){e.status(500).json({error:n?.message||String(n)})}});v.post("/api/tickets/flow",async(t,e)=>{let{trackId:n,cwd:r,set:o,actor:s}=t.body||{};try{let a=await nv(o),i=n?await X(n):null;!i&&r&&(i=(await ot()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+dt.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 Jr=async(t,e)=>{let n=t?await X(t):null;return!n&&e&&(n=(await ot()).find(o=>o.cwd&&(e===o.cwd||e.startsWith(o.cwd+dt.sep)))||null),n};v.get("/api/circuits",async(t,e)=>{try{e.json({circuits:await Zp()})}catch(n){e.status(502).json({error:n?.message||String(n)})}});v.post("/api/circuits/link",async(t,e)=>{let{trackId:n,cwd:r,ref:o}=t.body||{};try{let s=await Jr(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 es(o);await sl(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})}});v.post("/api/circuits/unlink",async(t,e)=>{let{trackId:n,cwd:r}=t.body||{};try{let o=await Jr(n,r);if(!o)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});await sl(o,null,{source:"chat"}),e.json({ok:!0,trackId:o.id})}catch(o){e.status(502).json({error:o?.message||String(o)})}});var RT=async(t,e,n)=>{if(t)return{ref:t,track:await Jr(e,n)};let r=await Jr(e,n),o=r?await tm(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}};v.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 RT(o,n,r),l=await J0({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})}});v.get("/api/blueprints/show",async(t,e)=>{try{let{ref:n}=await RT(t.query.circuit,t.query.track,t.query.cwd);e.json(await Qp(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})}});v.post("/api/decisions/record",async(t,e)=>{let{trackId:n,cwd:r,title:o,context:s,decision:a,alternatives:i,supersedesId:c}=t.body||{};try{let l=await Jr(n,r);if(!l)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let u=await X0(l,{title:o,context:s,decision:a,alternatives:i,supersedesId:c});e.json({ok:!0,trackId:l.id,...u})}catch(l){let u=l?.message||String(l);e.status(/required/i.test(u)?400:502).json({error:u})}});v.get("/api/decisions",async(t,e)=>{try{let n=await Jr(t.query.track,t.query.cwd);if(!n)return e.status(400).json({error:"run from inside a Track workspace"});e.json(await Z0(n.id))}catch(n){let r=n?.message||String(n);e.status(/no plane|required|run from inside/i.test(r)?400:502).json({error:r})}});v.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 Jr(n,r);if(!a)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=await tm(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 Y0(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})}});v.post("/api/tickets/link",async(t,e)=>{let{trackId:n,cwd:r,ref:o}=t.body||{};try{let s=n?await X(n):null;if(!s&&r&&(s=(await ot()).find(c=>c.cwd&&(r===c.cwd||r.startsWith(c.cwd+dt.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 os(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})}});v.get("/api/tickets/status",async(t,e)=>{let{cwd:n,track:r}=t.query;try{let o=r?await X(r):null;if(!o&&n&&(o=(await ot()).find(a=>a.cwd&&(n===a.cwd||String(n).startsWith(a.cwd+dt.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 yv(),ticket:await We(o.id)})}catch(o){e.status(500).json({error:o?.message||String(o)})}});v.get("/api/tracks/:id/ticket",async(t,e)=>{e.json({ticket:await We(t.params.id)})});v.post("/api/tracks/:id/ticket",async(t,e)=>{try{let n=await X(t.params.id);if(!n)return e.status(404).json({error:"track not found"});let r=await os(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})}});v.delete("/api/tracks/:id/ticket",async(t,e)=>{e.json({ok:!0,removed:await gm(t.params.id)})});var Fl=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;v.get("/api/tracks/:id/ticket/states",async(t,e)=>{try{e.json(await vv(t.params.id))}catch(n){let r=n?.message||String(n);e.status(Fl(r)).json({error:r})}});v.post("/api/tracks/:id/ticket/state",async(t,e)=>{try{e.json({ok:!0,...await ym(t.params.id,(t.body||{}).stateId)})}catch(n){let r=n?.message||String(n);e.status(Fl(r)).json({error:r})}});v.post("/api/tracks/:id/ticket/comment",async(t,e)=>{try{e.json({ok:!0,...await Sv(t.params.id,(t.body||{}).body)})}catch(n){let r=n?.message||String(n);e.status(Fl(r)).json({error:r})}});v.post("/api/tracks/:id/ticket-offer",async(t,e)=>{let{offerId:n,accept:r}=t.body||{};try{let o=await X(t.params.id);if(!o)return e.status(404).json({error:"track not found"});e.json({ok:!0,...await Tv(o,n,r===!0)})}catch(o){let s=o?.message||String(o);e.status(Fl(s)).json({error:s})}});v.post("/api/tracks/:id/fullscreen-offer",async(t,e)=>{let{offerId:n,accept:r}=t.body||{};try{e.json(await Fp(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})}});v.post("/api/tickets/propose",async(t,e)=>{let{trackId:n,cwd:r,plan:o}=t.body||{};try{let s=n?await X(n):null;if(!s&&r&&(s=(await ot()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+dt.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 Ev(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})}});v.get("/api/tickets/teams",async(t,e)=>{try{e.json({teams:await Av()})}catch(n){let r=n?.message||String(n);e.status(/no ticketing/i.test(r)?400:502).json({error:r})}});v.post("/api/tracks/:id/ticket-create-offer",async(t,e)=>{let{proposalId:n,accept:r,teamId:o}=t.body||{};try{let s=await X(t.params.id);if(!s)return e.status(404).json({error:"track not found"});e.json({ok:!0,...await _v(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})}});v.get("/api/mocks",async(t,e)=>{try{e.json({mocks:await ga({trackId:t.query.track||void 0,group:t.query.group||void 0})})}catch(n){e.status(500).json({error:n?.message||String(n)})}});v.get("/api/mocks/:id",async(t,e)=>{let n=await an(t.params.id);if(!n)return e.status(404).json({error:"mock not found"});e.json({mock:n})});var ni={dotfiles:"allow"};v.get("/api/mocks/:id/png",async(t,e)=>{let n=await an(t.params.id);if(!n)return e.status(404).json({error:"mock not found"});let r=Te(n,t.query.v??null);if(!r)return e.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=ha(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,ni,s=>{s&&!e.headersSent&&e.status(404).json({error:"rendered artifact missing"})})});v.get("/api/mocks/:id/media",async(t,e)=>{let n=await an(t.params.id);if(!n)return e.status(404).json({error:"mock not found"});let r=Te(n,t.query.v??null);if(!r)return e.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=ha(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,ni,s=>{s&&!e.headersSent&&e.status(404).json({error:"video artifact missing"})})});v.get("/api/mocks/:id/html",async(t,e)=>{let n=await an(t.params.id);if(!n)return e.status(404).json({error:"mock not found"});let r=Te(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(me(n,r.v).html,ni,o=>{o&&!e.headersSent&&e.status(404).json({error:"source artifact missing"})})});v.post("/api/mocks",async(t,e)=>{let n=Buffer.isBuffer(t.body)?t.body:null,r=n&&Bc(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 X(a):null;if(!d&&c&&(d=(await ot()).find(w=>w.cwd&&(c===w.cwd||c.startsWith(w.cwd+dt.sep)))||null),!d)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let f=(d.boxes||[]).find(h=>h.name===d.leadBox),p=await yx({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})}});v.post("/api/mocks/:id/update",async(t,e)=>{let n=Buffer.isBuffer(t.body)?t.body:null,r=n&&Bc(n)?n:null;try{let o=await bx(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})}});v.post("/api/mocks/:id/pick",async(t,e)=>{try{let{mock:n,siblings:r}=await vx(t.params.id),o=r.length?` over ${r.map(s=>`"${s.name}"`).join(", ")}`:"";await we(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})}});v.delete("/api/mocks/:id",async(t,e)=>{try{let n=(await Fx(t.params.id)).map(r=>({id:r.id,name:r.name}));e.json({...await Sx(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})}});v.get("/api/flows",async(t,e)=>{try{e.json({flows:await Px({trackId:t.query.track||void 0})})}catch(n){e.status(500).json({error:n?.message||String(n)})}});v.get("/api/flows/:id",async(t,e)=>{let n=await Bx(t.params.id);if(!n)return e.status(404).json({error:"flow not found"});e.json({flow:n})});v.post("/api/flows",async(t,e)=>{let{trackId:n,name:r,steps:o,cwd:s}=t.body||{};try{let a=n?await X(n):null;if(!a&&s&&(a=(await ot()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+dt.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 Dx({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})}});v.post("/api/flows/:id/update",async(t,e)=>{try{let{steps:n,note:r}=t.body||{};e.json({ok:!0,flow:await jx(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})}});v.delete("/api/flows/:id",async(t,e)=>{try{e.json(await Lx(t.params.id))}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:500).json({error:r})}});v.get("/api/runbooks",async(t,e)=>{try{let n=t.query.track||void 0;if(!n&&t.query.cwd){let s=await ot(),a=String(t.query.cwd);if(n=s.find(i=>i.cwd&&(a===i.cwd||a.startsWith(i.cwd+dt.sep)))?.id,!n)return e.json({runbooks:[]})}let{runbooks:r,fleetDegraded:o}=await zx({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)})}});v.get("/api/runbooks/:id",async(t,e)=>{let n=await Xf(t.params.id);if(!n)return e.status(404).json({error:"runbook not found"});e.json({runbook:n})});v.get("/api/runbooks/:id/md",async(t,e)=>{let n=await Xf(t.params.id);if(!n)return e.status(404).json({error:"runbook not found"});let r=Gx(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 Jx(n,r.v);return typeof o!="string"?e.status(404).json({error:"runbook artifact missing"}):e.send(o)}e.sendFile(dn(n,r.v),ni,o=>{o&&!e.headersSent&&e.status(404).json({error:"runbook artifact missing"})})});v.get("/api/loops",async(t,e)=>{e.json(await xc())});v.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 ot()).find(u=>u.cwd&&(o===u.cwd||o.startsWith(u.cwd+dt.sep)))||null;if(!a)return e.status(400).json({error:"cwd is not inside a Track workspace"});let i=await xc();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 sf({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})});v.post("/api/loops/propose",async(t,e)=>{let{trackId:n,cwd:r,plan:o}=t.body||{};try{let s=n?await X(n):null;if(!s&&r&&(s=(await ot()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+dt.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 IS(s,o)})}catch(s){e.status(400).json({error:s?.message||String(s)})}});v.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 X(t.params.id);if(!a)return e.status(404).json({error:"track not found"});e.json({ok:!0,...await RS(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})}});v.post("/api/runbooks",async(t,e)=>{let{trackId:n,name:r,md:o,cwd:s}=t.body||{};try{let a=n?await X(n):null;if(!a&&s&&(a=(await ot()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+dt.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 Yx({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})}});v.post("/api/runbooks/:id/update",async(t,e)=>{try{let{md:n,note:r}=t.body||{};e.json({ok:!0,runbook:await Xx(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})}});v.post("/api/runbooks/:id/status",async(t,e)=>{try{e.json({ok:!0,runbook:await Zx(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})}});v.delete("/api/runbooks/:id",async(t,e)=>{try{e.json(await Qx(t.params.id))}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:500).json({error:r})}});v.get("/api/changelog/draft",async(t,e)=>{try{let n=CS(t.query.since||null);e.json({since:n,repos:jm(),prs:await MS(n)})}catch(n){let r=n?.message||String(n);e.status(/unparseable/i.test(r)?400:500).json({error:r})}});v.post("/api/changelog/publish",async(t,e)=>{let{md:n,day:r,trackId:o,cwd:s}=t.body||{};try{let a=o?await X(o):null;if(!a&&s&&(a=(await ot()).find(c=>c.cwd&&(s===c.cwd||String(s).startsWith(c.cwd+dt.sep)))||null),!a)return e.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});e.json({ok:!0,entry:await NS(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 Xj=120,th=400,Ll=null;v.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>th)return e.status(400).json({error:`message is ${i.length} chars \u2014 over the ${th} cap; a notification is a nudge, put the detail in chat`});let c=ya(`${n||""}
528
+ ${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 X(a):null;if(!l&&s&&(l=(await ot()).find(h=>h.cwd&&(s===h.cwd||s.startsWith(h.cwd+dt.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,h)=>String(p).replace(/\s+/g," ").trim().slice(0,h),f={title:n?d(n,Xj):l.name,body:d(i,th),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:Ll?Ll.status().connected:null})}catch(i){e.status(500).json({error:i?.message||String(i)})}});v.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 hT(t.body,t.headers["content-type"]))}catch(n){e.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});v.get("/api/dictation/glossary",async(t,e)=>{e.json({configured:!!await Da(),terms:await Xm(),problem:await mT()})});v.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 pT(n,r)})});v.get("/api/tracks/:id/voice-chat",async(t,e)=>{if(!await X(t.params.id))return e.status(404).json({error:"track not found"});e.json(await wT())});v.post("/api/tracks/:id/voice-chat/session",async(t,e)=>{try{let n=await X(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 gT())}catch(n){e.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});v.post("/api/tracks/:id/voice-chat/usage",async(t,e)=>{try{let n=await X(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 yT(n,{model:r,usage:o,seconds:s})})}catch(n){e.status(n?.status||500).json({error:n?.message||String(n)})}});v.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 Yc({name:n,cwd:r,repo:o,repos:s,agent:a,skipPermissions:i!==!1}),d=null;if(c)try{await os(u,c,{source:"create"})}catch(p){d=p?.message||String(p)}let f=null;if(l)try{await sl(u,await es(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})}});v.get("/api/tracks/:id",async(t,e)=>{let n=await X(t.params.id);if(!n)return e.status(404).json({error:"track not found"});e.json({track:n,handoff:$T(ts(t.params.id)),subtasks:Wr(t.params.id).map(ri)})});v.delete("/api/tracks/:id",async(t,e)=>{try{let n=await Dp(t.params.id,{cascadeMocks:t.query.mocks!=="0",cascadeRunbooks:t.query.runbooks==="1"});await gm(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})}});v.post("/api/tracks/:id/archive",async(t,e)=>{try{e.json({ok:!0,track:await Hr(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})}});v.post("/api/tracks/:id/unarchive",async(t,e)=>{try{e.json({ok:!0,track:await jp(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})}});v.get("/api/tracks/:id/messages",async(t,e)=>{let n=await Gc(t.params.id);if(!n)return e.status(404).json({error:"track not found"});e.json(n)});v.get("/api/tracks/:id/events",async(t,e)=>{let n=await X(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}
528
529
  data: ${JSON.stringify(i)}
529
530
 
530
- `),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=Ew(n.id,r),a=setInterval(()=>e.write(`: hb
531
+ `),o=Number(t.query.since??t.headers["last-event-id"])||0;for(let i of await B(n))i.seq>o&&r(i);let s=Qw(n.id,r),a=setInterval(()=>e.write(`: hb
531
532
 
532
- `),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=$s(await F(n)),a=Oi(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 kh()})});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 xh(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 wj=["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(`
533
- `);S.post("/api/tracks/:id/memory/consolidate",async(t,e)=>{try{e.json({ok:!0,...await me(t.params.id,wj)})}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 Wc(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 N0(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||!Hf(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=Uf(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 gj=/^[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(!gj.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=Ge(a.cwd,a.sessionId);if(!i)return e.status(404).json({error:"transcript not found"});let c=`"${o}"`,l=null,u=cj.createInterface({input:Ut.createReadStream(i,{encoding:"utf8"}),crlfDelay:1/0});for await(let f of u){if(!f.includes(c))continue;let h;try{h=JSON.parse(f)}catch{continue}if(h.uuid===o){l=h,u.close();break}}let d=l?cu(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)})}});S.post("/api/tracks/:id/interrupt",async(t,e)=>{try{e.json(await Lc(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 pp(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 jc(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 Sp({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 dp(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 gp(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 hl(r,{fresh:o}))});S.post("/api/tracks/:id/model",async(t,e)=>{let{model:n}=t.body||{};try{e.json(await yp(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 Bp(t.params.id,{agent:n,task:r,skipPermissions:o!==!1,reason:s});e.json({ok:!0,subtask:Ya(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(Ya)})});S.get("/api/tracks/:id/subtask/:sid/messages",async(t,e)=>{let n=await up(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:Ya(zc(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:Ya(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 Ya(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 Kc(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 hp(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(lT(Vo(t.params.id))??{running:!1})});S.post("/api/tracks/:id/transfer-out",async(t,e)=>{try{let n=await Op(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=$p(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 Gc(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 Mp({...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 lT(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:hi(),paths:Dh,trace:await Bh({limit:n})})});var Wm=ut.resolve(rT,"..","..","client","dist");Ut.existsSync(Wm)&&(S.use(he.static(Wm)),S.get(/^(?!\/api\/).*/,(t,e)=>e.sendFile(ut.join(Wm,"index.html"),Ja)));var uT=uj.createServer(S),yj=new fj({noServer:!0}),dT=(t,e,n)=>{if(!(Fa(t)||as.allowed(as.clientIp(t))||Km.allows(t))){e.write(`HTTP/1.1 403 Forbidden\r
533
+ `),25e3);t.on("close",()=>{clearInterval(a),s()})});v.get("/api/tracks/:id/search",async(t,e)=>{let n=await X(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=Ws(await B(n)),a=Li(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}))})});v.get("/api/memory",async(t,e)=>{e.json({stores:await Ch()})});v.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 Mh(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 Zj=["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(`
534
+ `);v.post("/api/tracks/:id/memory/consolidate",async(t,e)=>{try{e.json({ok:!0,...await we(t.params.id,Zj)})}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})}});v.post("/api/tracks/:id/lead/restart",async(t,e)=>{try{e.json({ok:!0,track:await Qc(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})}});v.post("/api/tracks/:id/say",async(t,e)=>{let{text:n,attachments:r}=t.body||{};try{e.json(await we(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})}});v.post("/api/tracks/:id/upload",async(t,e)=>{try{let n=await X(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 s0(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})}});v.get("/api/tracks/:id/uploads/:file",async(t,e)=>{try{let n=await X(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=dt.basename(String(t.params.file||""));if(!r||!tp(dt.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=Qf(n.cwd),s,a;try{s=await Ht.promises.realpath(o),a=await Ht.promises.realpath(dt.join(o,r))}catch{return e.status(404).json({error:"upload not found"})}if(!a.startsWith(s+dt.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 Qj=/^[0-9a-fA-F-]{8,64}$/;v.get("/api/tracks/:id/chat-images/:box/:uuid/:idx",async(t,e)=>{try{let n=await X(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(!Qj.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=ze(a.cwd,a.sessionId);if(!i)return e.status(404).json({error:"transcript not found"});let c=`"${o}"`,l=null,u=qj.createInterface({input:Ht.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?_u(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)})}});v.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})}});v.delete("/api/tracks/:id/queue",async(t,e)=>{try{let{removed:n,restored:r,draftRev:o}=await Ap(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)})}});v.post("/api/tracks/:id/answer-prompt",async(t,e)=>{let{promptId:n,answers:r,text:o}=t.body||{};try{e.json(await Vc(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})}});v.post("/api/setup/:provider/start",async(t,e)=>{try{let n=await Pp({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})}});v.post("/api/tracks/:id/navigate-prompt",async(t,e)=>{let{promptId:n,questionIndex:r}=t.body||{};try{e.json(await Tp(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})}});v.put("/api/tracks/:id/draft",async(t,e)=>{let{text:n,rev:r}=t.body||{};try{e.json(await $p(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})}});v.get("/api/tracks/:id/usage",async(t,e)=>{let n=await X(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 Al(r,{fresh:o}))});v.post("/api/tracks/:id/model",async(t,e)=>{let{model:n}=t.body||{};try{e.json(await Op(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})}});v.post("/api/tracks/:id/subtask",async(t,e)=>{let{agent:n,task:r,skipPermissions:o,reason:s}=t.body||{};try{let a=await Jp(t.params.id,{agent:n,task:r,skipPermissions:o!==!1,reason:s});e.json({ok:!0,subtask:ri(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})}});v.get("/api/tracks/:id/subtasks",(t,e)=>{e.json({subtasks:Wr(t.params.id).map(ri)})});v.get("/api/tracks/:id/subtask/:sid/messages",async(t,e)=>{let n=await Sp(t.params.id,t.params.sid);if(!n)return e.status(404).json({error:"subtask not found"});e.json(n)});v.post("/api/tracks/:id/subtask/:sid/cancel",(t,e)=>{try{e.json({ok:!0,subtask:ri(ol(t.params.sid))})}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:409).json({error:r})}});v.post("/api/tracks/:id/subtask/:sid/merge-now",(t,e)=>{try{e.json({ok:!0,subtask:ri(Yp(t.params.sid))})}catch(n){let r=n?.message||String(n);e.status(/not found/i.test(r)?404:409).json({error:r})}});function ri(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}v.post("/api/tracks/:id/handoff-lead",async(t,e)=>{let{toAgent:n,skipPermissions:r,reason:o}=t.body||{};try{let s=await el(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})}});v.post("/api/tracks/:id/spin-up-view",async(t,e)=>{try{e.json(await Ip(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})}});v.get("/api/tracks/:id/handoff-lead",(t,e)=>{e.json($T(ts(t.params.id))??{running:!1})});v.post("/api/tracks/:id/transfer-out",async(t,e)=>{try{let n=await qp(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})}});v.get("/api/tracks/:id/transfer-out",(t,e)=>{let n=Wp(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??{}})});v.post("/api/tracks/:id/transfer-out/commit",async(t,e)=>{try{e.json(await nl(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})}});v.post("/api/tracks/adopt",async(t,e)=>{let{trackId:n}=t.body||{};try{e.json(await Gp({...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 $T(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}v.get("/api/debug/handoff",async(t,e)=>{let n=Math.min(Number(t.query.limit)||80,500);e.json({verbose:vi(),paths:Jh,trace:await zh({limit:n})})});var eh=dt.resolve(TT,"..","..","client","dist");Ht.existsSync(eh)&&(v.use(ge.static(eh)),v.get(/^(?!\/api\/).*/,(t,e)=>e.sendFile(dt.join(eh,"index.html"),ni)));var OT=Gj.createServer(v),tL=new zj({noServer:!0}),CT=(t,e,n)=>{if(!(Ja(t)||hs.allowed(hs.clientIp(t))||rh.allows(t))){e.write(`HTTP/1.1 403 Forbidden\r
534
535
  \r
535
- `),e.destroy();return}if(ZS(t,e,n))return;if(!YS(t,sT,{enforce:aT})){e.write(`HTTP/1.1 401 Unauthorized\r
536
+ `),e.destroy();return}if(vS(t,e,n))return;if(!kS(t,ET,{enforce:_T})){e.write(`HTTP/1.1 401 Unauthorized\r
536
537
  \r
537
- `),e.destroy();return}let r=Yh(t.url);if(!r.ok){e.write(`HTTP/1.1 ${r.status} ${r.status===400?"Bad Request":"Not Found"}\r
538
+ `),e.destroy();return}let r=cw(t.url);if(!r.ok){e.write(`HTTP/1.1 ${r.status} ${r.status===400?"Bad Request":"Not Found"}\r
538
539
  \r
539
- `),e.destroy();return}let o=r.sessionName;if(!At(o)){e.write(`HTTP/1.1 400 Bad Request\r
540
+ `),e.destroy();return}let o=r.sessionName;if(!St(o)){e.write(`HTTP/1.1 400 Bad Request\r
540
541
  \r
541
- `),e.destroy();return}let{cols:s,rows:a}=r;yj.handleUpgrade(t,e,n,i=>Vh(i,o,{cols:s,rows:a}))};uT.on("upgrade",dT);var fT=process.env.BOSTRAT_CERT_DIR||ut.join(process.env.HOME||qm.tmpdir(),".bostrat","certs"),tT=Number(process.env.BOSTRAT_TLS_PORT)||3443,eT=ut.join(fT,"bostrat.globopi.key"),nT=ut.join(fT,"bostrat.globopi.crt");if(Ut.existsSync(eT)&&Ut.existsSync(nT)){let t=dj.createServer({key:Ut.readFileSync(eT),cert:Ut.readFileSync(nT)},S);t.on("upgrade",dT),t.on("error",e=>{console.error(`[bostrat-agent] https listener failed (${e?.code||e?.message}) \u2014 continuing HTTP-only`)}),t.listen(tT,_l,()=>{console.log(`[bostrat-agent] https listening on ${_l||"0.0.0.0"}:${tT}`)})}uT.listen(Zv,_l,()=>{console.log(`[bostrat-agent] listening on ${_l||"0.0.0.0"}:${Zv}`);let t=wS(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: ${oT}%`),console.log(`[bostrat-agent] ip allowlist: ${as.open?"OPEN":process.env.BOSTRAT_ALLOW_IPS||"CLOSED (BOSTRAT_ALLOW_IPS unset)"}`+(Km.active?` \xB7 view front-door: ${process.env.BOSTRAT_VIEW_FRONT_CIDRS} (registered views only)`:"")),Rp().then(e=>e&&console.log("[bostrat-agent] reconciled interrupted handoff(s)")).catch(e=>console.error("[bostrat-agent] handoff reconcile failed:",e?.message||e)),Np().then(e=>e&&console.log("[bostrat-agent] reconciled interrupted subtask(s)")).catch(e=>console.error("[bostrat-agent] subtask reconcile failed:",e?.message||e)),Ep().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)),xp().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)),Sj(),xj(),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)),L0()&&F0({listTracks:nt}),kv(),vv(),oS({resolveTrack:Y}),mS({listTracks:nt,createTrack:Fc,archiveTrack:Dr,listRepos:We,resolveTrack:Y,sayToLead:me,answerPrompt:jc,startLeadHandoff:Kc,interruptLead:Lc,listSubtaskJobs:jr,cancelSubtask:zc,readEvents:F,appendEvent:I,divertShip:Cm,answerPrExists:Mm,knownAgents:xa}),bj(),xs().then(e=>{e||console.warn(`[boot] no host tmux server on ${ne} and auto-start failed \u2014 boxes cannot spawn until one runs`)}),Dv(),process.env.BOSTRAT_PLANE_URL&&process.env.BOSTRAT_PLANE_TOKEN&&(Rl=bS({url:process.env.BOSTRAT_PLANE_URL,token:process.env.BOSTRAT_PLANE_TOKEN,nodeId:process.env.BOSTRAT_NODE_ID||qm.hostname(),name:process.env.BOSTRAT_NODE_NAME||qm.hostname(),listTracks:nt,detectAgents:Bc,sampleMetrics:xS,onTracksTransferred:Cp}),console.log(`[bostrat-agent] plane link \u2192 ${process.env.BOSTRAT_PLANE_URL}`),Yr().catch(()=>{}),O0().then(e=>e.pushed&&console.log(`[content-plane] seeded ${e.pushed} runbooks to the plane`),()=>{}),sS().then(e=>e.pushed&&console.log(`[content-plane] seeded ${e.pushed} ticket links to the plane`),()=>{}),e0().then(e=>e.pushed&&console.log(`[content-plane] seeded ${e.pushed} mocks to the plane`),()=>{}),y0().then(e=>e.pushed&&console.log(`[content-plane] seeded ${e.pushed} flows to the plane`),()=>{}),$b().then(e=>e.pushed&&console.log(`[content-plane] seeded ${e.pushed} PR links to the plane`),()=>{}))});process.on("SIGTERM",()=>{try{Rl?.stop()}catch{}setTimeout(()=>process.exit(0),150)});function bj(){kj(),yc().catch(()=>{}),setInterval(()=>yc().catch(()=>{}),1e4)}function kj(){for(let t of["bostrat-view","bostrat-mock","bostrat-flow","bostrat-ticket","bostrat-circuit","bostrat-blueprint","bostrat-decision","bostrat-runbook","bostrat-loop","bostrat-notify","bostrat-gmail","bostrat-changelog","gh"])try{let e=ut.resolve(rT,"..","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 xj(){let t=!1,e=async()=>{if(!t){t=!0;try{let n=await nt(),r=await PS({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 Sj(){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 Pk(n).catch(()=>{}))}catch{}finally{t=!1}}},4e3)}
542
+ `),e.destroy();return}let{cols:s,rows:a}=r;tL.handleUpgrade(t,e,n,i=>sw(i,o,{cols:s,rows:a}))};OT.on("upgrade",CT);var MT=process.env.BOSTRAT_CERT_DIR||dt.join(process.env.HOME||nh.tmpdir(),".bostrat","certs"),xT=Number(process.env.BOSTRAT_TLS_PORT)||3443,vT=dt.join(MT,"bostrat.globopi.key"),ST=dt.join(MT,"bostrat.globopi.crt");if(Ht.existsSync(vT)&&Ht.existsSync(ST)){let t=Vj.createServer({key:Ht.readFileSync(vT),cert:Ht.readFileSync(ST)},v);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(xT,Dl,()=>{console.log(`[bostrat-agent] https listening on ${Dl||"0.0.0.0"}:${xT}`)})}OT.listen(bT,Dl,()=>{console.log(`[bostrat-agent] listening on ${Dl||"0.0.0.0"}:${bT}`);let t=Fv(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: ${re}`),console.log(`[bostrat-agent] auto-trigger default: ${AT}%`),console.log(`[bostrat-agent] ip allowlist: ${hs.open?"OPEN":process.env.BOSTRAT_ALLOW_IPS||"CLOSED (BOSTRAT_ALLOW_IPS unset)"}`+(rh.active?` \xB7 view front-door: ${process.env.BOSTRAT_VIEW_FRONT_CIDRS} (registered views only)`:"")),Hp().then(e=>e&&console.log("[bostrat-agent] reconciled interrupted handoff(s)")).catch(e=>console.error("[bostrat-agent] handoff reconcile failed:",e?.message||e)),Vp().then(e=>e&&console.log("[bostrat-agent] reconciled interrupted subtask(s)")).catch(e=>console.error("[bostrat-agent] subtask reconcile failed:",e?.message||e)),Lp().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)),Np().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)),oL(),rL(),Zy({listTracks:ot,getTrack:X}).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)),u0()&&d0({listTracks:ot}),US(),qS(),Iv({resolveTrack:X}),jv({listTracks:ot,createTrack:Yc,archiveTrack:Hr,listRepos:qe,resolveTrack:X,sayToLead:we,answerPrompt:Vc,startLeadHandoff:el,interruptLead:Jc,listSubtaskJobs:Wr,cancelSubtask:ol,readEvents:B,appendEvent:I,divertShip:qm,answerPrExists:Km,knownAgents:$a}),eL(),$s().then(e=>{e||console.warn(`[boot] no host tmux server on ${re} and auto-start failed \u2014 boxes cannot spawn until one runs`)}),oT(),process.env.BOSTRAT_PLANE_URL&&process.env.BOSTRAT_PLANE_TOKEN&&(Ll=Wv({url:process.env.BOSTRAT_PLANE_URL,token:process.env.BOSTRAT_PLANE_TOKEN,nodeId:process.env.BOSTRAT_NODE_ID||nh.hostname(),name:process.env.BOSTRAT_NODE_NAME||nh.hostname(),listTracks:ot,detectAgents:Kc,sampleMetrics:Kv,onTracksTransferred:Kp}),console.log(`[bostrat-agent] plane link \u2192 ${process.env.BOSTRAT_PLANE_URL}`),eo().catch(()=>{}),n0().then(e=>e.pushed&&console.log(`[content-plane] seeded ${e.pushed} runbooks to the plane`),()=>{}),Rv().then(e=>e.pushed&&console.log(`[content-plane] seeded ${e.pushed} ticket links to the plane`),()=>{}),Ex().then(e=>e.pushed&&console.log(`[content-plane] seeded ${e.pushed} mocks to the plane`),()=>{}),Wx().then(e=>e.pushed&&console.log(`[content-plane] seeded ${e.pushed} flows to the plane`),()=>{}),Kb().then(e=>e.pushed&&console.log(`[content-plane] seeded ${e.pushed} PR links to the plane`),()=>{}))});process.on("SIGTERM",()=>{try{Ll?.stop()}catch{}setTimeout(()=>process.exit(0),150)});function eL(){nL(),_c().catch(()=>{}),setInterval(()=>_c().catch(()=>{}),1e4)}function nL(){for(let t of["bostrat-view","bostrat-mock","bostrat-flow","bostrat-ticket","bostrat-circuit","bostrat-blueprint","bostrat-decision","bostrat-runbook","bostrat-loop","bostrat-notify","bostrat-gmail","bostrat-changelog","gh"])try{let e=dt.resolve(TT,"..","bin",t),n=dt.join(process.env.HOME||"",".local","bin");if(!process.env.HOME||!Ht.existsSync(e))continue;Ht.mkdirSync(n,{recursive:!0});let r=dt.join(n,t);(Ht.existsSync(r)?Ht.readlinkSync(r):null)!==e&&(Ht.rmSync(r,{force:!0}),Ht.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 rL(){let t=!1,e=async()=>{if(!t){t=!0;try{let n=await ot(),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 oL(){let t=!1;setInterval(async()=>{if(!t){t=!0;try{let e=await ot();for(let n of e)n.archivedAt||n.transferredTo||!n.boxes?.some(r=>r.state==="live")||(await Gc(n.id).catch(()=>{}),await ax(n).catch(()=>{}))}catch{}finally{t=!1}}},4e3)}