bostrat-node 1.7.9 → 1.7.10

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,93 +1,96 @@
1
- var dA=Object.defineProperty;var O=(e,t,n)=>()=>{if(n)throw n[0];try{return e&&(t=e(e=0)),t}catch(r){throw n=[r],r}};var $u=(e,t)=>{for(var n in t)dA(e,n,{get:t[n],enumerable:!0})};import{createHash as fA,randomBytes as pA,timingSafeEqual as mA}from"node:crypto";function ew(){return pA(32).toString("hex")}function js(e){let t=typeof e=="string"?e.trim():"";return t?fA("sha256").update(t).digest("hex"):null}function tw(e,t){return typeof e!="string"||typeof t!="string"||e.length!==t.length||!e?!1:mA(Buffer.from(e),Buffer.from(t))}function Ls(e,t={},{now:n=Date.now(),log:r=console.warn}={}){if(Ou.set(e,(Ou.get(e)||0)+1),Cu.has(e)&&n-Cu.get(e)<hA)return!1;Cu.set(e,n);let o=Object.entries(t).filter(([,s])=>s!=null&&s!=="").map(([s,a])=>`${s}=${a}`).join(" ");return r(`[hook-audit] ${e} n=${Ou.get(e)}${o?` ${o}`:""}`),!0}async function nw(e,{byToken:t,legacy:n,env:r=process.env}={}){let o=typeof e=="string"?e.trim():"";if(!o)return r.BOSTRAT_HOOK_LEGACY_DENY==="1"?{mode:"legacy-denied",target:null}:{mode:"legacy",target:await n()};let s=await t(o);return s?.track?{mode:"token",target:s}:{mode:"refused",target:null}}var Li,Fi,Ou,Cu,hA,Fs=O(()=>{Li="BOSTRAT_HOOK_TOKEN",Fi="x-bostrat-hook";Ou=new Map,Cu=new Map,hA=6e4});import dt from"node:fs/promises";import rw from"node:os";import ot from"node:path";import{execFile as wA}from"node:child_process";import{promisify as gA}from"node:util";function Ui(){return/^(1|true|yes|on)$/i.test(process.env.BOSTRAT_CLAUDE_USE_API_KEY||"")&&process.env.ANTHROPIC_API_KEY?.trim()||null}function yA(){return process.env.CLAUDE_CONFIG_DIR?ot.join(process.env.CLAUDE_CONFIG_DIR,".claude.json"):ot.join(rw.homedir(),".claude.json")}function bA(){return process.env.CLAUDE_CONFIG_DIR?ot.join(process.env.CLAUDE_CONFIG_DIR,"settings.json"):ot.join(rw.homedir(),".claude","settings.json")}async function Ln(e){if(!e||typeof e!="string")return;let t=ot.resolve(e),n=yA(),r=bA(),o={};try{o=JSON.parse(await dt.readFile(n,"utf8"))}catch{}o.hasCompletedOnboarding=!0,o.theme||(o.theme="dark"),o.projects=o.projects||{},o.projects[t]=o.projects[t]||{};let s=o.projects[t];Array.isArray(s.allowedTools)||(s.allowedTools=[]),s.hasTrustDialogAccepted=!0,s.hasCompletedProjectOnboarding=!0;let a=process.env.ANTHROPIC_API_KEY;if(a){let c=a.slice(-20);o.customApiKeyResponses=o.customApiKeyResponses||{},o.customApiKeyResponses.approved=o.customApiKeyResponses.approved||[],o.customApiKeyResponses.rejected=o.customApiKeyResponses.rejected||[],o.customApiKeyResponses.approved.includes(c)||o.customApiKeyResponses.approved.push(c)}await dt.mkdir(ot.dirname(n),{recursive:!0}),await dt.writeFile(n,JSON.stringify(o,null,2));let i={};try{i=JSON.parse(await dt.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 "${Fi}: $${Li}" --data-binary @- >/dev/null 2>&1 || true`,u=[{hooks:[{type:"command",command:l}]}];i.hooks=i.hooks||{};for(let f of["SessionStart","UserPromptSubmit","Stop"])i.hooks[f]=u;i.hooks.PostToolUse=[{matcher:"*",hooks:[{type:"command",command:l}]}]}await dt.mkdir(ot.dirname(r),{recursive:!0}),await dt.writeFile(r,JSON.stringify(i,null,2)),await kA(t)}async function kA(e){try{let t=ot.resolve(e),n=ot.join(t,".bostrat","memory","claude"),r=ot.join(t,".claude","settings.local.json"),o={};try{o=JSON.parse(await dt.readFile(r,"utf8"))}catch{}let s=o.autoMemoryDirectory,a=typeof s=="string"&&s.includes(ot.join(".bostrat","memory"));if(s&&!a||s===n)return;o.autoMemoryDirectory=n,await dt.mkdir(n,{recursive:!0}),await dt.mkdir(ot.dirname(r),{recursive:!0}),await dt.writeFile(r,JSON.stringify(o,null,2)),await xA(t,["/.claude/settings.local.json"])}catch{}}async function xA(e,t){try{let{stdout:n}=await gA(wA)("git",["-C",e,"rev-parse","--git-path","info/exclude"]),r=ot.resolve(e,n.trim()),o=await dt.readFile(r,"utf8").catch(()=>""),s=t.filter(a=>!o.split(`
1
+ var bA=Object.defineProperty;var C=(e,t,n)=>()=>{if(n)throw n[0];try{return e&&(t=e(e=0)),t}catch(r){throw n=[r],r}};var Nu=(e,t)=>{for(var n in t)bA(e,n,{get:t[n],enumerable:!0})};import{createHash as kA,randomBytes as xA,timingSafeEqual as SA}from"node:crypto";function aw(){return xA(32).toString("hex")}function Hs(e){let t=typeof e=="string"?e.trim():"";return t?kA("sha256").update(t).digest("hex"):null}function iw(e,t){return typeof e!="string"||typeof t!="string"||e.length!==t.length||!e?!1:SA(Buffer.from(e),Buffer.from(t))}function Ws(e,t={},{now:n=Date.now(),log:r=console.warn}={}){if(Pu.set(e,(Pu.get(e)||0)+1),Du.has(e)&&n-Du.get(e)<vA)return!1;Du.set(e,n);let o=Object.entries(t).filter(([,s])=>s!=null&&s!=="").map(([s,a])=>`${s}=${a}`).join(" ");return r(`[hook-audit] ${e} n=${Pu.get(e)}${o?` ${o}`:""}`),!0}async function cw(e,{byToken:t,legacy:n,env:r=process.env}={}){let o=typeof e=="string"?e.trim():"";if(!o)return r.BOSTRAT_HOOK_LEGACY_DENY==="1"?{mode:"legacy-denied",target:null}:{mode:"legacy",target:await n()};let s=await t(o);return s?.track?{mode:"token",target:s}:{mode:"refused",target:null}}var Wi,qi,Pu,Du,vA,qs=C(()=>{Wi="BOSTRAT_HOOK_TOKEN",qi="x-bostrat-hook";Pu=new Map,Du=new Map,vA=6e4});import dt from"node:fs/promises";import lw from"node:os";import ot from"node:path";import{execFile as TA}from"node:child_process";import{promisify as EA}from"node:util";function Ki(){return/^(1|true|yes|on)$/i.test(process.env.BOSTRAT_CLAUDE_USE_API_KEY||"")&&process.env.ANTHROPIC_API_KEY?.trim()||null}function AA(){return process.env.CLAUDE_CONFIG_DIR?ot.join(process.env.CLAUDE_CONFIG_DIR,".claude.json"):ot.join(lw.homedir(),".claude.json")}function _A(){return process.env.CLAUDE_CONFIG_DIR?ot.join(process.env.CLAUDE_CONFIG_DIR,"settings.json"):ot.join(lw.homedir(),".claude","settings.json")}async function Fn(e){if(!e||typeof e!="string")return;let t=ot.resolve(e),n=AA(),r=_A(),o={};try{o=JSON.parse(await dt.readFile(n,"utf8"))}catch{}o.hasCompletedOnboarding=!0,o.theme||(o.theme="dark"),o.projects=o.projects||{},o.projects[t]=o.projects[t]||{};let s=o.projects[t];Array.isArray(s.allowedTools)||(s.allowedTools=[]),s.hasTrustDialogAccepted=!0,s.hasCompletedProjectOnboarding=!0;let a=process.env.ANTHROPIC_API_KEY;if(a){let c=a.slice(-20);o.customApiKeyResponses=o.customApiKeyResponses||{},o.customApiKeyResponses.approved=o.customApiKeyResponses.approved||[],o.customApiKeyResponses.rejected=o.customApiKeyResponses.rejected||[],o.customApiKeyResponses.approved.includes(c)||o.customApiKeyResponses.approved.push(c)}await dt.mkdir(ot.dirname(n),{recursive:!0}),await dt.writeFile(n,JSON.stringify(o,null,2));let i={};try{i=JSON.parse(await dt.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 "${qi}: $${Wi}" --data-binary @- >/dev/null 2>&1 || true`,u=[{hooks:[{type:"command",command:l}]}];i.hooks=i.hooks||{};for(let f of["SessionStart","UserPromptSubmit","Stop"])i.hooks[f]=u;i.hooks.PostToolUse=[{matcher:"*",hooks:[{type:"command",command:l}]}]}await dt.mkdir(ot.dirname(r),{recursive:!0}),await dt.writeFile(r,JSON.stringify(i,null,2)),await IA(t)}async function IA(e){try{let t=ot.resolve(e),n=ot.join(t,".bostrat","memory","claude"),r=ot.join(t,".claude","settings.local.json"),o={};try{o=JSON.parse(await dt.readFile(r,"utf8"))}catch{}let s=o.autoMemoryDirectory,a=typeof s=="string"&&s.includes(ot.join(".bostrat","memory"));if(s&&!a||s===n)return;o.autoMemoryDirectory=n,await dt.mkdir(n,{recursive:!0}),await dt.mkdir(ot.dirname(r),{recursive:!0}),await dt.writeFile(r,JSON.stringify(o,null,2)),await RA(t,["/.claude/settings.local.json"])}catch{}}async function RA(e,t){try{let{stdout:n}=await EA(TA)("git",["-C",e,"rev-parse","--git-path","info/exclude"]),r=ot.resolve(e,n.trim()),o=await dt.readFile(r,"utf8").catch(()=>""),s=t.filter(a=>!o.split(`
2
2
  `).includes(a));if(!s.length)return;await dt.mkdir(ot.dirname(r),{recursive:!0}),await dt.appendFile(r,(o&&!o.endsWith(`
3
3
  `)?`
4
4
  `:"")+s.join(`
5
5
  `)+`
6
- `)}catch{}}var Us=O(()=>{Fs()});import Mu from"node:fs/promises";import SA from"node:os";import Hi from"node:path";function vA(){let e=process.env.CODEX_HOME||Hi.join(SA.homedir(),".codex");return Hi.join(e,"config.toml")}function ow(e){return`[projects."${e}"]`}function TA(e,t){let n=ow(t),r=e.indexOf(n);if(r===-1)return!1;let o=e.slice(r+n.length),s=o.search(/^\s*\[/m),a=s===-1?o:o.slice(0,s);return/trust_level\s*=\s*"trusted"/.test(a)}async function go(e){if(!e||typeof e!="string")return;let t=Hi.resolve(e),n=vA(),r="";try{r=await Mu.readFile(n,"utf8")}catch{}if(TA(r,t))return;let o=ow(t);if(r.includes(o)){let a=r.indexOf(o)+o.length,c=r.slice(a).search(/^\s*\[/m),l=c===-1?r.length:a+c,u=r.slice(a,l),f=/trust_level\s*=/.test(u)?u.replace(/trust_level\s*=\s*"[^"]*"/,'trust_level = "trusted"'):`${u.replace(/\s*$/,"")}
6
+ `)}catch{}}var Ks=C(()=>{qs()});import Bu from"node:fs/promises";import $A from"node:os";import Gi from"node:path";function OA(){let e=process.env.CODEX_HOME||Gi.join($A.homedir(),".codex");return Gi.join(e,"config.toml")}function uw(e){return`[projects."${e}"]`}function CA(e,t){let n=uw(t),r=e.indexOf(n);if(r===-1)return!1;let o=e.slice(r+n.length),s=o.search(/^\s*\[/m),a=s===-1?o:o.slice(0,s);return/trust_level\s*=\s*"trusted"/.test(a)}async function go(e){if(!e||typeof e!="string")return;let t=Gi.resolve(e),n=OA(),r="";try{r=await Bu.readFile(n,"utf8")}catch{}if(CA(r,t))return;let o=uw(t);if(r.includes(o)){let a=r.indexOf(o)+o.length,c=r.slice(a).search(/^\s*\[/m),l=c===-1?r.length:a+c,u=r.slice(a,l),f=/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)+f+r.slice(l)}else{let s=`
9
9
  ${o}
10
10
  trust_level = "trusted"
11
11
  `;r=r.trimEnd()+s+(r.length&&!r.endsWith(`
12
12
  `)?`
13
- `:"")}try{await Mu.mkdir(Hi.dirname(n),{recursive:!0}),await Mu.writeFile(n,r)}catch(s){console.warn(`[codex-config] could not seed folder trust for ${t}: ${s?.message||s}`)}}var Wi=O(()=>{});import sw from"node:fs/promises";import EA from"node:os";import Hs from"node:path";function AA(e){let n=Hs.resolve(e).slice(1).replace(/\//g,"-").replace(/\./g,""),r=process.env.CURSOR_CONFIG_DIR||Hs.join(EA.homedir(),".cursor");return Hs.join(r,"projects",n)}async function yo(e){if(!e||typeof e!="string")return;let t=Hs.resolve(e),n=AA(t),r=Hs.join(n,".workspace-trusted");await sw.mkdir(n,{recursive:!0}),await sw.writeFile(r,`${JSON.stringify({trustedAt:new Date().toISOString(),workspacePath:t},null,2)}
14
- `,"utf8")}var qi=O(()=>{});import Pu from"node:fs/promises";import Fn from"node:path";import{execFile as _A}from"node:child_process";import{promisify as IA}from"node:util";async function NA(e){try{return(await Pu.stat(Fn.join(e,".git"))).isDirectory()?"repo":"worktree"}catch{return null}}async function PA(e){let t=i=>Pu.readFile(Fn.join(e,".git",i),"utf8").then(c=>c.trim()).catch(()=>null),r=(await t("refs/remotes/origin/HEAD"))?.match(/^ref:\s*refs\/remotes\/origin\/(.+)/);if(r)return r[1].trim();let o;for(let i of["main","master"])if(await t(`refs/heads/${i}`)||(o??=await t("packed-refs")||"",new RegExp(`^[0-9a-f]{40} refs/heads/${i}$`,"m").test(o)))return i;let a=(await t("HEAD"))?.match(/^ref:\s*refs\/heads\/(.+)/);return a?a[1].trim():null}async function cn(){let e=new Map;async function t(o,s){if(e.has(o))return;let a=await NA(o);if(a==="worktree")return;if(a==="repo"){e.set(o,{path:o,name:Fn.basename(o),branch:await PA(o)});return}if(s>=CA)return;let i;try{i=await Pu.readdir(o,{withFileTypes:!0})}catch{return}for(let c of i)!c.isDirectory()||c.name.startsWith(".")||MA.has(c.name)||await t(Fn.join(o,c.name),s+1)}for(let o of OA)await t(Fn.resolve(o),0);let n=new Set,r=[];for(let o of e.values()){let s=(await me(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 DA(e){let t=String(e||"").trim().match(/github\.com[:/]+([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i);return t?`${t[1]}/${t[2]}`:null}async function me(e){if(!e)return null;if(Nu.has(e))return Nu.get(e);let t=null;try{let{stdout:n}=await RA("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});t=DA(n)}catch{t=null}return Nu.set(e,t),t}async function bo(e){let t=String(e||"").toLowerCase();if(!t)return null;for(let n of await cn())if((await me(n.path))?.toLowerCase()===t)return n.path;return null}var RA,aw,$A,OA,CA,MA,Nu,Un=O(()=>{RA=IA(_A),aw=process.env.HOME||"/home/globo",$A=Fn.join(process.env.BOSTRAT_STATE_DIR||Fn.join(aw,".bostrat"),"repos"),OA=[...(process.env.BOSTRAT_REPOS_ROOT||Fn.join(aw,"Documents")).split(","),$A].map(e=>e.trim()).filter(Boolean),CA=Number(process.env.BOSTRAT_REPOS_DEPTH)||3,MA=new Set(["node_modules",".git",".cache","dist","build",".next","vendor","__pycache__","venv",".venv","target"]);Nu=new Map});import BA from"node:fs";import iw from"node:fs/promises";import Ws from"node:path";import jA from"node:os";import{fileURLToPath as LA}from"node:url";import{execFile as FA}from"node:child_process";import{promisify as UA}from"node:util";function ke(e=process.env){let t=e.BOSTRAT_PLANE_URL||"";if(!t)return null;try{let n=new URL(t);return n.protocol=n.protocol==="ws:"?"http:":"https:",n.origin}catch{return null}}function Ki(e=process.env){return!!(ke(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Gi(e,{env:t=process.env}={}){let n=String(e||"").toLowerCase();if(!lw.test(n))throw ko("repo must be owner/name",400);let r=Du.get(n);if(r&&r.expiresAt-Date.now()>qA)return r;if(!Ki(t))throw ko("node is not plane-linked \u2014 GitHub auth unavailable",503);let o;try{o=await uw(`${ke(t)}/v1/github/token?repo=${encodeURIComponent(e)}`,{headers:dw(t)})}catch(i){if(r&&r.expiresAt>Date.now())return r;throw ko(`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 ko(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 Du.set(n,a),a}async function qs({env:e=process.env,force:t=!1}={}){if(!Ki(e))return{configured:!1,repos:[],username:null};if(!t&&$r&&Date.now()-$r.at<KA)return $r.data;try{let n=await uw(`${ke(e)}/v1/github/repos`,{headers:dw(e)});if(!n.ok)throw new Error(`plane replied ${n.status}`);let r=await n.json();return $r={at:Date.now(),data:r},r}catch(n){return $r?$r.data:{configured:!0,repos:[],username:null,error:n?.message||String(n)}}}function fw(){Du.clear(),$r=null}async function qt({cwd:e=null,slug:t=null,env:n=process.env}={}){try{let r=t||(e?await me(e):null);if(!r)return{};let{token:o}=await Gi(r,{env:n});return o?{GH_TOKEN:o}:{}}catch{return{}}}async function Bu({env:e=process.env}={}){return(await qs({env:e})).username??null}function JA(e){let[t,n]=String(e).split("/");return Ws.join(WA,t,n)}async function ju(e,{env:t=process.env}={}){let n=(...r)=>cw("git",["-C",e,...r],{timeout:1e4});await n("config","--replace-all","credential.helper",""),await n("config","--add","credential.helper",`!"${VA()}" ${zA(t)}`),await n("config","credential.useHttpPath","true")}async function Vi(e,{env:t=process.env,baseUrl:n="https://github.com"}={}){if(!lw.test(String(e||"")))throw ko(`bad repo slug "${e}"`,400);let r=JA(e);if(BA.existsSync(Ws.join(r,".git")))return r;let{token:o}=await Gi(e,{env:t});await iw.mkdir(Ws.dirname(r),{recursive:!0});let s="!f() { echo username=x-access-token; echo password=$BOSTRAT_GIT_TOKEN; }; f";try{await cw("git",["-c","credential.helper=","-c",`credential.helper=${s}`,"clone","--no-tags","-q",`${n}/${e}.git`,r],{timeout:GA,env:{...t,BOSTRAT_GIT_TOKEN:o,GIT_TERMINAL_PROMPT:"0"}})}catch(a){throw await iw.rm(r,{recursive:!0,force:!0}).catch(()=>{}),ko(`clone of ${e} failed: ${a?.stderr?.trim?.()||a?.message||a}`,502)}return await ju(r,{env:t}),r}var cw,HA,WA,lw,qA,KA,GA,uw,Du,$r,dw,ko,VA,zA,Qe=O(()=>{Un();cw=UA(FA),HA=process.env.BOSTRAT_STATE_DIR||Ws.join(process.env.HOME||jA.tmpdir(),".bostrat"),WA=Ws.join(HA,"repos"),lw=/^[^/\s]+\/[^/\s]+$/,qA=5*6e4,KA=6e4,GA=10*6e4,uw=fetch,Du=new Map,$r=null;dw=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),ko=(e,t)=>Object.assign(new Error(e),{status:t});VA=()=>LA(new URL("../bin/bostrat-git-credential",import.meta.url)),zA=(e=process.env)=>`http://127.0.0.1:${Number(e.PORT)||3362}`});function mw(e=process.env){return!!(ke(e)&&e.BOSTRAT_PLANE_TOKEN)}async function ww(e,t,n,r=pw){let o=ke(n),s=new AbortController,a=setTimeout(()=>s.abort(),r);try{return await XA(`${o}${e}`,{...t,signal:s.signal})}finally{clearTimeout(a)}}async function gw(e,{env:t=process.env,force:n=!1,timeoutMs:r=pw}={}){if(!mw(t))return{facts:[],source:"unconfigured"};let o=Lu.get(e);if(!n&&o&&Date.now()-o.at<YA)return{facts:o.facts,source:"cache"};try{let s=await ww(`/v1/memory/${encodeURIComponent(e)}`,{headers:hw(t)},t,r);if(!s.ok)throw new Error(`plane ${s.status}`);let a=await s.json(),i=Array.isArray(a?.facts)?a.facts:[];return Lu.set(e,{at:Date.now(),facts:i}),{facts:i,source:"plane"}}catch(s){return o?{facts:o.facts,source:"stale",error:s?.message}:{facts:[],source:"unreachable",error:s?.message}}}async function zi(e,t,{env:n=process.env}={}){if(!mw(n))return{pushed:0,source:"unconfigured"};if(!t?.length)return{pushed:0,source:"empty"};try{let r=await ww(`/v1/memory/${encodeURIComponent(e)}`,{method:"POST",headers:{...hw(n),"content-type":"application/json"},body:JSON.stringify({facts:t})},n);if(!r.ok)throw new Error(`plane ${r.status}`);let o=await r.json(),s=Array.isArray(o?.results)?o.results:[];return Lu.delete(e),{pushed:s.filter(a=>a.outcome==="accepted").length,rejected:s.filter(a=>a.outcome==="rejected"),source:"plane"}}catch(r){return{pushed:0,source:"unreachable",error:r?.message}}}var YA,pw,Lu,XA,hw,yw=O(()=>{Qe();YA=6e4,pw=5e3,Lu=new Map,XA=(...e)=>fetch(...e);hw=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});import Fu from"node:fs/promises";import xo from"node:path";import ZA from"node:os";import{EventEmitter as QA}from"node:events";import{randomUUID as e_}from"node:crypto";function So(e){return e?.cwd?xo.join(e.cwd,".bostrat","events"):xo.join(Uu,"events")}async function o_(e,t){if(!Ji.has(t)){let o=(await L(e,t)).reduce((s,a)=>a.seq>s?a.seq:s,0);Ji.set(t,o)}let n=Ji.get(t)+1;return Ji.set(t,n),n}function s_(e,t){let n=Array.isArray(e?.epochs)?e.epochs:null;if(!(!n||n.length===0)){if(!Number.isFinite(t))return n.length-1;for(let r=n.length-1;r>=0;r--){let o=n[r].startedAt;if(o==null||o<=t)return r}return 0}}async function _(e,t){let n=typeof e=="string"?e:e?.id;if(!n)throw new Error("appendEvent: a track (or trackId) is required");if(!t||!t_.has(t.type))throw new Error(`appendEvent: unknown event type "${t?.type}"`);if(t.actor&&!n_.has(t.actor))throw new Error(`appendEvent: bad actor "${t.actor}"`);if(t.source&&!r_.has(t.source))throw new Error(`appendEvent: bad source "${t.source}"`);let r=typeof e=="string"?xo.join(Uu,"events"):So(e),o=t.epoch;if(o==null&&typeof e=="object"&&t.boxId&&Array.isArray(e?.boxes)){let c=e.boxes.find(l=>l.name===t.boxId);o=s_(c,Number(t.payload?.ts??t.ts)||Date.now())}let s=await o_(r,n),a=t.userId??process.env.BOSTRAT_OWNER??null,i={id:t.id||e_(),trackId:n,boxId:t.boxId??null,...o!=null?{epoch:o}:{},...a?{userId:a}:{},seq:s,ts:t.ts??Date.now(),type:t.type,actor:t.actor??"system",provider:t.provider??null,source:t.source??"orchestrator",payload:t.payload??{},...t.causationId?{causationId:t.causationId}:{},...t.correlationId?{correlationId:t.correlationId}:{}};return await Fu.mkdir(r,{recursive:!0}),await Fu.appendFile(bw(r,n),JSON.stringify(i)+`
15
- `),st.emit("event",i),st.emit(`track:${n}`,i),i}async function L(e,t){let n,r;typeof e=="string"&&t?(n=e,r=t):(r=typeof e=="string"?e:e?.id,n=typeof e=="string"?xo.join(Uu,"events"):So(e));let o;try{o=await Fu.readFile(bw(n,r),"utf8")}catch{return[]}let s=[];for(let a of o.split(`
16
- `))if(a.trim())try{s.push(JSON.parse(a))}catch{}return s}function kw(e,t){let n=`track:${e}`;return st.on(n,t),()=>st.off(n,t)}var t_,n_,r_,st,Uu,bw,Ji,ue=O(()=>{t_=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","memory.harvested","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"]),n_=new Set(["user","agent","orchestrator","system","peer"]),r_=new Set(["hook","otel","statusline","transcript","pane","orchestrator","vendor"]),st=new QA;st.setMaxListeners(0);Uu=process.env.BOSTRAT_STATE_DIR||xo.join(process.env.HOME||ZA.tmpdir(),".bostrat");bw=(e,t)=>xo.join(e,`${t}.ndjson`),Ji=new Map});import K from"node:fs/promises";import a_ from"node:os";import oe from"node:path";import{execFile as i_}from"node:child_process";import{promisify as c_}from"node:util";function Xi(){return oe.join(Zi,"memory","repos")}function Or(e){return e===ln?oe.join(Zi,"memory",ln):oe.join(Xi(),e)}async function Gs(e){try{return JSON.parse(await K.readFile(oe.join(e,_w),"utf8"))}catch{return{}}}async function Wu(e,t){let n=await Gs(e);for(let[r,o]of t)n[r]=Math.max(Number(n[r])||0,o);await K.mkdir(e,{recursive:!0}),await K.writeFile(oe.join(e,_w),JSON.stringify(n))}function Sw(e){let t=String(e||"").trim();if(!t)return null;let r=(t.replace(/\/+$/,"").split(/[/:]/).pop()||"").replace(/\.git$/i,"").toLowerCase();return/^[a-z0-9][a-z0-9._-]*$/.test(r)?r:null}async function vw(e){try{let{stdout:t}=await l_("git",["-C",e,"config","--get","remote.origin.url"]);return t.trim()||null}catch{return null}}async function qu(e){if(!e)return[];let t=Sw(await vw(e));if(t)return[t];let n=[],r=[];try{r=await K.readdir(e,{withFileTypes:!0})}catch{return[]}for(let o of r){if(!o.isDirectory()||o.name.startsWith("."))continue;let s=Sw(await vw(oe.join(e,o.name)));s&&!n.includes(s)&&n.push(s)}return n}function Qi(e){let t=/^---\n([\s\S]*?)\n---\n?/.exec(e);return t?{fm:t[1],body:e.slice(t[0].length)}:{fm:null,body:e}}function Hn(e,t){let n=new RegExp(`^\\s*${t}:\\s*(.+?)\\s*$`,"m").exec(e||"");return n?n[1].replace(/^"|"$/g,""):null}async function Kt(e,t=null){let n=t??await K.readFile(e,"utf8").catch(()=>""),{fm:r}=Qi(n),o=Hn(r,"modified"),s=o?Date.parse(o):NaN;if(Number.isFinite(s))return s;try{return(await K.stat(e)).mtimeMs}catch{return 0}}function Iw(e,t){let n=Hn(e,"scope"),r=/^repo:([a-z0-9][a-z0-9._-]*)$/i.exec(n||"");if(r)return r[1].toLowerCase();if((n||"").toLowerCase()===ln){let o=Hn(e,"trust");if(!o||/^operator/i.test(o))return ln}return t}function Ku(e,t,n,r=new Map){let o=(e||"").split(`
13
+ `:"")}try{await Bu.mkdir(Gi.dirname(n),{recursive:!0}),await Bu.writeFile(n,r)}catch(s){console.warn(`[codex-config] could not seed folder trust for ${t}: ${s?.message||s}`)}}var Vi=C(()=>{});import dw from"node:fs/promises";import MA from"node:os";import Gs from"node:path";function NA(e){let n=Gs.resolve(e).slice(1).replace(/\//g,"-").replace(/\./g,""),r=process.env.CURSOR_CONFIG_DIR||Gs.join(MA.homedir(),".cursor");return Gs.join(r,"projects",n)}async function yo(e){if(!e||typeof e!="string")return;let t=Gs.resolve(e),n=NA(t),r=Gs.join(n,".workspace-trusted");await dw.mkdir(n,{recursive:!0}),await dw.writeFile(r,`${JSON.stringify({trustedAt:new Date().toISOString(),workspacePath:t},null,2)}
14
+ `,"utf8")}var zi=C(()=>{});import Lu from"node:fs/promises";import Un from"node:path";import{execFile as PA}from"node:child_process";import{promisify as DA}from"node:util";async function HA(e){try{return(await Lu.stat(Un.join(e,".git"))).isDirectory()?"repo":"worktree"}catch{return null}}async function WA(e){let t=i=>Lu.readFile(Un.join(e,".git",i),"utf8").then(c=>c.trim()).catch(()=>null),r=(await t("refs/remotes/origin/HEAD"))?.match(/^ref:\s*refs\/remotes\/origin\/(.+)/);if(r)return r[1].trim();let o;for(let i of["main","master"])if(await t(`refs/heads/${i}`)||(o??=await t("packed-refs")||"",new RegExp(`^[0-9a-f]{40} refs/heads/${i}$`,"m").test(o)))return i;let a=(await t("HEAD"))?.match(/^ref:\s*refs\/heads\/(.+)/);return a?a[1].trim():null}async function un(){let e=new Map;async function t(o,s){if(e.has(o))return;let a=await HA(o);if(a==="worktree")return;if(a==="repo"){e.set(o,{path:o,name:Un.basename(o),branch:await WA(o)});return}if(s>=FA)return;let i;try{i=await Lu.readdir(o,{withFileTypes:!0})}catch{return}for(let c of i)!c.isDirectory()||c.name.startsWith(".")||UA.has(c.name)||await t(Un.join(o,c.name),s+1)}for(let o of LA)await t(Un.resolve(o),0);let n=new Set,r=[];for(let o of e.values()){let s=(await me(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 qA(e){let t=String(e||"").trim().match(/github\.com[:/]+([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i);return t?`${t[1]}/${t[2]}`:null}async function me(e){if(!e)return null;if(ju.has(e))return ju.get(e);let t=null;try{let{stdout:n}=await BA("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});t=qA(n)}catch{t=null}return ju.set(e,t),t}async function bo(e){let t=String(e||"").toLowerCase();if(!t)return null;for(let n of await un())if((await me(n.path))?.toLowerCase()===t)return n.path;return null}var BA,fw,jA,LA,FA,UA,ju,Hn=C(()=>{BA=DA(PA),fw=process.env.HOME||"/home/globo",jA=Un.join(process.env.BOSTRAT_STATE_DIR||Un.join(fw,".bostrat"),"repos"),LA=[...(process.env.BOSTRAT_REPOS_ROOT||Un.join(fw,"Documents")).split(","),jA].map(e=>e.trim()).filter(Boolean),FA=Number(process.env.BOSTRAT_REPOS_DEPTH)||3,UA=new Set(["node_modules",".git",".cache","dist","build",".next","vendor","__pycache__","venv",".venv","target"]);ju=new Map});import KA from"node:fs";import pw from"node:fs/promises";import Vs from"node:path";import GA from"node:os";import{fileURLToPath as VA}from"node:url";import{execFile as zA}from"node:child_process";import{promisify as JA}from"node:util";function ke(e=process.env){let t=e.BOSTRAT_PLANE_URL||"";if(!t)return null;try{let n=new URL(t);return n.protocol=n.protocol==="ws:"?"http:":"https:",n.origin}catch{return null}}function Ji(e=process.env){return!!(ke(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Xi(e,{env:t=process.env}={}){let n=String(e||"").toLowerCase();if(!hw.test(n))throw ko("repo must be owner/name",400);let r=Fu.get(n);if(r&&r.expiresAt-Date.now()>ZA)return r;if(!Ji(t))throw ko("node is not plane-linked \u2014 GitHub auth unavailable",503);let o;try{o=await ww(`${ke(t)}/v1/github/token?repo=${encodeURIComponent(e)}`,{headers:gw(t)})}catch(i){if(r&&r.expiresAt>Date.now())return r;throw ko(`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 ko(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 Fu.set(n,a),a}async function zs({env:e=process.env,force:t=!1}={}){if(!Ji(e))return{configured:!1,repos:[],username:null};if(!t&&Rr&&Date.now()-Rr.at<QA)return Rr.data;try{let n=await ww(`${ke(e)}/v1/github/repos`,{headers:gw(e)});if(!n.ok)throw new Error(`plane replied ${n.status}`);let r=await n.json();return Rr={at:Date.now(),data:r},r}catch(n){return Rr?Rr.data:{configured:!0,repos:[],username:null,error:n?.message||String(n)}}}function yw(){Fu.clear(),Rr=null}async function qt({cwd:e=null,slug:t=null,env:n=process.env}={}){try{let r=t||(e?await me(e):null);if(!r)return{};let{token:o}=await Xi(r,{env:n});return o?{GH_TOKEN:o}:{}}catch{return{}}}async function Uu({env:e=process.env}={}){return(await zs({env:e})).username??null}function r_(e){let[t,n]=String(e).split("/");return Vs.join(YA,t,n)}async function Hu(e,{env:t=process.env}={}){let n=(...r)=>mw("git",["-C",e,...r],{timeout:1e4});await n("config","--replace-all","credential.helper",""),await n("config","--add","credential.helper",`!"${t_()}" ${n_(t)}`),await n("config","credential.useHttpPath","true")}async function Yi(e,{env:t=process.env,baseUrl:n="https://github.com"}={}){if(!hw.test(String(e||"")))throw ko(`bad repo slug "${e}"`,400);let r=r_(e);if(KA.existsSync(Vs.join(r,".git")))return r;let{token:o}=await Xi(e,{env:t});await pw.mkdir(Vs.dirname(r),{recursive:!0});let s="!f() { echo username=x-access-token; echo password=$BOSTRAT_GIT_TOKEN; }; f";try{await mw("git",["-c","credential.helper=","-c",`credential.helper=${s}`,"clone","--no-tags","-q",`${n}/${e}.git`,r],{timeout:e_,env:{...t,BOSTRAT_GIT_TOKEN:o,GIT_TERMINAL_PROMPT:"0"}})}catch(a){throw await pw.rm(r,{recursive:!0,force:!0}).catch(()=>{}),ko(`clone of ${e} failed: ${a?.stderr?.trim?.()||a?.message||a}`,502)}return await Hu(r,{env:t}),r}var mw,XA,YA,hw,ZA,QA,e_,ww,Fu,Rr,gw,ko,t_,n_,et=C(()=>{Hn();mw=JA(zA),XA=process.env.BOSTRAT_STATE_DIR||Vs.join(process.env.HOME||GA.tmpdir(),".bostrat"),YA=Vs.join(XA,"repos"),hw=/^[^/\s]+\/[^/\s]+$/,ZA=5*6e4,QA=6e4,e_=10*6e4,ww=fetch,Fu=new Map,Rr=null;gw=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),ko=(e,t)=>Object.assign(new Error(e),{status:t});t_=()=>VA(new URL("../bin/bostrat-git-credential",import.meta.url)),n_=(e=process.env)=>`http://127.0.0.1:${Number(e.PORT)||3362}`});function kw(e=process.env){return!!(ke(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Sw(e,t,n,r=bw){let o=ke(n),s=new AbortController,a=setTimeout(()=>s.abort(),r);try{return await s_(`${o}${e}`,{...t,signal:s.signal})}finally{clearTimeout(a)}}async function vw(e,{env:t=process.env,force:n=!1,timeoutMs:r=bw}={}){if(!kw(t))return{facts:[],source:"unconfigured"};let o=Wu.get(e);if(!n&&o&&Date.now()-o.at<o_)return{facts:o.facts,source:"cache"};try{let s=await Sw(`/v1/memory/${encodeURIComponent(e)}`,{headers:xw(t)},t,r);if(!s.ok)throw new Error(`plane ${s.status}`);let a=await s.json(),i=Array.isArray(a?.facts)?a.facts:[];return Wu.set(e,{at:Date.now(),facts:i}),{facts:i,source:"plane"}}catch(s){return o?{facts:o.facts,source:"stale",error:s?.message}:{facts:[],source:"unreachable",error:s?.message}}}async function Zi(e,t,{env:n=process.env}={}){if(!kw(n))return{pushed:0,source:"unconfigured"};if(!t?.length)return{pushed:0,source:"empty"};try{let r=await Sw(`/v1/memory/${encodeURIComponent(e)}`,{method:"POST",headers:{...xw(n),"content-type":"application/json"},body:JSON.stringify({facts:t})},n);if(!r.ok)throw new Error(`plane ${r.status}`);let o=await r.json(),s=Array.isArray(o?.results)?o.results:[];return Wu.delete(e),{pushed:s.filter(a=>a.outcome==="accepted").length,rejected:s.filter(a=>a.outcome==="rejected"),source:"plane"}}catch(r){return{pushed:0,source:"unreachable",error:r?.message}}}var o_,bw,Wu,s_,xw,Tw=C(()=>{et();o_=6e4,bw=5e3,Wu=new Map,s_=(...e)=>fetch(...e);xw=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});import qu from"node:fs/promises";import xo from"node:path";import a_ from"node:os";import{EventEmitter as i_}from"node:events";import{randomUUID as c_}from"node:crypto";function So(e){return e?.cwd?xo.join(e.cwd,".bostrat","events"):xo.join(Ku,"events")}async function f_(e,t){if(!Qi.has(t)){let o=(await L(e,t)).reduce((s,a)=>a.seq>s?a.seq:s,0);Qi.set(t,o)}let n=Qi.get(t)+1;return Qi.set(t,n),n}function p_(e,t){let n=Array.isArray(e?.epochs)?e.epochs:null;if(!(!n||n.length===0)){if(!Number.isFinite(t))return n.length-1;for(let r=n.length-1;r>=0;r--){let o=n[r].startedAt;if(o==null||o<=t)return r}return 0}}async function _(e,t){let n=typeof e=="string"?e:e?.id;if(!n)throw new Error("appendEvent: a track (or trackId) is required");if(!t||!l_.has(t.type))throw new Error(`appendEvent: unknown event type "${t?.type}"`);if(t.actor&&!u_.has(t.actor))throw new Error(`appendEvent: bad actor "${t.actor}"`);if(t.source&&!d_.has(t.source))throw new Error(`appendEvent: bad source "${t.source}"`);let r=typeof e=="string"?xo.join(Ku,"events"):So(e),o=t.epoch;if(o==null&&typeof e=="object"&&t.boxId&&Array.isArray(e?.boxes)){let c=e.boxes.find(l=>l.name===t.boxId);o=p_(c,Number(t.payload?.ts??t.ts)||Date.now())}let s=await f_(r,n),a=t.userId??process.env.BOSTRAT_OWNER??null,i={id:t.id||c_(),trackId:n,boxId:t.boxId??null,...o!=null?{epoch:o}:{},...a?{userId:a}:{},seq:s,ts:t.ts??Date.now(),type:t.type,actor:t.actor??"system",provider:t.provider??null,source:t.source??"orchestrator",payload:t.payload??{},...t.causationId?{causationId:t.causationId}:{},...t.correlationId?{correlationId:t.correlationId}:{}};return await qu.mkdir(r,{recursive:!0}),await qu.appendFile(Ew(r,n),JSON.stringify(i)+`
15
+ `),st.emit("event",i),st.emit(`track:${n}`,i),i}async function L(e,t){let n,r;typeof e=="string"&&t?(n=e,r=t):(r=typeof e=="string"?e:e?.id,n=typeof e=="string"?xo.join(Ku,"events"):So(e));let o;try{o=await qu.readFile(Ew(n,r),"utf8")}catch{return[]}let s=[];for(let a of o.split(`
16
+ `))if(a.trim())try{s.push(JSON.parse(a))}catch{}return s}function Aw(e,t){let n=`track:${e}`;return st.on(n,t),()=>st.off(n,t)}var l_,u_,d_,st,Ku,Ew,Qi,ue=C(()=>{l_=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","memory.harvested","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"]),u_=new Set(["user","agent","orchestrator","system","peer"]),d_=new Set(["hook","otel","statusline","transcript","pane","orchestrator","vendor"]),st=new i_;st.setMaxListeners(0);Ku=process.env.BOSTRAT_STATE_DIR||xo.join(process.env.HOME||a_.tmpdir(),".bostrat");Ew=(e,t)=>xo.join(e,`${t}.ndjson`),Qi=new Map});import K from"node:fs/promises";import m_ from"node:os";import oe from"node:path";import{execFile as h_}from"node:child_process";import{promisify as w_}from"node:util";function tc(){return oe.join(nc,"memory","repos")}function $r(e){return e===dn?oe.join(nc,"memory",dn):oe.join(tc(),e)}async function Xs(e){try{return JSON.parse(await K.readFile(oe.join(e,Mw),"utf8"))}catch{return{}}}async function Vu(e,t){let n=await Xs(e);for(let[r,o]of t)n[r]=Math.max(Number(n[r])||0,o);await K.mkdir(e,{recursive:!0}),await K.writeFile(oe.join(e,Mw),JSON.stringify(n))}function Iw(e){let t=String(e||"").trim();if(!t)return null;let r=(t.replace(/\/+$/,"").split(/[/:]/).pop()||"").replace(/\.git$/i,"").toLowerCase();return/^[a-z0-9][a-z0-9._-]*$/.test(r)?r:null}async function Rw(e){try{let{stdout:t}=await g_("git",["-C",e,"config","--get","remote.origin.url"]);return t.trim()||null}catch{return null}}async function zu(e){if(!e)return[];let t=Iw(await Rw(e));if(t)return[t];let n=[],r=[];try{r=await K.readdir(e,{withFileTypes:!0})}catch{return[]}for(let o of r){if(!o.isDirectory()||o.name.startsWith("."))continue;let s=Iw(await Rw(oe.join(e,o.name)));s&&!n.includes(s)&&n.push(s)}return n}function rc(e){let t=/^---\n([\s\S]*?)\n---\n?/.exec(e);return t?{fm:t[1],body:e.slice(t[0].length)}:{fm:null,body:e}}function Wn(e,t){let n=new RegExp(`^\\s*${t}:\\s*(.+?)\\s*$`,"m").exec(e||"");return n?n[1].replace(/^"|"$/g,""):null}async function Kt(e,t=null){let n=t??await K.readFile(e,"utf8").catch(()=>""),{fm:r}=rc(n),o=Wn(r,"modified"),s=o?Date.parse(o):NaN;if(Number.isFinite(s))return s;try{return(await K.stat(e)).mtimeMs}catch{return 0}}function Nw(e,t){let n=Wn(e,"scope"),r=/^repo:([a-z0-9][a-z0-9._-]*)$/i.exec(n||"");if(r)return r[1].toLowerCase();if((n||"").toLowerCase()===dn){let o=Wn(e,"trust");if(!o||/^operator/i.test(o))return dn}return t}function Ju(e,t,n,r=new Map){let o=(e||"").split(`
17
17
  `),s=new Map;for(let c of(t||"").split(`
18
18
  `)){let l=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(`
19
19
  `).replace(/\n{3,}/g,`
20
20
 
21
- `)}function Rw(e,t){let n=Hn(t,"name")||e.replace(/\.md$/,""),r=Hn(t,"description")||"";return`- [${n}](${e})${r?` \u2014 ${r}`:""}`}async function Vs(e){let t=[];try{t=await K.readdir(e,{withFileTypes:!0})}catch{return[]}return t.filter(n=>n.isFile()&&n.name.endsWith(".md")&&n.name!=="MEMORY.md").map(n=>n.name)}async function $w(e,t){let n=oe.join(e,".bostrat","memory"),r=await Vs(n);if(!r.length)return{harvested:0,changedByKey:new Map};let o=Tw.get(e)??0,s=Date.now(),a=new Map,i=new Map,c=0,l=new Map;for(let f of r){let d=oe.join(n,f);if(o)try{if((await K.stat(d)).mtimeMs<o-d_)continue}catch{continue}let p;try{p=await K.readFile(d,"utf8")}catch{continue}let{fm:m}=Qi(p),h=Iw(m,t);if(!h)continue;let g=Or(h),x=oe.join(g,f),k=await Kt(d,p);if(l.has(g)||l.set(g,await Gs(g)),(l.get(g)[f]||0)>=k)continue;let E=await Kt(x).catch(()=>0);if(await K.access(x).then(()=>!0).catch(()=>!1)&&E>=k)continue;await K.mkdir(g,{recursive:!0}),await K.writeFile(x,p),c++;let M=a.get(g);M||a.set(g,M={won:new Set,generated:new Map}),M.won.add(f),M.generated.set(f,Rw(f,m)),i.has(h)||i.set(h,new Set),i.get(h).add(f)}let u=await K.readFile(oe.join(n,"MEMORY.md"),"utf8").catch(()=>"");for(let[f,d]of a){let p=oe.join(f,"MEMORY.md"),m=await K.readFile(p,"utf8").catch(()=>"");await K.writeFile(p,Ku(m,u,d.won,d.generated))}return Tw.set(e,s),{harvested:c,changedByKey:i}}async function Ow(e){let t=0,n=new Map;for(let r of e||[]){if(!r||!await K.access(oe.join(r,".bostrat","memory")).then(()=>!0).catch(()=>!1))continue;let[s]=await qu(r),a=await $w(r,s||null);t+=a.harvested;for(let[i,c]of a.changedByKey){n.has(i)||n.set(i,new Set);for(let l of c)n.get(i).add(l)}}return{harvested:t,changedByKey:n}}async function f_(){let e=oe.join(Zi,"workspaces"),t=[];try{t=await K.readdir(e,{withFileTypes:!0})}catch{return{harvested:0,changedByKey:new Map}}return Ow(t.filter(n=>n.isDirectory()).map(n=>oe.join(e,n.name)))}async function h_(e,t){let n=Or(e),r=await Gs(n),o=new Set,s=new Map,a=[],i=0;for(let c of t||[]){let l=String(c?.file||"");if(!p_.test(l)||l==="MEMORY.md")continue;let u=oe.join(n,l),f=await K.access(u).then(()=>!0).catch(()=>!1),d=f?await Kt(u):0,p=Number(c.modified)||0;if(c.deleted){p>d&&(f&&await K.rm(u,{force:!0}),await Wu(n,[[l,p]]),f&&(a.push(l),i++));continue}f&&d>=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=oe.join(n,"MEMORY.md"),l=await K.readFile(c,"utf8").catch(()=>""),u=Ku(l,[...s.values()].join(`
21
+ `)}function Pw(e,t){let n=Wn(t,"name")||e.replace(/\.md$/,""),r=Wn(t,"description")||"";return`- [${n}](${e})${r?` \u2014 ${r}`:""}`}async function Ys(e){let t=[];try{t=await K.readdir(e,{withFileTypes:!0})}catch{return[]}return t.filter(n=>n.isFile()&&n.name.endsWith(".md")&&n.name!=="MEMORY.md").map(n=>n.name)}async function Dw(e,t){let n=oe.join(e,".bostrat","memory"),r=await Ys(n);if(!r.length)return{harvested:0,changedByKey:new Map};let o=$w.get(e)??0,s=Date.now(),a=new Map,i=new Map,c=0,l=new Map;for(let f of r){let d=oe.join(n,f);if(o)try{if((await K.stat(d)).mtimeMs<o-b_)continue}catch{continue}let p;try{p=await K.readFile(d,"utf8")}catch{continue}let{fm:m}=rc(p),h=Nw(m,t);if(!h)continue;let g=$r(h),x=oe.join(g,f),k=await Kt(d,p);if(l.has(g)||l.set(g,await Xs(g)),(l.get(g)[f]||0)>=k)continue;let E=await Kt(x).catch(()=>0);if(await K.access(x).then(()=>!0).catch(()=>!1)&&E>=k)continue;await K.mkdir(g,{recursive:!0}),await K.writeFile(x,p),c++;let M=a.get(g);M||a.set(g,M={won:new Set,generated:new Map}),M.won.add(f),M.generated.set(f,Pw(f,m)),i.has(h)||i.set(h,new Set),i.get(h).add(f)}let u=await K.readFile(oe.join(n,"MEMORY.md"),"utf8").catch(()=>"");for(let[f,d]of a){let p=oe.join(f,"MEMORY.md"),m=await K.readFile(p,"utf8").catch(()=>"");await K.writeFile(p,Ju(m,u,d.won,d.generated))}return $w.set(e,s),{harvested:c,changedByKey:i}}async function Bw(e){let t=0,n=new Map;for(let r of e||[]){if(!r||!await K.access(oe.join(r,".bostrat","memory")).then(()=>!0).catch(()=>!1))continue;let[s]=await zu(r),a=await Dw(r,s||null);t+=a.harvested;for(let[i,c]of a.changedByKey){n.has(i)||n.set(i,new Set);for(let l of c)n.get(i).add(l)}}return{harvested:t,changedByKey:n}}async function k_(){let e=oe.join(nc,"workspaces"),t=[];try{t=await K.readdir(e,{withFileTypes:!0})}catch{return{harvested:0,changedByKey:new Map}}return Bw(t.filter(n=>n.isDirectory()).map(n=>oe.join(e,n.name)))}async function v_(e,t){let n=$r(e),r=await Xs(n),o=new Set,s=new Map,a=[],i=0;for(let c of t||[]){let l=String(c?.file||"");if(!x_.test(l)||l==="MEMORY.md")continue;let u=oe.join(n,l),f=await K.access(u).then(()=>!0).catch(()=>!1),d=f?await Kt(u):0,p=Number(c.modified)||0;if(c.deleted){p>d&&(f&&await K.rm(u,{force:!0}),await Vu(n,[[l,p]]),f&&(a.push(l),i++));continue}f&&d>=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=oe.join(n,"MEMORY.md"),l=await K.readFile(c,"utf8").catch(()=>""),u=Ju(l,[...s.values()].join(`
22
22
  `),o);if(a.length){let f=new Set(a);u=u.split(`
23
23
  `).filter(d=>!f.has(To(d))).join(`
24
- `)}await K.mkdir(n,{recursive:!0}),await K.writeFile(c,u)}return{changed:i,tombstoned:a.length}}async function ec(e,t=null){let n=Or(e),r=t?.length?t:await Vs(n);if(!r.length)return{pushed:0,source:"empty"};let o=m_(await K.readFile(oe.join(n,"MEMORY.md"),"utf8").catch(()=>"")),s=[];for(let a of r){let i=oe.join(n,a),c;try{c=await K.readFile(i,"utf8")}catch{continue}s.push({file:a,content:c,modified:await Kt(i,c),indexLine:o.get(a)??null})}return zi(e,s)}async function w_(e,{timeoutMs:t}={}){let{facts:n,source:r}=await gw(e,t?{timeoutMs:t}:{});n.length?await h_(e,n):r==="plane"&&await ec(e)}function g_(e){let t=e.split(`
25
- `);t.length>xw&&(t=t.slice(0,xw));let n=t.join(`
26
- `);for(;Buffer.byteLength(n,"utf8")>u_&&t.length;)t.pop(),n=t.join(`
27
- `);return n}async function b_(e,t){if(!e||!t?.length)return{materialized:!1,reason:"no-repo-key"};let n=oe.join(e,".bostrat","memory"),r=0,o=0,s=[];for(let u of t){let f=Or(u),d=await Gs(f);for(let[g,x]of Object.entries(d)){let k=oe.join(n,g);await K.access(k).then(()=>!0).catch(()=>!1)&&await Kt(k)<=x&&(await K.rm(k,{force:!0}),o++)}let p=await Vs(f);if(!p.length)continue;await K.mkdir(n,{recursive:!0});for(let g of p){let x=oe.join(f,g),k=oe.join(n,g),E=await Kt(x),I=await Kt(k).catch(()=>0);await K.access(k).then(()=>!0).catch(()=>!1)&&I>=E||(await K.copyFile(x,k),r++)}let m=await K.readFile(oe.join(f,"MEMORY.md"),"utf8").catch(()=>""),h=u===ln?"## operator memory":`## repo: ${u}`;m.trim()&&s.push(t.length>1?`${h}
24
+ `)}await K.mkdir(n,{recursive:!0}),await K.writeFile(c,u)}return{changed:i,tombstoned:a.length}}async function oc(e,t=null){let n=$r(e),r=t?.length?t:await Ys(n);if(!r.length)return{pushed:0,source:"empty"};let o=S_(await K.readFile(oe.join(n,"MEMORY.md"),"utf8").catch(()=>"")),s=[];for(let a of r){let i=oe.join(n,a),c;try{c=await K.readFile(i,"utf8")}catch{continue}s.push({file:a,content:c,modified:await Kt(i,c),indexLine:o.get(a)??null})}return Zi(e,s)}async function T_(e,{timeoutMs:t}={}){let{facts:n,source:r}=await vw(e,t?{timeoutMs:t}:{});n.length?await v_(e,n):r==="plane"&&await oc(e)}function E_(e){let t=e.split(`
25
+ `);t.length>_w&&(t=t.slice(0,_w));let n=t.join(`
26
+ `);for(;Buffer.byteLength(n,"utf8")>y_&&t.length;)t.pop(),n=t.join(`
27
+ `);return n}async function __(e,t){if(!e||!t?.length)return{materialized:!1,reason:"no-repo-key"};let n=oe.join(e,".bostrat","memory"),r=0,o=0,s=[];for(let u of t){let f=$r(u),d=await Xs(f);for(let[g,x]of Object.entries(d)){let k=oe.join(n,g);await K.access(k).then(()=>!0).catch(()=>!1)&&await Kt(k)<=x&&(await K.rm(k,{force:!0}),o++)}let p=await Ys(f);if(!p.length)continue;await K.mkdir(n,{recursive:!0});for(let g of p){let x=oe.join(f,g),k=oe.join(n,g),E=await Kt(x),I=await Kt(k).catch(()=>0);await K.access(k).then(()=>!0).catch(()=>!1)&&I>=E||(await K.copyFile(x,k),r++)}let m=await K.readFile(oe.join(f,"MEMORY.md"),"utf8").catch(()=>""),h=u===dn?"## operator memory":`## repo: ${u}`;m.trim()&&s.push(t.length>1?`${h}
28
28
 
29
29
  ${m.trim()}`:m.trim())}if(!s.length)return o?{materialized:!1,reason:"empty-store",cleaned:o}:{materialized:!1,reason:"empty-store"};let i="_Shared Track memory (point-in-time facts). Verify file/line citations against the current code before acting on them; correct a wrong fact in place (bump `modified`, use `supersedes`) rather than working around it._\n\n"+s.join(`
30
30
 
31
31
  `)+`
32
- `,c=g_(i);await K.mkdir(n,{recursive:!0}),await K.writeFile(oe.join(n,"MEMORY.md"),c);let l=oe.join(n,"claude");return await K.mkdir(l,{recursive:!0}),await K.writeFile(oe.join(l,"MEMORY.md"),y_,{flag:"wx"}).catch(()=>{}),{materialized:!0,facts:r,capped:c!==i}}async function Cw(e){try{let t=await qu(e);if(!t.length)return{materialized:!1,reason:"no-repo-key"};let n=[...t,ln];return await Promise.all(n.map(r=>w_(r,{timeoutMs:k_}))),await b_(e,n)}catch(t){return{materialized:!1,reason:"error",error:t?.message||String(t)}}}function Mw(){return{...De,pending:vo.size,queued:Hu.size}}function Nw(e){if(Yi.has(e))return Yi.get(e);Hu.add(e);let t=Ew.then(async()=>{Hu.delete(e),Yi.delete(e);let n=await Vu(e);return De.runs++,De.lastRunAt=Date.now(),n.error?(De.errors++,De.lastError=n.error):De.harvested+=n.harvested||0,n}).catch(n=>({harvested:0,error:n?.message||String(n)}));return Yi.set(e,t),Ew=t.then(()=>{}),t}function tc(e,{delayMs:t=x_}={}){if(!e||typeof e!="string")return;De.scheduled++;let n=vo.get(e);n&&clearTimeout(n);let r=setTimeout(()=>{vo.delete(e),Nw(e)},t);r.unref?.(),vo.set(e,r)}async function Gu(e,{timeoutMs:t=3e3}={}){if(!e)return{harvested:0,skipped:"no-cwd"};if(!await K.access(oe.join(e,".bostrat","memory")).then(()=>!0,()=>!1))return{harvested:0,skipped:"no-memory-dir"};let r=vo.get(e);r&&(clearTimeout(r),vo.delete(e));let o,s=new Promise(a=>{o=setTimeout(()=>a({harvested:0,timedOut:!0}),t),o.unref?.()});try{return await Promise.race([Nw(e),s])}finally{clearTimeout(o)}}async function Pw(e){return Ks||(Ks=(async()=>{try{Aw||(Aw=!0,await v_());let{harvested:t,changedByKey:n}=await Ow(e);for(let[r,o]of n)await ec(r,[...o]);return De.reconciles++,De.lastReconcileAt=Date.now(),De.harvested+=t,{harvested:t,keys:[...n.keys()]}}catch(t){return De.errors++,De.lastError=t?.message||String(t),{harvested:0,error:De.lastError}}finally{Ks=null}})(),Ks)}function S_(){return oe.join(Zi,"memory",".full-sweep-done")}async function Dw(){let e=S_();try{let t=JSON.parse(await K.readFile(e,"utf8"));return De.backfill={at:Number(t?.at)||0,harvested:Number(t?.harvested)||0,prior:!0},{ran:!1,...De.backfill}}catch{}try{let{harvested:t,changedByKey:n}=await f_();for(let[o,s]of n)await ec(o,[...s]);let r={at:Date.now(),harvested:t};return await K.mkdir(oe.dirname(e),{recursive:!0}),await K.writeFile(e,JSON.stringify(r)),De.backfill=r,{ran:!0,...r}}catch(t){return De.errors++,De.lastError=t?.message||String(t),{ran:!1,error:De.lastError}}}async function v_(){let e=0,t=[];try{t=await K.readdir(Xi(),{withFileTypes:!0})}catch{return{moved:e}}for(let n of t){if(!n.isDirectory())continue;let r=oe.join(Xi(),n.name),o=Or(ln),s=new Set,a=new Map;for(let p of await Vs(r)){let m=oe.join(r,p),h;try{h=await K.readFile(m,"utf8")}catch{continue}let{fm:g}=Qi(h);if(Iw(g,n.name)!==ln)continue;let x=oe.join(o,p),k=await Kt(x).catch(()=>0),E=await Kt(m,h);await K.mkdir(o,{recursive:!0}),E>k&&await K.writeFile(x,h),await K.rm(m,{force:!0}),s.add(p),a.set(p,Rw(p,g)),e++}if(!s.size)continue;let i=Date.now();await Wu(r,[...s].map(p=>[p,i])),await zi(n.name,[...s].map(p=>({file:p,deleted:!0,modified:i})));let c=oe.join(r,"MEMORY.md"),l=await K.readFile(c,"utf8").catch(()=>""),u=l.split(`
32
+ `,c=E_(i);await K.mkdir(n,{recursive:!0}),await K.writeFile(oe.join(n,"MEMORY.md"),c);let l=oe.join(n,"claude");return await K.mkdir(l,{recursive:!0}),await K.writeFile(oe.join(l,"MEMORY.md"),A_,{flag:"wx"}).catch(()=>{}),{materialized:!0,facts:r,capped:c!==i}}async function jw(e){try{let t=await zu(e);if(!t.length)return{materialized:!1,reason:"no-repo-key"};let n=[...t,dn];return await Promise.all(n.map(r=>T_(r,{timeoutMs:I_}))),await __(e,n)}catch(t){return{materialized:!1,reason:"error",error:t?.message||String(t)}}}function Lw(){return{...Be,pending:vo.size,queued:Gu.size}}function Fw(e){if(ec.has(e))return ec.get(e);Gu.add(e);let t=Ow.then(async()=>{Gu.delete(e),ec.delete(e);let n=await Yu(e);return Be.runs++,Be.lastRunAt=Date.now(),n.error?(Be.errors++,Be.lastError=n.error):Be.harvested+=n.harvested||0,n}).catch(n=>({harvested:0,error:n?.message||String(n)}));return ec.set(e,t),Ow=t.then(()=>{}),t}function sc(e,{delayMs:t=R_}={}){if(!e||typeof e!="string")return;Be.scheduled++;let n=vo.get(e);n&&clearTimeout(n);let r=setTimeout(()=>{vo.delete(e),Fw(e)},t);r.unref?.(),vo.set(e,r)}async function Xu(e,{timeoutMs:t=3e3}={}){if(!e)return{harvested:0,skipped:"no-cwd"};if(!await K.access(oe.join(e,".bostrat","memory")).then(()=>!0,()=>!1))return{harvested:0,skipped:"no-memory-dir"};let r=vo.get(e);r&&(clearTimeout(r),vo.delete(e));let o,s=new Promise(a=>{o=setTimeout(()=>a({harvested:0,timedOut:!0}),t),o.unref?.()});try{return await Promise.race([Fw(e),s])}finally{clearTimeout(o)}}async function Uw(e){return Js||(Js=(async()=>{try{Cw||(Cw=!0,await O_());let{harvested:t,changedByKey:n}=await Bw(e);for(let[r,o]of n)await oc(r,[...o]);return Be.reconciles++,Be.lastReconcileAt=Date.now(),Be.harvested+=t,{harvested:t,keys:[...n.keys()]}}catch(t){return Be.errors++,Be.lastError=t?.message||String(t),{harvested:0,error:Be.lastError}}finally{Js=null}})(),Js)}function $_(){return oe.join(nc,"memory",".full-sweep-done")}async function Hw(){let e=$_();try{let t=JSON.parse(await K.readFile(e,"utf8"));return Be.backfill={at:Number(t?.at)||0,harvested:Number(t?.harvested)||0,prior:!0},{ran:!1,...Be.backfill}}catch{}try{let{harvested:t,changedByKey:n}=await k_();for(let[o,s]of n)await oc(o,[...s]);let r={at:Date.now(),harvested:t};return await K.mkdir(oe.dirname(e),{recursive:!0}),await K.writeFile(e,JSON.stringify(r)),Be.backfill=r,{ran:!0,...r}}catch(t){return Be.errors++,Be.lastError=t?.message||String(t),{ran:!1,error:Be.lastError}}}async function O_(){let e=0,t=[];try{t=await K.readdir(tc(),{withFileTypes:!0})}catch{return{moved:e}}for(let n of t){if(!n.isDirectory())continue;let r=oe.join(tc(),n.name),o=$r(dn),s=new Set,a=new Map;for(let p of await Ys(r)){let m=oe.join(r,p),h;try{h=await K.readFile(m,"utf8")}catch{continue}let{fm:g}=rc(h);if(Nw(g,n.name)!==dn)continue;let x=oe.join(o,p),k=await Kt(x).catch(()=>0),E=await Kt(m,h);await K.mkdir(o,{recursive:!0}),E>k&&await K.writeFile(x,h),await K.rm(m,{force:!0}),s.add(p),a.set(p,Pw(p,g)),e++}if(!s.size)continue;let i=Date.now();await Vu(r,[...s].map(p=>[p,i])),await Zi(n.name,[...s].map(p=>({file:p,deleted:!0,modified:i})));let c=oe.join(r,"MEMORY.md"),l=await K.readFile(c,"utf8").catch(()=>""),u=l.split(`
33
33
  `).filter(p=>!s.has(To(p))).join(`
34
- `);await K.writeFile(c,u).catch(()=>{});let f=oe.join(o,"MEMORY.md"),d=await K.readFile(f,"utf8").catch(()=>"");await K.writeFile(f,Ku(d,l,s,a))}return{moved:e}}async function Bw(){let e=[],t=[ln];try{for(let n of await K.readdir(Xi(),{withFileTypes:!0}))n.isDirectory()&&t.push(n.name)}catch{}for(let n of t){let r=Or(n),o=await Vs(r),s=await Gs(r);if(!o.length&&!Object.keys(s).length)continue;let a=[];for(let i of o){let c=await K.readFile(oe.join(r,i),"utf8").catch(()=>""),{fm:l}=Qi(c);a.push({file:i,name:Hn(l,"name")||i.replace(/\.md$/,""),description:Hn(l,"description")||"",scope:Hn(l,"scope")||null,modified:await Kt(oe.join(r,i),c)})}e.push({key:n,facts:a,tombstones:Object.keys(s).length})}return e}async function jw(e,t){if(!/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/.test(t)||t==="MEMORY.md")throw new Error("bad fact filename");let n=Or(e),r=oe.join(n,t);if(!await K.access(r).then(()=>!0).catch(()=>!1))throw new Error(`fact ${t} not found in ${e}`);let s=Date.now();await K.rm(r,{force:!0}),await Wu(n,[[t,s]]);let a=oe.join(n,"MEMORY.md"),i=await K.readFile(a,"utf8").catch(()=>"");await K.writeFile(a,i.split(`
34
+ `);await K.writeFile(c,u).catch(()=>{});let f=oe.join(o,"MEMORY.md"),d=await K.readFile(f,"utf8").catch(()=>"");await K.writeFile(f,Ju(d,l,s,a))}return{moved:e}}async function Ww(){let e=[],t=[dn];try{for(let n of await K.readdir(tc(),{withFileTypes:!0}))n.isDirectory()&&t.push(n.name)}catch{}for(let n of t){let r=$r(n),o=await Ys(r),s=await Xs(r);if(!o.length&&!Object.keys(s).length)continue;let a=[];for(let i of o){let c=await K.readFile(oe.join(r,i),"utf8").catch(()=>""),{fm:l}=rc(c);a.push({file:i,name:Wn(l,"name")||i.replace(/\.md$/,""),description:Wn(l,"description")||"",scope:Wn(l,"scope")||null,modified:await Kt(oe.join(r,i),c)})}e.push({key:n,facts:a,tombstones:Object.keys(s).length})}return e}async function qw(e,t){if(!/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/.test(t)||t==="MEMORY.md")throw new Error("bad fact filename");let n=$r(e),r=oe.join(n,t);if(!await K.access(r).then(()=>!0).catch(()=>!1))throw new Error(`fact ${t} not found in ${e}`);let s=Date.now();await K.rm(r,{force:!0}),await Vu(n,[[t,s]]);let a=oe.join(n,"MEMORY.md"),i=await K.readFile(a,"utf8").catch(()=>"");await K.writeFile(a,i.split(`
35
35
  `).filter(l=>To(l)!==t).join(`
36
- `)).catch(()=>{});let c=await zi(e,[{file:t,deleted:!0,modified:s}]);return{deleted:t,key:e,plane:c.source}}async function Vu(e){try{let t=await qu(e),{harvested:n,changedByKey:r}=await $w(e,t[0]||null);for(let[o,s]of r)await ec(o,[...s]);return n>0&&await E_(e,r).catch(()=>{}),{harvested:n}}catch(t){return{harvested:0,error:t?.message||String(t)}}}async function E_(e,t){let n=/workspaces[/\\]([0-9a-f]{8})$/.exec(e||"")?.[1];if(!n)return;let r={},o=0;for(let[s,a]of t){let i=[...a].sort();o+=i.length,r[s]={count:i.length,files:i.slice(0,T_)}}await _({id:n,cwd:e},{type:"memory.harvested",actor:"orchestrator",payload:{harvested:o,keys:r,ts:Date.now()}})}var l_,Zi,xw,u_,ln,_w,To,Tw,d_,p_,m_,y_,k_,x_,vo,Hu,Ew,De,Yi,Aw,Ks,T_,zs=O(()=>{yw();ue();l_=c_(i_),Zi=process.env.BOSTRAT_STATE_DIR||oe.join(process.env.HOME||a_.tmpdir(),".bostrat"),xw=200,u_=25*1024;ln="operator";_w=".tombstones.json";To=e=>/\]\(([^)]+\.md)\)/.exec(e)?.[1]||null;Tw=new Map,d_=2e3;p_=/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/,m_=e=>{let t=new Map;for(let n of(e||"").split(`
37
- `)){let r=To(n);r&&n.trim().startsWith("-")&&t.set(r,n)}return t};y_=`# Track memory
36
+ `)).catch(()=>{});let c=await Zi(e,[{file:t,deleted:!0,modified:s}]);return{deleted:t,key:e,plane:c.source}}async function Yu(e){try{let t=await zu(e),{harvested:n,changedByKey:r}=await Dw(e,t[0]||null);for(let[o,s]of r)await oc(o,[...s]);return n>0&&await M_(e,r).catch(()=>{}),{harvested:n}}catch(t){return{harvested:0,error:t?.message||String(t)}}}async function M_(e,t){let n=/workspaces[/\\]([0-9a-f]{8})$/.exec(e||"")?.[1];if(!n)return;let r={},o=0;for(let[s,a]of t){let i=[...a].sort();o+=i.length,r[s]={count:i.length,files:i.slice(0,C_)}}await _({id:n,cwd:e},{type:"memory.harvested",actor:"orchestrator",payload:{harvested:o,keys:r,ts:Date.now()}})}var g_,nc,_w,y_,dn,Mw,To,$w,b_,x_,S_,A_,I_,R_,vo,Gu,Ow,Be,ec,Cw,Js,C_,Zs=C(()=>{Tw();ue();g_=w_(h_),nc=process.env.BOSTRAT_STATE_DIR||oe.join(process.env.HOME||m_.tmpdir(),".bostrat"),_w=200,y_=25*1024;dn="operator";Mw=".tombstones.json";To=e=>/\]\(([^)]+\.md)\)/.exec(e)?.[1]||null;$w=new Map,b_=2e3;x_=/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/,S_=e=>{let t=new Map;for(let n of(e||"").split(`
37
+ `)){let r=To(n);r&&n.trim().startsWith("-")&&t.set(r,n)}return t};A_=`# Track memory
38
38
 
39
39
  Shared Track memory (all providers) lives one level up: read \`../MEMORY.md\` for the
40
40
  index and the fact files beside it. Facts you save here stay Claude-local but ride the
41
41
  same sync; prefer adding durable cross-provider facts to \`../\` following its format.
42
- `;k_=Number(process.env.BOSTRAT_MEMORY_SPAWN_PULL_MS)||1500;x_=Number(process.env.BOSTRAT_MEMORY_HARVEST_DEBOUNCE_MS)||2e3,vo=new Map,Hu=new Set,Ew=Promise.resolve(),De={scheduled:0,runs:0,harvested:0,errors:0,lastRunAt:null,lastError:null,reconciles:0,lastReconcileAt:null,backfill:null};Yi=new Map;Aw=!1,Ks=null;T_=20});import zu from"node:fs/promises";import A_ from"node:path";async function at(e,t,{mode:n}={}){await zu.mkdir(A_.dirname(e),{recursive:!0});let r=`${e}.${process.pid}.${++__}.tmp`;await zu.writeFile(r,JSON.stringify(t,null,2)+`
43
- `,n!=null?{mode:n}:void 0),await zu.rename(r,e)}var __,Wn=O(()=>{__=0});import Ww from"node:fs/promises";import qw from"node:os";import Kw from"node:path";function Ee(e=process.env){return!!(ke(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Xs(e,t={},n=process.env){let r=new AbortController,o=setTimeout(()=>r.abort(),I_);try{return await N_(`${ke(n)}${e}`,{...t,signal:r.signal})}finally{clearTimeout(o)}}async function Vw(){return rc||(Ju||=Ww.readFile(Gw(),"utf8").then(e=>JSON.parse(e)).catch(()=>({ops:[]})).then(e=>rc={ops:Array.isArray(e?.ops)?e.ops:[],parked:Array.isArray(e?.parked)?e.parked:[]}).finally(()=>Ju=null),Ju)}async function oc(){await at(Gw(),rc).catch(()=>{})}function Uw(e){return e.op==="blob"?`blob ${e.family} ${e.id} ${e.v} ${e.kind}`:`${e.op} ${e.family} ${e.id}`}async function Xu(e){let t=await Vw(),n=Uw(e);if(e.op==="delete")t.ops=t.ops.filter(r=>!(r.family===e.family&&r.id===e.id)),t.ops.push(e);else{t.ops=t.ops.filter(o=>!(o.op==="delete"&&o.family===e.family&&o.id===e.id));let r=t.ops.findIndex(o=>Uw(o)===n);r>=0?t.ops[r]=e:t.ops.push(e)}t.ops.length>Lw&&(t.ops=t.ops.slice(-Lw)),await oc()}function Hw(){nc||(nc=setTimeout(()=>{nc=null,Eo().catch(()=>{})},P_),nc.unref?.())}function Yu(e){let t=new Error(`plane ${e}`);return t.refused=!0,t}async function B_(e,t=process.env){if(e.op==="record"){let n=await Xs(`/v1/content/${encodeURIComponent(e.family)}`,{method:"POST",headers:{...Ys(t),"content-type":"application/json"},body:JSON.stringify({records:[{id:e.id,trackId:e.trackId??null,data:e.data,updatedAt:e.updatedAt,originNode:M_()}]})},t);if(!n.ok)throw Yu(n.status);let o=(await n.json().catch(()=>null))?.results?.[0];return o?.outcome==="rejected"?{delivered:!1,rejected:o.reason}:{delivered:!0}}if(e.op==="blob"){let n=await Ww.readFile(e.path).catch(()=>null);if(!n)return{delivered:!0,dropped:"source file gone"};let r=await Xs(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}/blob?v=${e.v}&kind=${encodeURIComponent(e.kind)}`,{method:"POST",headers:{...Ys(t),"content-type":"application/octet-stream"},body:n},t);if(!r.ok&&r.status!==400)throw Yu(r.status);return r.status===400?{delivered:!1,rejected:(await r.json().catch(()=>null))?.error||"rejected"}:{delivered:!0}}if(e.op==="delete"){let n=await Xs(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}?deletedAt=${e.deletedAt}`,{method:"DELETE",headers:Ys(t)},t);if(!n.ok)throw Yu(n.status);return{delivered:!0}}return{delivered:!0,dropped:"unknown op"}}async function Eo({env:e=process.env,log:t=console,now:n=Date.now()}={}){return Ee(e)?Js||(Js=(async()=>{let r=await Vw();j_(r,n);let o=0,s=0;for(;r.ops.length;){let a=r.ops[0],i;try{i=await B_(a,e)}catch(c){if(!c?.refused)return Hw(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};if(a.refusals=(a.refusals||0)+1,a.refusals<$_)return Hw(),await oc(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};t.error?.(`[content-plane] ALARM parking ${a.op} ${a.family}/${a.id} after ${a.refusals} refusals (${c.message}) \u2014 draining the ${r.ops.length-1} ops behind it`),r.ops.shift(),r.parked.push({...a,parkedAt:n,error:c.message}),r.parked.length>Fw&&(r.parked=r.parked.slice(-Fw)),s++,await oc();continue}i.rejected&&t.error?.(`[content-plane] ALARM plane rejected ${a.op} ${a.family}/${a.id}: ${i.rejected}`),r.ops.shift(),o++,await oc()}return{flushed:o,parked:s,pending:0}})().finally(()=>{Js=null}),Js):{flushed:0,source:"unconfigured"}}function j_(e,t){if(!e.parked.length||e.ops.length)return;let n=e.parked.filter(r=>t-(r.parkedAt||0)>=D_);if(n.length){e.parked=e.parked.filter(r=>!n.includes(r));for(let r of n)e.ops.push({...r,refusals:0,parkedAt:void 0,error:void 0})}}async function et(e,t,{trackId:n=null,env:r=process.env}={}){return Ee(r)?(await Xu({op:"record",family:e,id:t.id,trackId:n??t.trackId??null,data:t,updatedAt:Number(t.updatedAt)||Date.now()}),Eo({env:r})):{queued:!1,source:"unconfigured"}}async function qn(e,t,n,r,o,{env:s=process.env}={}){return Ee(s)?(await Xu({op:"blob",family:e,id:t,v:Number(n),kind:r,path:o}),Eo({env:s})):{queued:!1,source:"unconfigured"}}async function $t(e,t,{deletedAt:n=Date.now(),env:r=process.env}={}){return Ee(r)?(await Xu({op:"delete",family:e,id:t,deletedAt:n}),Eo({env:r})):{queued:!1,source:"unconfigured"}}async function je(e,{env:t=process.env}={}){if(!Ee(t))return{records:[],source:"unconfigured"};try{let n=await Xs(`/v1/content/${encodeURIComponent(e)}?tombstones=1`,{headers:Ys(t)},t);if(!n.ok)throw new Error(`plane ${n.status}`);let r=await n.json();return{records:Array.isArray(r?.records)?r.records:[],source:"plane"}}catch(n){return{records:[],source:"unreachable",error:n?.message}}}async function Zs(e,t,n,r,{env:o=process.env}={}){if(!Ee(o))return null;try{let s=await Xs(`/v1/content/${encodeURIComponent(e)}/${encodeURIComponent(t)}/blob?v=${Number(n)}&kind=${encodeURIComponent(r)}`,{headers:Ys(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 I_,R_,Lw,$_,Fw,O_,C_,Gw,M_,N_,P_,D_,Ys,rc,Ju,nc,Js,Kn=O(()=>{Qe();Wn();I_=1e4,R_=3e4,Lw=2e3,$_=5,Fw=100,O_=60*6e4,C_=()=>process.env.BOSTRAT_STATE_DIR||Kw.join(process.env.HOME||qw.tmpdir(),".bostrat"),Gw=()=>Kw.join(C_(),"content-outbox.json"),M_=()=>process.env.BOSTRAT_NODE_ID||qw.hostname(),N_=(...e)=>fetch(...e),P_=R_,D_=O_;Ys=(e=process.env)=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`});rc=null,Ju=null,nc=null,Js=null});import Zu from"node:fs/promises";import zw from"node:path";async function Jw(e,t,{box:n=null,agent:r=null}={}){if(!e||!Ee())return{pushed:!1};try{let o=Date.now();return await et("checkpoints",{id:e,trackId:e,v:o,box:n,agent:r,updatedAt:o},{trackId:e}),await qn("checkpoints",e,o,"md",t),Qs=null,{pushed:!0,v:o}}catch{return{pushed:!1}}}async function W_(){if(Qs&&Date.now()-Qs.at<H_)return{records:Qs.records,source:"plane"};let e=await je("checkpoints");return e.source==="plane"&&(Qs={at:Date.now(),records:e.records}),e}async function sc(e){try{let t=U_(e);if(!t||!Ee())return{restored:!1};let n=zw.join(e,L_,F_);if(await Zu.stat(n).then(()=>!0,()=>!1))return{restored:!1};let{records:r,source:o}=await W_();if(o!=="plane")return{restored:!1};let s=r.find(i=>!i.deletedAt&&i.data?.id===t);if(!s?.data?.v)return{restored:!1};let a=await Zs("checkpoints",t,s.data.v,"md");return typeof a!="string"||!a?{restored:!1}:(await Zu.mkdir(zw.dirname(n),{recursive:!0}),await Zu.writeFile(n,a),{restored:!0,v:s.data.v})}catch{return{restored:!1}}}var L_,F_,U_,H_,Qs,ac=O(()=>{Kn();L_=".bostrat/handoff",F_="latest.md",U_=e=>/workspaces[/\\]([0-9a-f]{8})$/.exec(e||"")?.[1]??null;H_=6e4,Qs=null});import ea from"node:fs/promises";import q_ from"node:os";import Xw from"node:path";function Cr(e){let t=String(e??"");for(let n of K_)t=t.replace(n,"\u2039redacted\u203A");return t}function ic(){let e=process.env.BOSTRAT_HANDOFF_DEBUG;return e==="1"||e==="true"}async function G_(e){try{await ea.mkdir(Qu,{recursive:!0}),await ea.appendFile(Ao,`${JSON.stringify(e)}
44
- `,"utf8");let n=(await ea.readFile(Ao,"utf8")).split(`
45
- `).filter(Boolean);n.length>Yw&&await ea.writeFile(Ao,`${n.slice(-Yw).join(`
42
+ `;I_=Number(process.env.BOSTRAT_MEMORY_SPAWN_PULL_MS)||1500;R_=Number(process.env.BOSTRAT_MEMORY_HARVEST_DEBOUNCE_MS)||2e3,vo=new Map,Gu=new Set,Ow=Promise.resolve(),Be={scheduled:0,runs:0,harvested:0,errors:0,lastRunAt:null,lastError:null,reconciles:0,lastReconcileAt:null,backfill:null};ec=new Map;Cw=!1,Js=null;C_=20});import Zu from"node:fs/promises";import N_ from"node:path";async function at(e,t,{mode:n}={}){await Zu.mkdir(N_.dirname(e),{recursive:!0});let r=`${e}.${process.pid}.${++P_}.tmp`;await Zu.writeFile(r,JSON.stringify(t,null,2)+`
43
+ `,n!=null?{mode:n}:void 0),await Zu.rename(r,e)}var P_,qn=C(()=>{P_=0});import Jw from"node:fs/promises";import Xw from"node:os";import Yw from"node:path";function Ae(e=process.env){return!!(ke(e)&&e.BOSTRAT_PLANE_TOKEN)}async function ta(e,t={},n=process.env){let r=new AbortController,o=setTimeout(()=>r.abort(),D_);try{return await H_(`${ke(n)}${e}`,{...t,signal:r.signal})}finally{clearTimeout(o)}}async function Qw(){return ic||(Qu||=Jw.readFile(Zw(),"utf8").then(e=>JSON.parse(e)).catch(()=>({ops:[]})).then(e=>ic={ops:Array.isArray(e?.ops)?e.ops:[],parked:Array.isArray(e?.parked)?e.parked:[]}).finally(()=>Qu=null),Qu)}async function cc(){await at(Zw(),ic).catch(()=>{})}function Vw(e){return e.op==="blob"?`blob ${e.family} ${e.id} ${e.v} ${e.kind}`:`${e.op} ${e.family} ${e.id}`}async function td(e){let t=await Qw(),n=Vw(e);if(e.op==="delete")t.ops=t.ops.filter(r=>!(r.family===e.family&&r.id===e.id)),t.ops.push(e);else{t.ops=t.ops.filter(o=>!(o.op==="delete"&&o.family===e.family&&o.id===e.id));let r=t.ops.findIndex(o=>Vw(o)===n);r>=0?t.ops[r]=e:t.ops.push(e)}t.ops.length>Kw&&(t.ops=t.ops.slice(-Kw)),await cc()}function zw(){ac||(ac=setTimeout(()=>{ac=null,Eo().catch(()=>{})},W_),ac.unref?.())}function ed(e){let t=new Error(`plane ${e}`);return t.refused=!0,t}async function K_(e,t=process.env){if(e.op==="record"){let n=await ta(`/v1/content/${encodeURIComponent(e.family)}`,{method:"POST",headers:{...ea(t),"content-type":"application/json"},body:JSON.stringify({records:[{id:e.id,trackId:e.trackId??null,data:e.data,updatedAt:e.updatedAt,originNode:U_()}]})},t);if(!n.ok)throw ed(n.status);let o=(await n.json().catch(()=>null))?.results?.[0];return o?.outcome==="rejected"?{delivered:!1,rejected:o.reason}:{delivered:!0}}if(e.op==="blob"){let n=await Jw.readFile(e.path).catch(()=>null);if(!n)return{delivered:!0,dropped:"source file gone"};let r=await ta(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}/blob?v=${e.v}&kind=${encodeURIComponent(e.kind)}`,{method:"POST",headers:{...ea(t),"content-type":"application/octet-stream"},body:n},t);if(!r.ok&&r.status!==400)throw ed(r.status);return r.status===400?{delivered:!1,rejected:(await r.json().catch(()=>null))?.error||"rejected"}:{delivered:!0}}if(e.op==="delete"){let n=await ta(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}?deletedAt=${e.deletedAt}`,{method:"DELETE",headers:ea(t)},t);if(!n.ok)throw ed(n.status);return{delivered:!0}}return{delivered:!0,dropped:"unknown op"}}async function Eo({env:e=process.env,log:t=console,now:n=Date.now()}={}){return Ae(e)?Qs||(Qs=(async()=>{let r=await Qw();G_(r,n);let o=0,s=0;for(;r.ops.length;){let a=r.ops[0],i;try{i=await K_(a,e)}catch(c){if(!c?.refused)return zw(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};if(a.refusals=(a.refusals||0)+1,a.refusals<j_)return zw(),await cc(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};t.error?.(`[content-plane] ALARM parking ${a.op} ${a.family}/${a.id} after ${a.refusals} refusals (${c.message}) \u2014 draining the ${r.ops.length-1} ops behind it`),r.ops.shift(),r.parked.push({...a,parkedAt:n,error:c.message}),r.parked.length>Gw&&(r.parked=r.parked.slice(-Gw)),s++,await cc();continue}i.rejected&&t.error?.(`[content-plane] ALARM plane rejected ${a.op} ${a.family}/${a.id}: ${i.rejected}`),r.ops.shift(),o++,await cc()}return{flushed:o,parked:s,pending:0}})().finally(()=>{Qs=null}),Qs):{flushed:0,source:"unconfigured"}}function G_(e,t){if(!e.parked.length||e.ops.length)return;let n=e.parked.filter(r=>t-(r.parkedAt||0)>=q_);if(n.length){e.parked=e.parked.filter(r=>!n.includes(r));for(let r of n)e.ops.push({...r,refusals:0,parkedAt:void 0,error:void 0})}}async function tt(e,t,{trackId:n=null,env:r=process.env}={}){return Ae(r)?(await td({op:"record",family:e,id:t.id,trackId:n??t.trackId??null,data:t,updatedAt:Number(t.updatedAt)||Date.now()}),Eo({env:r})):{queued:!1,source:"unconfigured"}}async function Kn(e,t,n,r,o,{env:s=process.env}={}){return Ae(s)?(await td({op:"blob",family:e,id:t,v:Number(n),kind:r,path:o}),Eo({env:s})):{queued:!1,source:"unconfigured"}}async function $t(e,t,{deletedAt:n=Date.now(),env:r=process.env}={}){return Ae(r)?(await td({op:"delete",family:e,id:t,deletedAt:n}),Eo({env:r})):{queued:!1,source:"unconfigured"}}async function Fe(e,{env:t=process.env}={}){if(!Ae(t))return{records:[],source:"unconfigured"};try{let n=await ta(`/v1/content/${encodeURIComponent(e)}?tombstones=1`,{headers:ea(t)},t);if(!n.ok)throw new Error(`plane ${n.status}`);let r=await n.json();return{records:Array.isArray(r?.records)?r.records:[],source:"plane"}}catch(n){return{records:[],source:"unreachable",error:n?.message}}}async function na(e,t,n,r,{env:o=process.env}={}){if(!Ae(o))return null;try{let s=await ta(`/v1/content/${encodeURIComponent(e)}/${encodeURIComponent(t)}/blob?v=${Number(n)}&kind=${encodeURIComponent(r)}`,{headers:ea(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 D_,B_,Kw,j_,Gw,L_,F_,Zw,U_,H_,W_,q_,ea,ic,Qu,ac,Qs,Gn=C(()=>{et();qn();D_=1e4,B_=3e4,Kw=2e3,j_=5,Gw=100,L_=60*6e4,F_=()=>process.env.BOSTRAT_STATE_DIR||Yw.join(process.env.HOME||Xw.tmpdir(),".bostrat"),Zw=()=>Yw.join(F_(),"content-outbox.json"),U_=()=>process.env.BOSTRAT_NODE_ID||Xw.hostname(),H_=(...e)=>fetch(...e),W_=B_,q_=L_;ea=(e=process.env)=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`});ic=null,Qu=null,ac=null,Qs=null});import nd from"node:fs/promises";import eg from"node:path";async function tg(e,t,{box:n=null,agent:r=null}={}){if(!e||!Ae())return{pushed:!1};try{let o=Date.now();return await tt("checkpoints",{id:e,trackId:e,v:o,box:n,agent:r,updatedAt:o},{trackId:e}),await Kn("checkpoints",e,o,"md",t),ra=null,{pushed:!0,v:o}}catch{return{pushed:!1}}}async function Y_(){if(ra&&Date.now()-ra.at<X_)return{records:ra.records,source:"plane"};let e=await Fe("checkpoints");return e.source==="plane"&&(ra={at:Date.now(),records:e.records}),e}async function lc(e){try{let t=J_(e);if(!t||!Ae())return{restored:!1};let n=eg.join(e,V_,z_);if(await nd.stat(n).then(()=>!0,()=>!1))return{restored:!1};let{records:r,source:o}=await Y_();if(o!=="plane")return{restored:!1};let s=r.find(i=>!i.deletedAt&&i.data?.id===t);if(!s?.data?.v)return{restored:!1};let a=await na("checkpoints",t,s.data.v,"md");return typeof a!="string"||!a?{restored:!1}:(await nd.mkdir(eg.dirname(n),{recursive:!0}),await nd.writeFile(n,a),{restored:!0,v:s.data.v})}catch{return{restored:!1}}}var V_,z_,J_,X_,ra,uc=C(()=>{Gn();V_=".bostrat/handoff",z_="latest.md",J_=e=>/workspaces[/\\]([0-9a-f]{8})$/.exec(e||"")?.[1]??null;X_=6e4,ra=null});import oa from"node:fs/promises";import Z_ from"node:os";import rg from"node:path";function Or(e){let t=String(e??"");for(let n of Q_)t=t.replace(n,"\u2039redacted\u203A");return t}function dc(){let e=process.env.BOSTRAT_HANDOFF_DEBUG;return e==="1"||e==="true"}async function eI(e){try{await oa.mkdir(rd,{recursive:!0}),await oa.appendFile(Ao,`${JSON.stringify(e)}
44
+ `,"utf8");let n=(await oa.readFile(Ao,"utf8")).split(`
45
+ `).filter(Boolean);n.length>ng&&await oa.writeFile(Ao,`${n.slice(-ng).join(`
46
46
  `)}
47
- `,"utf8")}catch(t){console.warn(`[handoff-debug] failed to write ${Ao}: ${t?.message||t}`)}}async function Y(e={}){let t={at:new Date().toISOString(),ts:Date.now(),...e},n=[t.flow||"handoff",t.phase||t.step||"?",t.trackId?`track=${t.trackId}`:"",t.sessionName?`box=${t.sessionName}`:"",t.error?`ERR=${t.error}`:""].filter(Boolean).join(" \xB7 ");if(console.log(`[handoff-debug] ${n}`),t.sessionName&&ic())try{t.paneTail=Cr((await Ae(t.sessionName,{lines:35})).slice(-4e3))}catch{t.paneTail=null}(ic()||t.error||/^(checkpoint|spawn|hydrate|commit|done|summarize|clear|resume|ready|send|failed|launch)/.test(String(t.phase||t.step||"")))&&await G_(t)}async function Zw({limit:e=80}={}){try{return(await ea.readFile(Ao,"utf8")).split(`
48
- `).filter(Boolean).slice(-e).map(r=>{try{let o=JSON.parse(r);return typeof o?.paneTail=="string"&&(o.paneTail=Cr(o.paneTail)),o}catch{return{raw:Cr(r)}}})}catch{return[]}}var K_,Qu,Ao,Yw,Qw,un=O(()=>{tt();K_=[/[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];Qu=process.env.BOSTRAT_DEBUG_DIR||Xw.join(q_.homedir(),".bostrat","debug"),Ao=Xw.join(Qu,"handoff.jsonl"),Yw=Number(process.env.BOSTRAT_HANDOFF_DEBUG_MAX)||500;Qw={DEBUG_DIR:Qu,LOG_FILE:Ao}});import{execFile as tg}from"node:child_process";import{promisify as V_}from"node:util";import lc from"node:fs";import{randomUUID as ng}from"node:crypto";function Ro(e){return new Promise(t=>setTimeout(t,e))}function cc(e,t){if(!t)return e;let n=o=>typeof o=="string"?o.split(t).join("<redacted>"):o,r=new Error(n(e?.message)||"command failed");return e?.code!==void 0&&(r.code=e.code),e?.stderr!==void 0&&(r.stderr=n(e.stderr)),r}function rg(e){return`/tmp/tmux-${e}/default`}function z_({explicit:e,legacyExists:t,runtimeDir:n,uid:r}){if(e)return e;let o=rg(r);return t?o:n?`${n}/bostrat/tmux-default`:o}function na(){return process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1"?[]:["-e",`${ta}=1`]}function rd(e,t,n){let r=Mr(e),o=/(^|\s)(--session-id|--resume|--continue|-r|-c)(\s|=|$)/.test(e);if(!r||o)return e;let s=`${e} --session-id ${t}`,a=/(^|\s)(--name|-n)(\s|=)/.test(e);return n&&!a&&_e(n)&&(s+=` --name ${n}`),s}function Mr(e){return/(^|\/|\s)claude(\s|$)/.test(String(e||""))}function Gn(e){return/(^|\/|\s)claude(\s|$)/.test(e)?"claude":/cursor/.test(e)?"cursor":/codex/.test(e)?"codex":/gemini/.test(e)?"gemini":"agent"}function X_(e){let t=String(e||"").trim();return!t||/fake-|\.sh(\s|$)/.test(t)?!1:Mr(t)||/(^|\/|\s)codex(\s|$)/.test(t)||/cursor-agent/.test(t)||/(^|\/|\s)gemini(\s|$)/.test(t)}async function og(e,{loginShell:t=!1,failOpen:n=!1}={}){let r=await sg(e,{loginShell:t});return r===uc?!0:r===_o?!1:n}async function sg(e,{loginShell:t=!1,timeoutMs:n=ed}={}){if(!e)return _o;let r=t?process.env.SHELL||"/bin/sh":"sh",o=t?"-lic":"-c";try{return await we(r,[o,'command -v "$1" >/dev/null 2>&1',"_",e],{timeout:n}),uc}catch(s){return s?.killed||s?.signal?Io:s?.code===1||s?.code===127?_o:Io}}async function dc(e,{retries:t=Z_,sleep:n=Q_,probe:r=sg}={}){let o=String(e||"").trim().split(/\s+/)[0],s=await r(o,{timeoutMs:ed});for(let a=0;s===Io&&a<t.length;a++)await n(t[a]),s=await r(o,{timeoutMs:ed*2});return s}function H(...e){return["-S",ft,...e]}async function Vn(){if(!lc.existsSync(ft))return!1;try{return await we(F,H("list-sessions")),!0}catch(e){let t=e&&e.stderr?String(e.stderr):"";return!/no server running/i.test(t)}}async function ra(){if(await Vn())return!0;try{lc.mkdirSync(ft.replace(/\/[^/]+$/,""),{recursive:!0}),await we(F,H("new-session","-d","-s","keeper","sleep 2147483647"))}catch{}return await Vn()}function _e(e){return typeof e=="string"&&eI.test(e)}async function Ot(){if(!lc.existsSync(ft))return[];try{let e="#{session_name}|#{session_windows}|#{session_attached}|#{session_activity}|#{pane_current_path}|#{@bostrat-session}|#{@bostrat-title}|#{@bostrat-sid}|#{@bostrat-agent}|#{alternate_on}|#{session_created}",{stdout:t}=await we(F,H("list-sessions","-F",e)),n=Date.now();return t.trim().split(`
49
- `).filter(Boolean).map(r=>{let[o,s,a,i,c,l,u,f,d,p,m]=r.split("|"),h=Number(i),g=Number(m);return{name:o,title:u||null,windows:Number(s),attached:Number(a),lastActivityMs:Number.isFinite(h)?n-h*1e3:null,cwd:c||null,isBostrat:l==="1",sessionId:f||null,agent:d||(l==="1"?"claude":null),alternateOn:p==="1",createdMs:Number.isFinite(g)&&g>0?g*1e3:null}}).filter(r=>!Y_.has(r.name)&&!r.name.startsWith("bostrat-view-"))}catch{return[]}}async function se(e){return(await Ot()).find(n=>n.name===e)||null}function rI(e){if(typeof e!="string")return!1;let t=e.trim();return t.length>=1&&t.length<=nI&&tI.test(t)}function fc(e){return e.trim().replace(/\s+/g,"-").toLowerCase().replace(/[^A-Za-z0-9_.-]/g,"").replace(/^-+|-+$/g,"")}async function ag(e){try{let{stdout:t}=await we(F,H("list-sessions","-F","#{session_name}"));return t.split(`
50
- `).map(n=>n.trim()).includes(e)}catch{return!1}}function aI(e){let t=String(e||"").trim().split(/\s+/)[0]||"";if(t.includes("/"))return null;let n=[];for(let o=1;o<=t.length-3;o++)n.push(t.slice(o));if(!n.length)return null;let r=n.map(o=>o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));return new RegExp(`\\b(?:${r.join("|")})`)}async function iI(e,t){let n=Date.now()+oa(),r=aI(t),o=!1,s=0;for(;;){if(await Ro(oI),s+=1,!await ag(e))return;let a=await Ae(e,{lines:15}),i=!o&&sI.test(a)&&!!r?.test(a);if(!i&&s>1&&!await dn(e))return;if(i){o=!0,await Y({flow:"spawn",phase:"launch-retry",sessionName:e,agent:Gn(t),promptHead:t.slice(0,120)}).catch(()=>{}),await we(F,H("send-keys","-t",e,"C-u")),await we(F,H("send-keys","-t",e,"-l",t)),await we(F,H("send-keys","-t",e,"Enter"));continue}if(Date.now()>n){await Y({flow:"spawn",phase:"launch-failed",sessionName:e,agent:Gn(t),retried:o,error:"agent CLI never started after launch was typed"}).catch(()=>{});return}}}async function zn(e,t=J_,n={}){if(!rI(e))throw new Error("displayName must be 1\u201364 chars (letters, digits, space . _ -)");let r=e.trim(),o=fc(r);if(!_e(o))throw new Error("resulting tmux session name is invalid");if(!await ra())throw new Error(`host tmux server not running on ${ft} and auto-start failed \u2014 start one: ${F} -S ${ft} new-session -d -s keeper "sleep 2147483647"`);if(await ag(o))throw new Error(`tmux session "${o}" already exists`);let s=n.agentCmd||td,a=n.agent||Gn(s),i=!!n.resumeSessionId,c=n.resumeSessionId||ng(),l=i?s:rd(s,c,o),u=i?n.pinned===!0:/(^|\s)--session-id(\s|=)/.test(l),f=a==="claude"&&Mr(s),d=n.firstRun===!0;d||(f&&await Ln(t),a==="codex"&&await go(t),a==="cursor"&&await yo(t),await Cw(t),n.freshWorkspace!==!0&&await sc(t));let p=f&&!d?Ui():null,m=ew(),h=["-e",`${Li}=${m}`];p&&h.push("-e",`ANTHROPIC_API_KEY=${p}`),f&&h.push(...na());try{await we(F,H("new-session","-d","-s",o,"-c",t,...h))}catch(g){throw cc(p?cc(g,p):g,m)}return await Nr(o),await we(F,H("set-option","-t",o,"@bostrat-session","1")),await we(F,H("set-option","-t",o,"@bostrat-title",r)),await we(F,H("set-option","-t",o,"@bostrat-sid",c)),await we(F,H("set-option","-t",o,"@bostrat-agent",a)),await we(F,H("send-keys","-t",o,l,"Enter")),X_(l)&&iI(o,l).catch(()=>{}),{name:o,title:r,cwd:t,sessionId:c,agent:a,pinned:u,hookToken:m}}async function Ct(e){if(!_e(e))throw new Error("invalid session name");await we(F,H("kill-session","-t",e))}async function ig(e,t){if(_e(e))try{let n=t?H("set-option","-t",e,"@bostrat-sid",t):H("set-option","-u","-t",e,"@bostrat-sid");await we(F,n)}catch{}}async function Ae(e,{lines:t=40}={}){if(!_e(e))return"";try{let n=H("capture-pane","-t",e,"-p");Number.isFinite(t)&&t>0&&n.push("-S",`-${Math.floor(t)}`);let{stdout:r}=await we(F,n);return String(r||"")}catch{return""}}async function cg(e){if(!_e(e))return 0;try{let{stdout:t}=await we(F,H("list-clients","-t",e,"-F","1"));return String(t||"").trim().split(`
51
- `).filter(Boolean).length}catch{return 0}}async function Nr(e,{cols:t=uI,rows:n=dI}={}){if(!_e(e))return!0;if(await cg(e))return!1;try{let r=await lg(e);if(r.cols===t&&r.rows===n)return!0;await we(F,H("resize-window","-t",e,"-x",String(t),"-y",String(n))),await we(F,H("set-window-option","-t",e,"window-size","latest")),await Ro(80)}catch{}return!0}async function fI(e){if(!_e(e))return 0;try{let{stdout:t}=await we(F,H("display-message","-t",e,"-p","#{pane_pid}"));return Number(String(t||"").trim())||0}catch{return 0}}async function dn(e){let t=await fI(e);if(!t)return!1;try{return await we("pgrep",["-P",String(t)]),!1}catch(n){return n?.code===1}}async function lg(e){if(!_e(e))return{cols:0,rows:0};try{let{stdout:t}=await we(F,H("display-message","-t",e,"-p","#{window_width} #{window_height}")),[n,r]=String(t||"").trim().split(/\s+/).map(o=>Number(o)||0);return{cols:n,rows:r}}catch{return{cols:0,rows:0}}}async function pc(e,{cols:t=cI,rows:n=lI}={}){if(_e(e)&&!await cg(e))try{let r=await lg(e),o=Math.max(r.cols,t),s=Math.max(r.rows,n);(o>r.cols||s>r.rows)&&(await we(F,H("resize-window","-t",e,"-x",String(o),"-y",String(s))),await we(F,H("set-window-option","-t",e,"window-size","latest")),await Ro(80))}catch{}}async function fn(e){return await pc(e),Ae(e,{lines:Le})}async function $e(e,t,{settleMs:n=40,kind:r}={}){if(!_e(e))throw new Error("invalid session name");let o=(Array.isArray(t)?t:[t]).filter(s=>pI.has(s));for(let s=0;s<o.length;s++)await we(F,H("send-keys","-t",e,o[s])),n>0&&s<o.length-1&&await Ro(n);return Y({flow:"tmux",phase:"send-keys",sessionName:e,kind:r||"keys",keys:o.join(" ")}).catch(()=>{}),o.length}async function $o(e,t,{kind:n}={}){if(!_e(e))throw new Error("invalid session name");let r=Math.max(0,Math.floor(Number(t)||0));return r>0&&await we(F,H("send-keys","-t",e,"-N",String(r),"BSpace")),Y({flow:"tmux",phase:"send-keys",sessionName:e,kind:n||"wipe",keys:`BSpace x${r}`}).catch(()=>{}),r}async function hc(e,t,{perCharDelayMs:n=120,kind:r}={}){if(!_e(e))throw new Error("invalid session name");let o=[...String(t)];for(let s of o)await we(F,H("send-keys","-t",e,"-l",s)),n>0&&await Ro(n);Y({flow:"tmux",phase:"type",sessionName:e,kind:r||"type",textLen:o.length,textHead:String(t).slice(0,120)}).catch(()=>{})}function mI(e,t){return new Promise((n,r)=>{let o=tg(F,H(...e),(s,a,i)=>{s?r(s):n({stdout:a,stderr:i})});o.stdin.on("error",()=>{}),o.stdin.end(t)})}async function hI(e,t){let n=`bostrat-${ng().slice(0,8)}`;await mI(["load-buffer","-b",n,"-"],t),await we(F,H("paste-buffer","-p","-d","-b",n,"-t",e))}async function Fe(e,t,{enter:n=!0,submitDelayMs:r=0,kind:o,paste:s=!1}={}){if(!_e(e))throw new Error("invalid session name");if(typeof t=="string"&&t.length>0&&(s?await hI(e,t):await we(F,H("send-keys","-t",e,"-l",t))),n){let a=Number(r);Number.isFinite(a)&&a>0&&await Ro(a),await we(F,H("send-keys","-t",e,"Enter"))}Y({flow:"tmux",phase:"send",sessionName:e,kind:o||"text",textLen:typeof t=="string"?t.length:0,textHead:typeof t=="string"?t.slice(0,120):"",enter:n,submitDelayMs:r,...s?{paste:!0}:{}}).catch(()=>{})}var we,F,eg,ft,J_,td,ta,nd,Y_,uc,_o,Io,ed,Z_,Q_,od,eI,tI,nI,oa,oI,sI,cI,lI,Le,uI,dI,pI,mc,tt=O(()=>{Us();Wi();qi();zs();ac();un();Fs();we=V_(tg);F=process.env.BOSTRAT_TMUX_BIN||"/usr/bin/tmux";eg=typeof process.getuid=="function"?process.getuid():0,ft=z_({explicit:process.env.BOSTRAT_TMUX_SOCKET,legacyExists:(()=>{try{return lc.existsSync(rg(eg))}catch{return!1}})(),runtimeDir:process.env.XDG_RUNTIME_DIR,uid:eg}),J_=process.env.BOSTRAT_DEFAULT_CWD||process.env.HOME||"/",td=process.env.BOSTRAT_AGENT_CMD||"claude --dangerously-skip-permissions",ta="CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN";nd="bostrat-usage-probe",Y_=new Set([nd]);uc="present",_o="absent",Io="unknown",ed=5e3,Z_=[250,1e3,3e3],Q_=e=>new Promise(t=>setTimeout(t,e));od={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"};eI=/^[A-Za-z0-9_.-]{1,64}$/;tI=/^[A-Za-z0-9 ._↻-]+$/,nI=64;oa=()=>Number(process.env.BOSTRAT_LAUNCH_VERIFY_MS)||12e3,oI=1e3,sI=/not found|Unknown command/i;cI=Number(process.env.BOSTRAT_PROMPT_CAPTURE_COLS)||100,lI=Number(process.env.BOSTRAT_PROMPT_CAPTURE_ROWS)||40,Le=Number(process.env.BOSTRAT_PROMPT_CAPTURE_LINES)||80,uI=Number(process.env.BOSTRAT_BOX_COLS)||120,dI=Number(process.env.BOSTRAT_BOX_ROWS)||40;pI=new Set(["Up","Down","Left","Right","Space","Enter","Tab","BTab","Escape","BSpace"]);mc=1600});import sa from"node:fs";import xI from"node:fs/promises";import Oo from"node:path";import SI from"node:os";function id(e){return e.replace(/[^A-Za-z0-9]/g,"-")}function cd(e){let t=Oo.join(ad,id(e)),n;try{n=sa.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return null}let r=null;for(let o of n){let s=Oo.join(t,o);try{let{mtimeMs:a}=sa.statSync(s);(!r||a>r.mtimeMs)&&(r={full:s,mtimeMs:a})}catch{}}return r?r.full:null}function Mt(e,t){if(!t)return null;let n=Oo.join(ad,id(e),`${t}.jsonl`);return sa.existsSync(n)?n:null}function wg(e){if(!e)return[];let t=Oo.join(ad,id(e)),n;try{n=sa.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return[]}let r=[];for(let o of n)try{let s=sa.statSync(Oo.join(t,o));r.push({id:o.slice(0,-6),birthMs:s.birthtimeMs||s.ctimeMs||s.mtimeMs})}catch{}return r}async function it(e,t=131072){let n=await xI.open(e,"r");try{let{size:r}=await n.stat(),o=Math.max(0,r-t),s=r-o;if(s===0)return"";let a=Buffer.alloc(s);return await n.read(a,0,s,o),a.toString("utf8")}finally{await n.close()}}function TI(e){let t=e.split(`
52
- `);for(let n=t.length-1;n>=0;n--){let r=t[n].trim();if(!r||r[0]!=="{")continue;let o;try{o=JSON.parse(r)}catch{continue}let s=o?.message?.usage;if(!s)continue;let a=(s.input_tokens||0)+(s.cache_creation_input_tokens||0)+(s.cache_read_input_tokens||0);if(a>0)return{occupancy:a,model:o.message.model||o.model||null}}return null}async function aa(e,t=null,{fallbackNewest:n=!0}={}){if(!e)return null;let r,o;if(t){if(r=Mt(e,t),o=!0,!r)return null}else if(n){if(r=cd(e),o=!1,!r)return null}else return null;let s;try{s=TI(await it(r))}catch{return null}if(!s)return null;let a=Object.prototype.hasOwnProperty.call(hg,s.model),i=hg[s.model]||vI;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 hg,vI,ad,Nt=O(()=>{hg={"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},vI=2e5,ad=process.env.BOSTRAT_CLAUDE_PROJECTS||Oo.join(SI.homedir(),".claude","projects")});function EI(e){let t=[],n="",r=null;for(let o=0;o<e.length;o++){let s=e[o];if(r){n+=s,s===r&&e[o-1]!=="\\"&&(r=null);continue}if(s==="'"||s==='"'||s==="`"){r=s,n+=s;continue}if(s==="&"&&e[o+1]==="&"){t.push(n),n="",o++;continue}if(s==="|"&&e[o+1]==="|"){t.push(n),n="",o++;continue}if(s==="|"||s===";"||s===`
53
- `){t.push(n),n="";continue}n+=s}return t.push(n),t.map(o=>o.trim()).filter(Boolean)}function ia(e){let t=[],n="",r=null,o=!1,s=()=>{if(o){if(/^\d*[<>]/.test(n)||n.startsWith(">")){n="",o=!1;return}t.push(n),n="",o=!1}};for(let a=0;a<e.length;a++){let i=e[a];if(r){i===r&&e[a-1]!=="\\"?r=null:n+=i,o=!0;continue}if(i==="'"||i==='"'){r=i,o=!0;continue}if(i==="<"&&e[a+1]==="<")return s(),t.push("<<"),t;if(/\s/.test(i)){s();continue}n+=i,o=!0}return s(),t}function ca(e){let t=e;for(;t.length&&/^[A-Za-z_][A-Za-z0-9_]*=/.test(t[0]);)t=t.slice(1);for(;t.length&&(t[0]==="sudo"||t[0]==="time"||t[0]==="env");)t=t.slice(1);return t}function xe(e,t=new Set){let n=[];for(let r=1;r<e.length;r++){let o=e[r];if(o==="<<")break;if(bg(o)){t.has(o)&&r++;continue}n.push(o)}return n}function kg(e){let t=e.indexOf("-n"),n=t!==-1?e[t+1]:null;if(!n)return null;let r=/^(\d+),(\d+)p$/.exec(n)||/^(\d+)p$/.exec(n);return r?r[2]?{from:r[1],to:r[2]}:{from:r[1],to:r[1]}:null}function II(e){let t=kg(e),n=Ve(xe(e).find(r=>!/^\d+(,\d+)?p$/.test(r)));return t&&n?t.from===t.to?`Read line ${t.from} of ${Ie(n)}`:`Read lines ${t.from}\u2013${t.to} of ${Ie(n)}`:e.includes("-i")&&n?`Edit ${Ie(n)}`:null}function ld(e){if(e.includes("--files")){let s=Ve(xe(e,gg)[0]);return s&&s!=="."?`List files in ${Co(s)}`:"List files"}let t=xe(e,gg),n=t[0];if(!n)return null;let r=Ve(t.slice(1).find(s=>s!==".")),o=Mo(n,40);return r?`Search for \u201C${o}\u201D in ${Co(r)}`:`Search for \u201C${o}\u201D`}function ud(e){let t=xe(e,new Set(["--prefix"])),n=t[0];return n?n==="test"||n==="t"?"Run tests":n==="run"||n==="run-script"?t[1]?`Run ${t[1]}`:null:n==="ci"||n==="install"||n==="i"||n==="add"?"Install dependencies":null:null}function dd(e,t){if(e.includes("-e")||e.includes("--eval")||e.includes("-c")||e[1]==="-"||e.includes("<<"))return`Run an inline ${t} script`;if(e.includes("--test"))return"Run tests";let n=xe(e)[0];return n?`Run ${Ie(n)}`:null}function RI(e){let t=xe(e),n=t[0],r=t.find(a=>/\.(service|timer|socket|target)$/.test(a))||t[1],o=r?r.replace(/\.service$/,""):"a service";return{status:`Check ${o} status`,show:`Inspect ${o}`,restart:`Restart ${o}`,start:`Start ${o}`,stop:`Stop ${o}`,"daemon-reload":"Reload systemd"}[n]||null}function yg(e){return e.find(t=>/^https?:\/\//.test(t))||null}function CI(e){let t=ca(ia(e));if(!t.length)return null;if(/^(ba|z)?sh$/.test(Ie(t[0]))&&(t[1]==="-lc"||t[1]==="-c")&&t[2])return fd(t[2]);let n=Ie(t[0]);if(OI.has(n))return null;if(t.includes("--version"))return`Check ${n} version`;if(n.endsWith(".sh"))return`Run ${n}`;let r=$I[n];return r?r(t.map((o,s)=>s===0?n:o)):null}function fd(e){let t=String(e||"").trim();if(!t)return null;let n=t.indexOf("<<");if(n!==-1){let i=t.indexOf(`
54
- `,n);i!==-1&&(t=t.slice(0,i))}let r=EI(t);for(let i=0;i<r.length-1;i++){let c=ca(ia(r[i])),l=ca(ia(r[i+1]));if(!(!c.length||!l.length)&&["nl","cat"].includes(Ie(c[0]))&&Ie(l[0])==="sed"){let u=kg(l),f=xe(c)[0];if(u&&f)return Mo(u.from===u.to?`Read line ${u.from} of ${Ie(f)}`:`Read lines ${u.from}\u2013${u.to} of ${Ie(f)}`,88)}}let o=[];for(let i of r){let c=CI(i);c&&o.push({d:c,head:Ie(ca(ia(i))[0]||""),sub:xe(ca(ia(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":Mo(s?s.d:o[0].d,88)}var Mo,Ve,Ie,Co,bg,gg,AI,_I,$I,OI,xg=O(()=>{Mo=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,Ve=e=>e&&!/[$`]/.test(e)?e:null,Ie=e=>e.replace(/\/+$/,"").split("/").pop()||e,Co=e=>{let t=e.replace(/\/+$/,"").split("/").filter(Boolean);return t.length>3?t.slice(-2).join("/"):e},bg=e=>e.startsWith("-"),gg=new Set(["-g","--glob","-t","--type","-A","-B","-C","-m","--max-count","-e","--regexp","-f","--file"]);AI={status:()=>"Check git status",diff:()=>"Review changes",log:()=>"Review commit history",show:()=>"Inspect a commit",add:()=>"Stage files",commit:()=>"Commit changes",push:()=>"Push to remote",pull:()=>"Pull from remote",fetch:()=>"Fetch from remote",merge:()=>"Merge branches",rebase:()=>"Rebase branch",stash:()=>"Stash changes",clone:e=>e[1]?`Clone ${Ie(e[1])}`:"Clone repository",checkout:()=>"Switch branches",switch:()=>"Switch branches",restore:()=>"Restore files",reset:()=>"Reset git state",branch:(e,t)=>t.includes("--show-current")?"Check current branch":"List branches",remote:()=>"Check git remotes","rev-parse":()=>"Resolve a git ref",worktree:()=>"Manage git worktrees","merge-base":()=>"Find the merge base","ls-files":()=>"List tracked files"},_I={pr:e=>({create:"Create a pull request",list:"List pull requests",view:"View a pull request",merge:"Merge a pull request",checks:"Check PR status"})[e[1]]||"Run a gh pr command",auth:()=>"Authenticate GitHub CLI",api:()=>"Call the GitHub API",repo:()=>"Inspect the GitHub repo",issue:()=>"Work with GitHub issues"};$I={git:e=>{let t=xe(e,new Set(["-C","-c"])),n=AI[t[0]];return n?n(t,e):null},gh:e=>{let t=xe(e),n=_I[t[0]];return n?n(t):null},sed:II,rg:ld,grep:ld,egrep:ld,nl:e=>{let t=Ve(xe(e)[0]);return t?`Read ${Ie(t)}`:null},cat:e=>{let t=Ve(xe(e)[0]);return t?`Read ${Ie(t)}`:null},head:e=>{let t=Ve(xe(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the start of ${Ie(t)}`:null},tail:e=>{let t=Ve(xe(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the end of ${Ie(t)}`:null},wc:e=>{let t=Ve(xe(e)[0]);return t?`Count lines in ${Ie(t)}`:"Count input lines"},ls:e=>{let t=Ve(xe(e)[0]);return t&&t!=="."?`List files in ${Co(t)}`:"List files"},find:e=>Ve(e[1])&&!bg(e[1])&&e[1]!=="."?`Find files in ${Co(e[1])}`:"Find files",tree:()=>"List the directory tree",mkdir:e=>{let t=Ve(xe(e)[0]);return t?`Create directory ${Co(t)}`:null},touch:e=>{let t=Ve(xe(e)[0]);return t?`Create ${Ie(t)}`:null},rm:e=>{let t=Ve(xe(e)[0]);return t?`Delete ${Co(t)}`:null},mv:e=>{let t=Ve(xe(e)[0]);return t?`Move ${Ie(t)}`:null},cp:e=>{let t=Ve(xe(e)[0]);return t?`Copy ${Ie(t)}`:null},chmod:e=>{let t=Ve(xe(e)[1]);return t?`Change permissions on ${Ie(t)}`:null},diff:e=>{let t=xe(e);return t.length>=2?`Compare ${Ie(t[0])} and ${Ie(t[1])}`:null},curl:e=>{let t=yg(e);return t?`Fetch ${Mo(t,56)}`:"Fetch a URL"},wget:e=>{let t=yg(e);return t?`Fetch ${Mo(t,56)}`:"Fetch a URL"},npm:ud,pnpm:ud,yarn:ud,npx:e=>{let t=xe(e)[0];return t?`Run ${t}`:null},node:e=>dd(e,"Node"),python:e=>dd(e,"Python"),python3:e=>dd(e,"Python"),make:e=>{let t=xe(e)[0];return t?`Run make ${t}`:"Run make"},systemctl:RI,journalctl:e=>{let t=e.findIndex(r=>r==="-u"||r==="--unit"||r==="--user-unit"),n=t!==-1?e[t+1]:null;return n?`Read ${n.replace(/\.service$/,"")} logs`:"Read system logs"},tmux:e=>{let t=xe(e,new Set(["-S","-L","-t","-f"]))[0];return{ls:"List tmux sessions","list-sessions":"List tmux sessions","kill-session":"Kill a tmux session","send-keys":"Send keys to a tmux session","capture-pane":"Capture a tmux pane","new-session":"Start a tmux session"}[t]||null},ps:()=>"List processes",which:e=>{let t=xe(e)[0];return t?`Locate ${t}`:null},command:e=>e[1]==="-v"&&e[2]?`Locate ${e[2]}`:null,fly:e=>{let t=xe(e)[0];return t==="deploy"?"Deploy to Fly":t?`Run fly ${t}`:null}},OI=new Set(["pwd","echo","cd","sleep","true","false","test","[","set","export","exit","read"])});function No(e){let t=e.split(`
55
- `).map(n=>n.trim()).find(Boolean)||e;return t.length>88?`${t.slice(0,88).trimEnd()}\u2026`:t}function Jn(e,t=""){let n=t.trim();return n||fd(e)||No(e)}function pd(e,t){if(e){if(Array.isArray(e)){for(let n of e)pd(n,t);return}if(typeof e=="object"){if(e.type==="tool_use"&&md.has(e.name)){let n=String(e.input?.command||"").trim();n&&t.push({id:e.id||null,tool:e.name,command:n,description:String(e.input?.description||"").trim()})}for(let n of Object.values(e))pd(n,t)}}}async function Sg(e,{maxBytes:t=1048576,limit:n=400}={}){let r;try{r=await it(e,t)}catch{return[]}let o=[];for(let s of r.split(`
56
- `)){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(pd(c.content,l),!l.length)continue;let u=i.timestamp?Date.parse(i.timestamp):null;for(let f of l)o.push({...f,summary:Jn(f.command,f.description),ts:u})}return o.slice(-n)}function vg(e,t){let n=t.filter(l=>l.role==="assistant"&&(l.text||"").trim()).sort((l,u)=>(l.ts||0)-(u.ts||0)),r=[...e].sort((l,u)=>(l.ts||0)-(u.ts||0)),o=[],s=0,a=0,i=l=>{let u=l.n??a+1;return u>a&&(a=u),u};for(let l of n){let u=r.findIndex((m,h)=>h>=s&&(m.ts||0)>(l.ts||0)),f=u===-1?r.length:u,d=r.slice(s,f);if(s=f,!d.length)continue;let p=d.map(m=>({...m,n:i(m)}));o.push({id:`batch-${l.ts}-${l.box}`,anchorTs:l.ts,anchorBox:l.box,agent:l.agent,boxRole:l.boxRole,commands:p,ts:Math.max(...p.map(m=>m.ts||0)),pending:!1})}let c=r.slice(s);if(c.length){let l=c.map(u=>({...u,n:i(u)}));o.push({id:`batch-pending-${l[0]?.box||"lead"}`,anchorTs:null,anchorBox:l[l.length-1]?.box??null,agent:l[l.length-1]?.agent??"claude",boxRole:l[l.length-1]?.boxRole??"lead",commands:l,ts:Math.max(...l.map(u=>u.ts||0)),pending:!0})}return o}var md,Po=O(()=>{Nt();xg();md=new Set(["Bash"])});import Tg from"node:fs";import wd from"node:fs/promises";import hd from"node:path";import MI from"node:os";async function Eg(e){try{return await wd.realpath(e)}catch{return e}}function PI(e=NI){let t=[],n=r=>{let o;try{o=Tg.readdirSync(r,{withFileTypes:!0})}catch{return}for(let s of o){let a=hd.join(r,s.name);if(s.isDirectory())n(a);else if(s.isFile()&&s.name.startsWith("rollout-")&&s.name.endsWith(".jsonl")){let i=/-([0-9a-f-]{36})\.jsonl$/i.exec(s.name);try{t.push({id:i?i[1]:null,file:a,mtimeMs:Tg.statSync(a).mtimeMs})}catch{}}}};return n(e),t.sort((r,o)=>o.mtimeMs-r.mtimeMs)}async function DI(e,t=1048576){let n;try{n=await wd.open(e,"r")}catch{return""}try{let r=Buffer.alloc(Math.min(t,65536)),o="",s=0;for(;;){let{bytesRead:a}=await n.read(r,0,r.length,s);if(!a)break;o+=r.toString("utf8",0,a);let i=o.indexOf(`
57
- `);if(i!==-1)return o.slice(0,i);if(s+=a,o.length>=t)break}return o}finally{await n.close()}}async function BI(e){let t=await DI(e);if(!t)return null;let n;try{n=JSON.parse(t)}catch{return null}return n?.type==="session_meta"&&n?.payload?.cwd||null}async function Pr(e,t){if(!e&&!t)return null;let n=PI();if(t){let o=n.find(s=>s.id===t);return o||null}let r=await Eg(e);for(let o of n){let s=await BI(o.file);if(s&&(s===e||await Eg(s)===r))return o}return null}async function Ag(e,t,{limit:n=80,maxBytes:r=524288}={}){let o=await Pr(e,t);if(!o)return[];let s;try{s=await it(o.file,r)}catch{return[]}let a=[],i=null,c=[],l=!1,u=!1,f=null;for(let d of s.split(`
58
- `)){let p=d.trim();if(!p||p[0]!=="{")continue;let m;try{m=JSON.parse(p)}catch{continue}if((m.type==="turn_context"&&m.payload?.model||m.type==="session_meta"&&m.payload?.model)&&(i=m.payload.model),m.type==="event_msg"){let k=m.payload?.type;k==="task_started"?(l=!0,u=!1,f=m.payload?.turn_id||null):k==="task_complete"&&l&&(l=!1,!u&&m.payload?.last_agent_message==null&&a.push({role:"assistant",failed:!0,text:Dr,sourceId:m.payload?.turn_id||f||void 0,ts:m.timestamp?Date.parse(m.timestamp):null,model:i}));continue}if(m.type!=="response_item")continue;let h=m.payload;if(!h)continue;if((h.type==="function_call"||h.type==="custom_tool_call")&&h.name){u=!0,gd.has(h.name)||c.push(h.name);continue}if(h.type!=="message"||h.role!=="assistant")continue;u=!0;let g=LI(h.content),x=c.length?c.slice():null;c=[],!(!g&&!x)&&a.push({role:"assistant",text:g,tools:x||void 0,ts:m.timestamp?Date.parse(m.timestamp):null,model:i})}if(i)for(let d of a)d.model||(d.model=i);return a.slice(-n)}function FI(e){if(typeof e?.cmd=="string"&&e.cmd.trim())return e.cmd.trim();let t=e?.command;return typeof t=="string"&&t.trim()?t.trim():Array.isArray(t)&&t.length?t.length===3&&/^(ba)?sh$/.test(t[0])&&t[1]==="-lc"?String(t[2]).trim():t.map(String).join(" ").trim():null}function UI(e){let t=e[0];if(t!=='"'&&t!=="'"&&t!=="`")return null;let n="";for(let r=1;r<e.length;r++){let o=e[r];if(o==="\\"){let s=e[++r];if(s===void 0)return null;if(s==="n")n+=`
59
- `;else if(s==="t")n+=" ";else if(s==="r")n+="\r";else if(s==="u")if(e[r+1]==="{"){let a=e.indexOf("}",r+2);if(a===-1)return null;n+=String.fromCodePoint(parseInt(e.slice(r+2,a),16)),r=a}else n+=String.fromCharCode(parseInt(e.slice(r+1,r+5),16)),r+=4;else n+=s}else{if(o===t)return n;if(t==="`"&&o==="$"&&e[r+1]==="{")return null;n+=o}}return null}function HI(e){let t=String(e||""),n=[],r=/exec_command\s*\(/g;for(let s;s=r.exec(t);)n.push(s.index+s[0].length);let o=[];return n.forEach((s,a)=>{let i=t.slice(s,a+1<n.length?n[a+1]:t.length),c=/(?:^|[{,\s])["'`]?cmd["'`]?\s*:\s*/.exec(i);if(!c)return;let l=UI(i.slice(c.index+c[0].length).trimStart());l&&l.trim()&&o.push(l.trim())}),o}async function _g(e,t,{limit:n=400,maxBytes:r=524288}={}){let o=await Pr(e,t);if(!o)return[];let s;try{s=await it(o.file,r)}catch{return[]}let a=[];for(let i of s.split(`
60
- `)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.type!=="response_item")continue;let u=l.payload;if(!u)continue;let f=[];if(u.type==="function_call"&&la.has(u.name)){let p;try{p=JSON.parse(u.arguments||"{}")}catch{continue}let m=FI(p);m&&(f=[m])}else u.type==="custom_tool_call"&&u.name==="exec"&&(f=HI(u.input));if(!f.length)continue;let d=u.call_id||u.id||null;f.forEach((p,m)=>{a.push({id:d?m?`${d}:${m}`:d:null,tool:u.name,command:p,description:"",summary:Jn(p),ts:l.timestamp?Date.parse(l.timestamp):null})})}return a.slice(-n)}async function Ig(e,t){let n=await Pr(e,t);if(!n)return null;try{return Math.round((await wd.stat(n.file)).mtimeMs)}catch{return n.mtimeMs||null}}var NI,jI,LI,la,gd,Dr,Br=O(()=>{Nt();Po();NI=process.env.BOSTRAT_CODEX_SESSIONS||hd.join(process.env.CODEX_HOME||hd.join(MI.homedir(),".codex"),"sessions");jI=new Set(["output_text","text"]),LI=e=>typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&typeof t.text=="string"&&jI.has(t.type)).map(t=>t.text).join(`
61
- `).trim():"";la=new Set(["exec_command","shell","exec"]),gd=new Set(["wait","write_stdin"]),Dr="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 ua({error:e=null,status:t=null,text:n=""}={}){let r=String(e||"").trim().toLowerCase();if(r&&Rg.has(r))return Rg.get(r);let o=Number(t)||0;if(o===401)return"auth";if(o===403)return"entitlement";if(o===429)return"rate_limit";if(o===529)return"overloaded";if(o>=500)return"server";let s=String(n||"").toLowerCase();return/overloaded/.test(s)?"overloaded":/rate limit|too many requests|quota|usage limit/.test(s)?"rate_limit":/billing|subscription|not allowed|disabled .* access|upgrade your plan|no credits/.test(s)?"entitlement":/log ?in|authenticat|expired|invalid.*key|unauthorized/.test(s)?"auth":/server|internal error|5\d\d/.test(s)?"server":"other"}function $g(e){if(!e||e.role!=="assistant")return null;if(e.apiError){let t=e.apiError;return{cls:t.cls||ua({error:t.code,status:t.status,text:e.text}),code:t.code||null,status:t.status||null,requestId:t.requestId||null}}if(e.failed){let t=String(e.text||"");return{cls:t===Dr?"other":ua({text:t}),code:null,status:null,requestId:null}}return null}function Og(e,{codexFailedText:t=null}={}){let n=String(e?.text||"").trim();return n?e?.model==="<synthetic>"?/^No response requested\.$/.test(n)?null:{cls:ua({text:n}),code:null,status:WI(n),requestId:null,text:n}:t&&n===t?{cls:"other",code:null,status:null,requestId:null,text:n}:null:null}function WI(e){let t=/^API Error:\s*(\d{3})\b/.exec(e);return t?Number(t[1]):null}var p2,Rg,gc=O(()=>{Br();p2=Object.freeze(["entitlement","auth","rate_limit","overloaded","server","other"]),Rg=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 qI(e,t){return!e||!t?null:Mt(e,t)}function KI(e){return typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&t.type==="text"&&typeof t.text=="string").map(t=>t.text).join(`
62
- `).trim():""}function GI(e){if(!Array.isArray(e))return null;let t=e.filter(n=>n&&n.type==="tool_use").map(n=>n.name).filter(Boolean);return t.length?t:null}function VI(e){return Array.isArray(e)&&e.length>0&&e.every(t=>t&&t.type==="tool_result")}function yd(e){let t=[],n=e?.message?.content;if(!Array.isArray(n))return t;for(let r of n)if(r){if(r.type==="image"&&r.source?.type==="base64"&&r.source.data)t.push({mediaType:r.source.media_type||"image/png",data:r.source.data,toolUseId:null});else if(r.type==="tool_result"&&Array.isArray(r.content))for(let o of r.content)o?.type==="image"&&o.source?.type==="base64"&&o.source.data&&t.push({mediaType:o.source.media_type||"image/png",data:o.source.data,toolUseId:r.tool_use_id||null})}return t}function Cg(e,t){if(!e.uuid)return null;let n=yd(e).map((r,o)=>({uuid:e.uuid,index:o,mediaType:r.mediaType,name:r.toolUseId&&t.get(r.toolUseId)||null}));return n.length?n:null}async function bd(e,{maxBytes:t=524288,limit:n=80}={}){let r;try{r=await it(e,t)}catch{return[]}let o=[],s=new Map;for(let a of r.split(`
63
- `)){let i=a.trim();if(!i||i[0]!=="{")continue;let c;try{c=JSON.parse(i)}catch{continue}if(c.type==="attachment"){let h=c.attachment;h?.type==="queued_command"&&h.commandMode==="task-notification"&&typeof h.prompt=="string"&&h.prompt.trim()&&o.push({role:"user",text:h.prompt.trim(),ts:c.timestamp?Date.parse(c.timestamp):null,model:null});continue}let l=c.message;if(!l)continue;let u=l.role||c.type;if(u!=="user"&&u!=="assistant"||u==="assistant"&&l.model==="<synthetic>"&&!c.isApiErrorMessage)continue;if(u==="assistant"&&Array.isArray(l.content))for(let h of l.content){let g=h?.type==="tool_use"?h.input?.file_path||h.input?.path:null;typeof g=="string"&&zI.test(g)&&s.set(h.id,g.split("/").pop())}if(VI(l.content)){let h=Cg(c,s);h&&o.push({role:"assistant",text:"",images:h,ts:c.timestamp?Date.parse(c.timestamp):null,model:null});continue}let f=KI(l.content),d=u==="assistant"?GI(l.content):null,p=u==="user"?Cg(c,s):null;if(!f&&!d&&!p)continue;let m=u==="assistant"&&c.isApiErrorMessage?{code:typeof c.error=="string"?c.error:null,status:Number(c.apiErrorStatus)||null,requestId:c.requestId||null,cls:ua({error:c.error,status:c.apiErrorStatus,text:f})}:null;o.push({role:u,text:f,tools:d||void 0,images:p||void 0,ts:c.timestamp?Date.parse(c.timestamp):null,model:l.model||null,apiError:m||void 0})}return o.slice(-n)}async function Mg(e,t,{turns:n=16}={}){let r=qI(e,t);if(!r)return"";let o=await bd(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}:** ${JI(s.text||c,700)} ${i}`.trim()}).join(`
64
-
65
- `):""}var zI,JI,yc=O(()=>{gc();Nt();zI=/\.(png|jpe?g|gif|webp|bmp|svg|tiff?|avif|heic|heif|ico)$/i;JI=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e});import YI from"node:fs/promises";import{execFile as XI}from"node:child_process";import{promisify as ZI}from"node:util";function Bg(e){xd=typeof e=="function"?e:null}function Sd(e){let t=String(e||""),n=t.indexOf("/lib/node_modules/");return n>0?t.slice(0,n):null}function jg({sessionName:e,from:t,to:n}={}){let r=String(n||"").trim();!r||Ng.has(r)||(Ng.add(r),Pg=Pg.then(()=>eR({sessionName:e,from:t,to:r})).catch(()=>{}))}async function eR({sessionName:e,from:t,to:n}){await Y({flow:"codex-update",phase:"start",sessionName:e,from:t,to:n}).catch(()=>{});try{let r=(await kd("/bin/sh",["-c","command -v codex"])).stdout.trim();if(!r)throw new Error("codex not on PATH");let o=await YI.realpath(r),s=Sd(o),a=s?{...process.env,PATH:`${s}/bin:${process.env.PATH||""}`}:process.env;await kd("npm",["install","-g","@openai/codex"],{env:a,timeout:QI});let i=(await kd(r,["--version"])).stdout.trim().replace(/^codex-cli\s*/,"")||n;await Y({flow:"codex-update",phase:"done",sessionName:e,from:t,to:n,version:i}).catch(()=>{}),await Dg({sessionName:e,from:t,to:n,version:i,status:"updated"})}catch(r){let o=String(r?.message||r).slice(0,300);await Y({flow:"codex-update",phase:"failed",sessionName:e,from:t,to:n,error:o}).catch(()=>{}),await Dg({sessionName:e,from:t,to:n,status:"failed",error:o})}}async function Dg(e){if(xd)try{await xd(e)}catch{}}var kd,QI,Ng,Pg,xd,bc=O(()=>{un();kd=ZI(XI),QI=Number(process.env.BOSTRAT_CODEX_UPDATE_TIMEOUT_MS)||5*6e4,Ng=new Set,Pg=Promise.resolve(),xd=null});function nR(e,{provider:t,box:n}){let r=String(e).replace(/\r/g,"").split(`
66
- `);if(!Lg.test(e))return null;let o=[],s=!1;for(let l=r.length-1;l>=0;l--){let u=r[l].match(tR);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"&&Lg.test(a)?a:"The agent is asking for approval";return{provider:t,box:n,promptId:`${t}:${c}:${i.map(l=>l.label).join("|")}`.slice(0,200),questions:[{question:c,header:"Approval",multiSelect:!1,options:i.map(l=>({label:l.label,description:""}))}]}}function jr(e){let t=String(e??"").replace(/\r/g,""),n=t.split(`
67
- `);for(let r=n.length-1;r>=0;r--)if(Hg.test(n[r]))return n.slice(r).join(`
68
- `);return t}function rR(e){let t=String(e).trim();if(!t)return!1;let n=(t.match(/[A-Za-z]/g)||[]).length;return n>=3&&n/t.length>=.5}function oR(e){return/device code/i.test(e)?"works from the device you're reading this on":/sign in with chatgpt/i.test(e)?"opens a browser link on the node itself \u2014 can't finish from another device":""}function sR(e,t=""){let n=jr(e);if(da.test(n)||!/Sign in with ChatGPT/.test(n)||!/Press enter to continue/.test(n))return null;let r=n.split(`
69
- `),o=[],s=-1;for(let l=0;l<r.length;l++){let u=r[l].match(Fg);if(!u)continue;s<0&&(s=l);let f="";for(let d=l+1;d<Math.min(l+3,r.length);d++){let p=r[d].trim();if(p){if(Fg.test(r[d])||/^Press enter/.test(p))break;f=p;break}}o.push({n:Number(u[2]),cursor:!!u[1],label:u[3].trim(),desc:f})}let a=o.sort((l,u)=>l.n-u.n);if(a.length<2||a.some((l,u)=>l.n!==u+1)||!a.some(l=>/Sign in with ChatGPT/.test(l.label)))return null;let i=[];for(let l=0;l<s;l++){let u=r[l].trim();u&&!Hg.test(r[l])&&rR(u)&&i.push(u)}let c=i.join(" ").slice(0,400)||"Codex isn't signed in on this box \u2014 choose a sign-in method";return{provider:"codex",box:t,multiSelect:!1,cursorIndex:Math.max(0,a.findIndex(l=>l.cursor)),answerMode:"keys",promptId:`codex:signin:${a.map(l=>l.label).join("|")}`.slice(0,200),questions:[{question:c,header:"Sign in",multiSelect:!1,options:a.map(l=>{let u=oR(l.label);return{label:l.label,description:[l.desc,u].filter(Boolean).join(" \xB7 ")}})}]}}function cR(e,t=""){let n=jr(e);if(da.test(n)||!aR.test(n))return null;let r=n.trimEnd().split(`
70
- `).pop()||"";return iR.test(r)?{provider:"codex",box:t,multiSelect:!1,cursorIndex:0,answerMode:"keys",promptId:"codex:signin-complete",questions:[{question:"Codex successfully signed in and is waiting to open the session.",header:"Signed in",multiSelect:!1,options:[{label:"Continue",description:""}]}]}:null}function uR(e,t=""){let n=jr(e);if(da.test(n)||!Ug.test(n))return null;let r=n.split(`
71
- `),o=r.findIndex(i=>Ug.test(i)),s="";for(let i=o+1;i<r.length;i++){let c=r[i].match(lR);if(c){s=c[1];break}}if(!s)return null;let a=(n.match(/https:\/\/\S+/)||[])[0]||"https://auth.openai.com/codex/device";return{provider:"codex",box:t,multiSelect:!1,cursorIndex:0,answerMode:"esc",promptId:`codex:device-code:${s}`,questions:[{question:`Codex is waiting for you to finish signing in: open ${a} and enter code ${s} (expires in 15 minutes). The code goes straight to OpenAI \u2014 bostrat never sees your login. This card clears once OpenAI confirms.`,header:"Sign in",multiSelect:!1,options:[{label:"Cancel sign-in",description:"Go back to the sign-in options"}]}]}}function dR(e,t=""){let n=jr(e);return da.test(n)||!/open the following link to authenticate/.test(n)?null:{provider:"codex",box:t,multiSelect:!1,cursorIndex:0,answerMode:"esc",promptId:"codex:signin-browser",questions:[{question:"Codex started its browser sign-in, which opens on the box itself and can't complete from another device. Go back and choose \u201CSign in with Device Code\u201D instead.",header:"Sign in",multiSelect:!1,options:[{label:"Go back to sign-in options",description:""}]}]}}function fR(e,t=""){let n=jr(e);return da.test(n)||!/Paste or type your API key/.test(n)?null:{provider:"codex",box:t,multiSelect:!1,cursorIndex:0,answerMode:"esc",promptId:"codex:signin-apikey",questions:[{question:"Codex is asking for an OpenAI API key. For safety a key can only be typed in the Terminal tab, never through chat. To use your ChatGPT subscription instead, go back and pick a sign-in option.",header:"Sign in",multiSelect:!1,options:[{label:"Go back to sign-in options",description:""}]}]}}function pR(e,t=""){let n=String(e);if(!/Press any key to log in/.test(n)||vd.test(n))return null;let r=n.replace(/\r/g,"").split(`
72
- `).map(a=>a.trim()),o=r.findIndex(a=>/Press any key to log in/.test(a)),s=r.slice(0,o<0?r.length:o).filter(a=>a&&!/^Cursor Agent$/i.test(a)&&!/^v?\d{4}\.\d{2}\.\d{2}/.test(a)).join(" ");return{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,answerMode:"keys",promptId:"cursor:signin-start",questions:[{question:(s?`${s} `:"")+"Cursor isn't signed in on this box \u2014 start the sign-in to get a login link you can open from any device.",header:"Sign in",multiSelect:!1,options:[{label:"Start sign-in",description:"Shows a login link (and a QR option) \u2014 your login goes to cursor.com, never through bostrat"}]}]}}function hR(e,t=""){let n=String(e);if(!mR.test(n)||vd.test(n))return null;let r=n.replace(/\r/g,"").split(`
73
- `),o="",s=r.findIndex(a=>/https:\/\//.test(a));if(s>=0){o=r[s].slice(r[s].indexOf("https://")).trim();for(let a=s+1;a<r.length;a++){let i=r[a].trim();if(!i||!/^[A-Za-z0-9~%&=?/_.-]+$/.test(i))break;o+=i}}return{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,promptId:`cursor:signin-link:${(o.match(/[?&]challenge=([\w-]+)/)||[])[1]?.slice(0,16)||o.slice(-24)||"pending"}`,questions:[{question:o?`Cursor is waiting for you to finish signing in: open ${o} on any device and log in. Your login goes straight to cursor.com \u2014 bostrat never sees it. This card clears once sign-in completes.`:"Cursor is waiting for you to finish signing in \u2014 open the login link shown in the Terminal tab. This card clears once sign-in completes.",header:"Sign in",multiSelect:!1,options:[]}]}}function wR(e,t=""){let n=String(e);return!/Scan this QR code to log in/.test(n)||vd.test(n)?null:{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,promptId:"cursor:signin-qr",questions:[{question:"Cursor is showing a QR sign-in code in the Terminal tab \u2014 scan it from another device to log in. This card clears once sign-in completes.",header:"Sign in",multiSelect:!1,options:[]}]}}function Wg(e,t,n=""){if(e!=="cursor"&&e!=="codex")return null;if(e==="codex"){let r=cR(t,n)||uR(t,n)||dR(t,n)||fR(t,n)||sR(t,n);if(r)return r}if(e==="cursor"){let r=hR(t,n)||wR(t,n)||pR(t,n);if(r)return r}return nR(t,{provider:e,box:n})}function qg(e,t){let n=Array.isArray(t?.[0])?t[0]:[],o=(Number.isInteger(n[0])&&n[0]>=0?n[0]:0)+1;return String(o)}var tR,Lg,da,Hg,Fg,aR,iR,Ug,lR,vd,mR,kc=O(()=>{tR=/^\s*[›>*\-❯]?\s*(\d+)[.)]\s+(.+?)\s*$/,Lg=/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i;da=/(^|\n)\s*›/,Hg=/^\s*Welcome to Codex\b/;Fg=/^\s*(>)?\s*(\d+)\.\s+(.+?)\s*$/;aR=/Successfully logged in\./,iR=/^\s*Press Enter to continue\.\s*$/;Ug=/Enter this one-time code/,lR=/^\s*([A-Z0-9]{2,10}-[A-Z0-9]{2,10})\s*$/;vd=/Run Everything|Add a follow-up|Plan, search, build anything/;mR=/click this link to log in|Signing in with the browser/});function xR(e){let t=String(e||"");if(!Be.codex.block.test(t))return null;let n=jr(t);if(!Be.codex.block.test(n))return null;let r=n.match(kR);return{from:r?.[1]||null,to:r?.[2]||null}}function Yn(e){return new Promise(t=>setTimeout(t,e))}function Kg(e,t){let n=Date.now(),r=SR();for(let[s,a]of xc)n-a>=r&&xc.delete(s);let o=`${e}::${t}`;return xc.has(o)?!1:(xc.set(o,n),!0)}function ER(e){let t=0;for(let n of String(e).split(`
74
- `))TR.test(n)&&(t=Math.max(t,n.trimEnd().length));return t}function Ed(e,t){let n=Be[e];if(!n?.busy)return{state:"idle",reason:null};if(_d(e,t))return{state:"unknown",reason:"blocked"};if(n.up&&!n.up.test(t))return{state:"idle",reason:null};if(n.busy.test(t))return{state:"busy",reason:null};if(n.busyAlt&&n.busyAlt.test(t))return{state:"busy",reason:null};let r=ER(t);return e==="claude"&&r>0&&r<vR?{state:"unknown",reason:"narrow"}:{state:"idle",reason:null}}function Ad(e,t){return Ed(e,t).state}function zg(e,t){if(e!=="claude")return!1;let n=String(t||"").split(`
75
- `).slice(-_R).join(`
76
- `);return AR.test(n)}function pa(e,t){return Ad(e,t)==="busy"}function Sc(e,t){return Ad(e,t)!=="idle"}function vc(e,t){let n=Be[e];return n?.up?n.up.test(t):!0}function IR(e,t){let n=Be[e];return n?_d(e,t)?!1:n.up.test(t)&&Ad(e,t)==="idle":!0}function _d(e,t){let n=Be[e];return n?n.auth?.test(t)&&!n.up.test(t)?!0:n.block?.test(t)?e==="codex"?!0:!n.up.test(t):!1:!1}function Id(e,t){let n=String(t||"").trim();if(!n)return e;let r=String(e||"").split(`
47
+ `,"utf8")}catch(t){console.warn(`[handoff-debug] failed to write ${Ao}: ${t?.message||t}`)}}async function X(e={}){let t={at:new Date().toISOString(),ts:Date.now(),...e},n=[t.flow||"handoff",t.phase||t.step||"?",t.trackId?`track=${t.trackId}`:"",t.sessionName?`box=${t.sessionName}`:"",t.error?`ERR=${t.error}`:""].filter(Boolean).join(" \xB7 ");if(console.log(`[handoff-debug] ${n}`),t.sessionName&&dc())try{t.paneTail=Or((await Te(t.sessionName,{lines:35})).slice(-4e3))}catch{t.paneTail=null}(dc()||t.error||/^(checkpoint|spawn|hydrate|commit|done|summarize|clear|resume|ready|send|failed|launch|submit-|gate-accept|blocked|timeout|dialog)/.test(String(t.phase||t.step||"")))&&await eI(t)}async function og({limit:e=80}={}){try{return(await oa.readFile(Ao,"utf8")).split(`
48
+ `).filter(Boolean).slice(-e).map(r=>{try{let o=JSON.parse(r);return typeof o?.paneTail=="string"&&(o.paneTail=Or(o.paneTail)),o}catch{return{raw:Or(r)}}})}catch{return[]}}var Q_,rd,Ao,ng,sg,Gt=C(()=>{Ve();Q_=[/[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];rd=process.env.BOSTRAT_DEBUG_DIR||rg.join(Z_.homedir(),".bostrat","debug"),Ao=rg.join(rd,"handoff.jsonl"),ng=Number(process.env.BOSTRAT_HANDOFF_DEBUG_MAX)||500;sg={DEBUG_DIR:rd,LOG_FILE:Ao}});import{execFile as ig}from"node:child_process";import{promisify as tI}from"node:util";import pc from"node:fs";import{randomUUID as cg}from"node:crypto";function Ro(e){return new Promise(t=>setTimeout(t,e))}function fc(e,t){if(!t)return e;let n=o=>typeof o=="string"?o.split(t).join("<redacted>"):o,r=new Error(n(e?.message)||"command failed");return e?.code!==void 0&&(r.code=e.code),e?.stderr!==void 0&&(r.stderr=n(e.stderr)),r}function lg(e){return`/tmp/tmux-${e}/default`}function nI({explicit:e,legacyExists:t,runtimeDir:n,uid:r}){if(e)return e;let o=lg(r);return t?o:n?`${n}/bostrat/tmux-default`:o}function aa(){return process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1"?[]:["-e",`${sa}=1`]}function id(e,t,n){let r=Cr(e),o=/(^|\s)(--session-id|--resume|--continue|-r|-c)(\s|=|$)/.test(e);if(!r||o)return e;let s=`${e} --session-id ${t}`,a=/(^|\s)(--name|-n)(\s|=)/.test(e);return n&&!a&&_e(n)&&(s+=` --name ${n}`),s}function Cr(e){return/(^|\/|\s)claude(\s|$)/.test(String(e||""))}function Vn(e){return/(^|\/|\s)claude(\s|$)/.test(e)?"claude":/cursor/.test(e)?"cursor":/codex/.test(e)?"codex":/gemini/.test(e)?"gemini":"agent"}function sI(e){let t=String(e||"").trim();return!t||/fake-|\.sh(\s|$)/.test(t)?!1:Cr(t)||/(^|\/|\s)codex(\s|$)/.test(t)||/cursor-agent/.test(t)||/(^|\/|\s)gemini(\s|$)/.test(t)}async function ug(e,{loginShell:t=!1,failOpen:n=!1}={}){let r=await dg(e,{loginShell:t});return r===mc?!0:r===_o?!1:n}async function dg(e,{loginShell:t=!1,timeoutMs:n=od}={}){if(!e)return _o;let r=t?process.env.SHELL||"/bin/sh":"sh",o=t?"-lic":"-c";try{return await we(r,[o,'command -v "$1" >/dev/null 2>&1',"_",e],{timeout:n}),mc}catch(s){return s?.killed||s?.signal?Io:s?.code===1||s?.code===127?_o:Io}}async function hc(e,{retries:t=aI,sleep:n=iI,probe:r=dg}={}){let o=String(e||"").trim().split(/\s+/)[0],s=await r(o,{timeoutMs:od});for(let a=0;s===Io&&a<t.length;a++)await n(t[a]),s=await r(o,{timeoutMs:od*2});return s}function H(...e){return["-S",ft,...e]}async function zn(){if(!pc.existsSync(ft))return!1;try{return await we(F,H("list-sessions")),!0}catch(e){let t=e&&e.stderr?String(e.stderr):"";return!/no server running/i.test(t)}}async function ia(){if(await zn())return!0;try{pc.mkdirSync(ft.replace(/\/[^/]+$/,""),{recursive:!0}),await we(F,H("new-session","-d","-s","keeper","sleep 2147483647"))}catch{}return await zn()}function _e(e){return typeof e=="string"&&cI.test(e)}async function Ot(){if(!pc.existsSync(ft))return[];try{let e="#{session_name}|#{session_windows}|#{session_attached}|#{session_activity}|#{pane_current_path}|#{@bostrat-session}|#{@bostrat-title}|#{@bostrat-sid}|#{@bostrat-agent}|#{alternate_on}|#{session_created}",{stdout:t}=await we(F,H("list-sessions","-F",e)),n=Date.now();return t.trim().split(`
49
+ `).filter(Boolean).map(r=>{let[o,s,a,i,c,l,u,f,d,p,m]=r.split("|"),h=Number(i),g=Number(m);return{name:o,title:u||null,windows:Number(s),attached:Number(a),lastActivityMs:Number.isFinite(h)?n-h*1e3:null,cwd:c||null,isBostrat:l==="1",sessionId:f||null,agent:d||(l==="1"?"claude":null),alternateOn:p==="1",createdMs:Number.isFinite(g)&&g>0?g*1e3:null}}).filter(r=>!oI.has(r.name)&&!r.name.startsWith("bostrat-view-"))}catch{return[]}}async function se(e){return(await Ot()).find(n=>n.name===e)||null}function dI(e){if(typeof e!="string")return!1;let t=e.trim();return t.length>=1&&t.length<=uI&&lI.test(t)}function wc(e){return e.trim().replace(/\s+/g,"-").toLowerCase().replace(/[^A-Za-z0-9_.-]/g,"").replace(/^-+|-+$/g,"")}async function fg(e){try{let{stdout:t}=await we(F,H("list-sessions","-F","#{session_name}"));return t.split(`
50
+ `).map(n=>n.trim()).includes(e)}catch{return!1}}function mI(e){let t=String(e||"").trim().split(/\s+/)[0]||"";if(t.includes("/"))return null;let n=[];for(let o=1;o<=t.length-3;o++)n.push(t.slice(o));if(!n.length)return null;let r=n.map(o=>o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));return new RegExp(`\\b(?:${r.join("|")})`)}async function hI(e,t){let n=Date.now()+ca(),r=mI(t),o=!1,s=0;for(;;){if(await Ro(fI),s+=1,!await fg(e))return;let a=await Te(e,{lines:15}),i=!o&&pI.test(a)&&!!r?.test(a);if(!i&&s>1&&!await fn(e))return;if(i){o=!0,await X({flow:"spawn",phase:"launch-retry",sessionName:e,agent:Vn(t),promptHead:t.slice(0,120)}).catch(()=>{}),await we(F,H("send-keys","-t",e,"C-u")),await we(F,H("send-keys","-t",e,"-l",t)),await we(F,H("send-keys","-t",e,"Enter"));continue}if(Date.now()>n){await X({flow:"spawn",phase:"launch-failed",sessionName:e,agent:Vn(t),retried:o,error:"agent CLI never started after launch was typed"}).catch(()=>{});return}}}async function Jn(e,t=rI,n={}){if(!dI(e))throw new Error("displayName must be 1\u201364 chars (letters, digits, space . _ -)");let r=e.trim(),o=wc(r);if(!_e(o))throw new Error("resulting tmux session name is invalid");if(!await ia())throw new Error(`host tmux server not running on ${ft} and auto-start failed \u2014 start one: ${F} -S ${ft} new-session -d -s keeper "sleep 2147483647"`);if(await fg(o))throw new Error(`tmux session "${o}" already exists`);let s=n.agentCmd||sd,a=n.agent||Vn(s),i=!!n.resumeSessionId,c=n.resumeSessionId||cg(),l=i?s:id(s,c,o),u=i?n.pinned===!0:/(^|\s)--session-id(\s|=)/.test(l),f=a==="claude"&&Cr(s),d=n.firstRun===!0;d||(f&&await Fn(t),a==="codex"&&await go(t),a==="cursor"&&await yo(t),await jw(t),n.freshWorkspace!==!0&&await lc(t));let p=f&&!d?Ki():null,m=aw(),h=["-e",`${Wi}=${m}`];p&&h.push("-e",`ANTHROPIC_API_KEY=${p}`),f&&h.push(...aa());try{await we(F,H("new-session","-d","-s",o,"-c",t,...h))}catch(g){throw fc(p?fc(g,p):g,m)}return await Mr(o),await we(F,H("set-option","-t",o,"@bostrat-session","1")),await we(F,H("set-option","-t",o,"@bostrat-title",r)),await we(F,H("set-option","-t",o,"@bostrat-sid",c)),await we(F,H("set-option","-t",o,"@bostrat-agent",a)),await we(F,H("send-keys","-t",o,l,"Enter")),sI(l)&&hI(o,l).catch(()=>{}),{name:o,title:r,cwd:t,sessionId:c,agent:a,pinned:u,hookToken:m}}async function Ct(e){if(!_e(e))throw new Error("invalid session name");await we(F,H("kill-session","-t",e))}async function pg(e,t){if(_e(e))try{let n=t?H("set-option","-t",e,"@bostrat-sid",t):H("set-option","-u","-t",e,"@bostrat-sid");await we(F,n)}catch{}}async function Te(e,{lines:t=40}={}){if(!_e(e))return"";try{let n=H("capture-pane","-t",e,"-p");Number.isFinite(t)&&t>0&&n.push("-S",`-${Math.floor(t)}`);let{stdout:r}=await we(F,n);return String(r||"")}catch{return""}}async function mg(e){if(!_e(e))return 0;try{let{stdout:t}=await we(F,H("list-clients","-t",e,"-F","1"));return String(t||"").trim().split(`
51
+ `).filter(Boolean).length}catch{return 0}}async function Mr(e,{cols:t=yI,rows:n=bI}={}){if(!_e(e))return!0;if(await mg(e))return!1;try{let r=await hg(e);if(r.cols===t&&r.rows===n)return!0;await we(F,H("resize-window","-t",e,"-x",String(t),"-y",String(n))),await we(F,H("set-window-option","-t",e,"window-size","latest")),await Ro(80)}catch{}return!0}async function kI(e){if(!_e(e))return 0;try{let{stdout:t}=await we(F,H("display-message","-t",e,"-p","#{pane_pid}"));return Number(String(t||"").trim())||0}catch{return 0}}async function fn(e){let t=await kI(e);if(!t)return!1;try{return await we("pgrep",["-P",String(t)]),!1}catch(n){return n?.code===1}}async function hg(e){if(!_e(e))return{cols:0,rows:0};try{let{stdout:t}=await we(F,H("display-message","-t",e,"-p","#{window_width} #{window_height}")),[n,r]=String(t||"").trim().split(/\s+/).map(o=>Number(o)||0);return{cols:n,rows:r}}catch{return{cols:0,rows:0}}}async function gc(e,{cols:t=wI,rows:n=gI}={}){if(_e(e)&&!await mg(e))try{let r=await hg(e),o=Math.max(r.cols,t),s=Math.max(r.rows,n);(o>r.cols||s>r.rows)&&(await we(F,H("resize-window","-t",e,"-x",String(o),"-y",String(s))),await we(F,H("set-window-option","-t",e,"window-size","latest")),await Ro(80))}catch{}}async function pn(e){return await gc(e),Te(e,{lines:je})}async function Ie(e,t,{settleMs:n=40,kind:r}={}){if(!_e(e))throw new Error("invalid session name");let o=(Array.isArray(t)?t:[t]).filter(s=>xI.has(s));for(let s=0;s<o.length;s++)await we(F,H("send-keys","-t",e,o[s])),n>0&&s<o.length-1&&await Ro(n);return X({flow:"tmux",phase:"send-keys",sessionName:e,kind:r||"keys",keys:o.join(" ")}).catch(()=>{}),o.length}async function $o(e,t,{kind:n}={}){if(!_e(e))throw new Error("invalid session name");let r=Math.max(0,Math.floor(Number(t)||0));return r>0&&await we(F,H("send-keys","-t",e,"-N",String(r),"BSpace")),X({flow:"tmux",phase:"send-keys",sessionName:e,kind:n||"wipe",keys:`BSpace x${r}`}).catch(()=>{}),r}async function bc(e,t,{perCharDelayMs:n=120,kind:r}={}){if(!_e(e))throw new Error("invalid session name");let o=[...String(t)];for(let s of o)await we(F,H("send-keys","-t",e,"-l",s)),n>0&&await Ro(n);X({flow:"tmux",phase:"type",sessionName:e,kind:r||"type",textLen:o.length,textHead:String(t).slice(0,120)}).catch(()=>{})}function SI(e,t){return new Promise((n,r)=>{let o=ig(F,H(...e),(s,a,i)=>{s?r(s):n({stdout:a,stderr:i})});o.stdin.on("error",()=>{}),o.stdin.end(t)})}async function vI(e,t){let n=`bostrat-${cg().slice(0,8)}`;await SI(["load-buffer","-b",n,"-"],t),await we(F,H("paste-buffer","-p","-d","-b",n,"-t",e))}async function Le(e,t,{enter:n=!0,submitDelayMs:r=0,kind:o,paste:s=!1}={}){if(!_e(e))throw new Error("invalid session name");if(typeof t=="string"&&t.length>0&&(s?await vI(e,t):await we(F,H("send-keys","-t",e,"-l",t))),n){let a=Number(r);Number.isFinite(a)&&a>0&&await Ro(a),await we(F,H("send-keys","-t",e,"Enter"))}X({flow:"tmux",phase:"send",sessionName:e,kind:o||"text",textLen:typeof t=="string"?t.length:0,textHead:typeof t=="string"?t.slice(0,120):"",enter:n,submitDelayMs:r,...s?{paste:!0}:{}}).catch(()=>{})}var we,F,ag,ft,rI,sd,sa,ad,oI,mc,_o,Io,od,aI,iI,cd,cI,lI,uI,ca,fI,pI,wI,gI,je,yI,bI,xI,yc,Ve=C(()=>{Ks();Vi();zi();Zs();uc();Gt();qs();we=tI(ig);F=process.env.BOSTRAT_TMUX_BIN||"/usr/bin/tmux";ag=typeof process.getuid=="function"?process.getuid():0,ft=nI({explicit:process.env.BOSTRAT_TMUX_SOCKET,legacyExists:(()=>{try{return pc.existsSync(lg(ag))}catch{return!1}})(),runtimeDir:process.env.XDG_RUNTIME_DIR,uid:ag}),rI=process.env.BOSTRAT_DEFAULT_CWD||process.env.HOME||"/",sd=process.env.BOSTRAT_AGENT_CMD||"claude --dangerously-skip-permissions",sa="CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN";ad="bostrat-usage-probe",oI=new Set([ad]);mc="present",_o="absent",Io="unknown",od=5e3,aI=[250,1e3,3e3],iI=e=>new Promise(t=>setTimeout(t,e));cd={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"};cI=/^[A-Za-z0-9_.-]{1,64}$/;lI=/^[A-Za-z0-9 ._↻-]+$/,uI=64;ca=()=>Number(process.env.BOSTRAT_LAUNCH_VERIFY_MS)||12e3,fI=1e3,pI=/not found|Unknown command/i;wI=Number(process.env.BOSTRAT_PROMPT_CAPTURE_COLS)||100,gI=Number(process.env.BOSTRAT_PROMPT_CAPTURE_ROWS)||40,je=Number(process.env.BOSTRAT_PROMPT_CAPTURE_LINES)||80,yI=Number(process.env.BOSTRAT_BOX_COLS)||120,bI=Number(process.env.BOSTRAT_BOX_ROWS)||40;xI=new Set(["Up","Down","Left","Right","Space","Enter","Tab","BTab","Escape","BSpace"]);yc=1600});import la from"node:fs";import RI from"node:fs/promises";import Oo from"node:path";import $I from"node:os";function dd(e){return e.replace(/[^A-Za-z0-9]/g,"-")}function fd(e){let t=Oo.join(ud,dd(e)),n;try{n=la.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return null}let r=null;for(let o of n){let s=Oo.join(t,o);try{let{mtimeMs:a}=la.statSync(s);(!r||a>r.mtimeMs)&&(r={full:s,mtimeMs:a})}catch{}}return r?r.full:null}function Mt(e,t){if(!t)return null;let n=Oo.join(ud,dd(e),`${t}.jsonl`);return la.existsSync(n)?n:null}function Sg(e){if(!e)return[];let t=Oo.join(ud,dd(e)),n;try{n=la.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return[]}let r=[];for(let o of n)try{let s=la.statSync(Oo.join(t,o));r.push({id:o.slice(0,-6),birthMs:s.birthtimeMs||s.ctimeMs||s.mtimeMs})}catch{}return r}async function it(e,t=131072){let n=await RI.open(e,"r");try{let{size:r}=await n.stat(),o=Math.max(0,r-t),s=r-o;if(s===0)return"";let a=Buffer.alloc(s);return await n.read(a,0,s,o),a.toString("utf8")}finally{await n.close()}}function CI(e){let t=e.split(`
52
+ `);for(let n=t.length-1;n>=0;n--){let r=t[n].trim();if(!r||r[0]!=="{")continue;let o;try{o=JSON.parse(r)}catch{continue}let s=o?.message?.usage;if(!s)continue;let a=(s.input_tokens||0)+(s.cache_creation_input_tokens||0)+(s.cache_read_input_tokens||0);if(a>0)return{occupancy:a,model:o.message.model||o.model||null}}return null}async function ua(e,t=null,{fallbackNewest:n=!0}={}){if(!e)return null;let r,o;if(t){if(r=Mt(e,t),o=!0,!r)return null}else if(n){if(r=fd(e),o=!1,!r)return null}else return null;let s;try{s=CI(await it(r))}catch{return null}if(!s)return null;let a=Object.prototype.hasOwnProperty.call(xg,s.model),i=xg[s.model]||OI;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 xg,OI,ud,Nt=C(()=>{xg={"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},OI=2e5,ud=process.env.BOSTRAT_CLAUDE_PROJECTS||Oo.join($I.homedir(),".claude","projects")});function MI(e){let t=[],n="",r=null;for(let o=0;o<e.length;o++){let s=e[o];if(r){n+=s,s===r&&e[o-1]!=="\\"&&(r=null);continue}if(s==="'"||s==='"'||s==="`"){r=s,n+=s;continue}if(s==="&"&&e[o+1]==="&"){t.push(n),n="",o++;continue}if(s==="|"&&e[o+1]==="|"){t.push(n),n="",o++;continue}if(s==="|"||s===";"||s===`
53
+ `){t.push(n),n="";continue}n+=s}return t.push(n),t.map(o=>o.trim()).filter(Boolean)}function da(e){let t=[],n="",r=null,o=!1,s=()=>{if(o){if(/^\d*[<>]/.test(n)||n.startsWith(">")){n="",o=!1;return}t.push(n),n="",o=!1}};for(let a=0;a<e.length;a++){let i=e[a];if(r){i===r&&e[a-1]!=="\\"?r=null:n+=i,o=!0;continue}if(i==="'"||i==='"'){r=i,o=!0;continue}if(i==="<"&&e[a+1]==="<")return s(),t.push("<<"),t;if(/\s/.test(i)){s();continue}n+=i,o=!0}return s(),t}function fa(e){let t=e;for(;t.length&&/^[A-Za-z_][A-Za-z0-9_]*=/.test(t[0]);)t=t.slice(1);for(;t.length&&(t[0]==="sudo"||t[0]==="time"||t[0]==="env");)t=t.slice(1);return t}function xe(e,t=new Set){let n=[];for(let r=1;r<e.length;r++){let o=e[r];if(o==="<<")break;if(Eg(o)){t.has(o)&&r++;continue}n.push(o)}return n}function Ag(e){let t=e.indexOf("-n"),n=t!==-1?e[t+1]:null;if(!n)return null;let r=/^(\d+),(\d+)p$/.exec(n)||/^(\d+)p$/.exec(n);return r?r[2]?{from:r[1],to:r[2]}:{from:r[1],to:r[1]}:null}function DI(e){let t=Ag(e),n=ze(xe(e).find(r=>!/^\d+(,\d+)?p$/.test(r)));return t&&n?t.from===t.to?`Read line ${t.from} of ${Re(n)}`:`Read lines ${t.from}\u2013${t.to} of ${Re(n)}`:e.includes("-i")&&n?`Edit ${Re(n)}`:null}function pd(e){if(e.includes("--files")){let s=ze(xe(e,vg)[0]);return s&&s!=="."?`List files in ${Co(s)}`:"List files"}let t=xe(e,vg),n=t[0];if(!n)return null;let r=ze(t.slice(1).find(s=>s!==".")),o=Mo(n,40);return r?`Search for \u201C${o}\u201D in ${Co(r)}`:`Search for \u201C${o}\u201D`}function md(e){let t=xe(e,new Set(["--prefix"])),n=t[0];return n?n==="test"||n==="t"?"Run tests":n==="run"||n==="run-script"?t[1]?`Run ${t[1]}`:null:n==="ci"||n==="install"||n==="i"||n==="add"?"Install dependencies":null:null}function hd(e,t){if(e.includes("-e")||e.includes("--eval")||e.includes("-c")||e[1]==="-"||e.includes("<<"))return`Run an inline ${t} script`;if(e.includes("--test"))return"Run tests";let n=xe(e)[0];return n?`Run ${Re(n)}`:null}function BI(e){let t=xe(e),n=t[0],r=t.find(a=>/\.(service|timer|socket|target)$/.test(a))||t[1],o=r?r.replace(/\.service$/,""):"a service";return{status:`Check ${o} status`,show:`Inspect ${o}`,restart:`Restart ${o}`,start:`Start ${o}`,stop:`Stop ${o}`,"daemon-reload":"Reload systemd"}[n]||null}function Tg(e){return e.find(t=>/^https?:\/\//.test(t))||null}function FI(e){let t=fa(da(e));if(!t.length)return null;if(/^(ba|z)?sh$/.test(Re(t[0]))&&(t[1]==="-lc"||t[1]==="-c")&&t[2])return wd(t[2]);let n=Re(t[0]);if(LI.has(n))return null;if(t.includes("--version"))return`Check ${n} version`;if(n.endsWith(".sh"))return`Run ${n}`;let r=jI[n];return r?r(t.map((o,s)=>s===0?n:o)):null}function wd(e){let t=String(e||"").trim();if(!t)return null;let n=t.indexOf("<<");if(n!==-1){let i=t.indexOf(`
54
+ `,n);i!==-1&&(t=t.slice(0,i))}let r=MI(t);for(let i=0;i<r.length-1;i++){let c=fa(da(r[i])),l=fa(da(r[i+1]));if(!(!c.length||!l.length)&&["nl","cat"].includes(Re(c[0]))&&Re(l[0])==="sed"){let u=Ag(l),f=xe(c)[0];if(u&&f)return Mo(u.from===u.to?`Read line ${u.from} of ${Re(f)}`:`Read lines ${u.from}\u2013${u.to} of ${Re(f)}`,88)}}let o=[];for(let i of r){let c=FI(i);c&&o.push({d:c,head:Re(fa(da(i))[0]||""),sub:xe(fa(da(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":Mo(s?s.d:o[0].d,88)}var Mo,ze,Re,Co,Eg,vg,NI,PI,jI,LI,_g=C(()=>{Mo=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,ze=e=>e&&!/[$`]/.test(e)?e:null,Re=e=>e.replace(/\/+$/,"").split("/").pop()||e,Co=e=>{let t=e.replace(/\/+$/,"").split("/").filter(Boolean);return t.length>3?t.slice(-2).join("/"):e},Eg=e=>e.startsWith("-"),vg=new Set(["-g","--glob","-t","--type","-A","-B","-C","-m","--max-count","-e","--regexp","-f","--file"]);NI={status:()=>"Check git status",diff:()=>"Review changes",log:()=>"Review commit history",show:()=>"Inspect a commit",add:()=>"Stage files",commit:()=>"Commit changes",push:()=>"Push to remote",pull:()=>"Pull from remote",fetch:()=>"Fetch from remote",merge:()=>"Merge branches",rebase:()=>"Rebase branch",stash:()=>"Stash changes",clone:e=>e[1]?`Clone ${Re(e[1])}`:"Clone repository",checkout:()=>"Switch branches",switch:()=>"Switch branches",restore:()=>"Restore files",reset:()=>"Reset git state",branch:(e,t)=>t.includes("--show-current")?"Check current branch":"List branches",remote:()=>"Check git remotes","rev-parse":()=>"Resolve a git ref",worktree:()=>"Manage git worktrees","merge-base":()=>"Find the merge base","ls-files":()=>"List tracked files"},PI={pr:e=>({create:"Create a pull request",list:"List pull requests",view:"View a pull request",merge:"Merge a pull request",checks:"Check PR status"})[e[1]]||"Run a gh pr command",auth:()=>"Authenticate GitHub CLI",api:()=>"Call the GitHub API",repo:()=>"Inspect the GitHub repo",issue:()=>"Work with GitHub issues"};jI={git:e=>{let t=xe(e,new Set(["-C","-c"])),n=NI[t[0]];return n?n(t,e):null},gh:e=>{let t=xe(e),n=PI[t[0]];return n?n(t):null},sed:DI,rg:pd,grep:pd,egrep:pd,nl:e=>{let t=ze(xe(e)[0]);return t?`Read ${Re(t)}`:null},cat:e=>{let t=ze(xe(e)[0]);return t?`Read ${Re(t)}`:null},head:e=>{let t=ze(xe(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the start of ${Re(t)}`:null},tail:e=>{let t=ze(xe(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the end of ${Re(t)}`:null},wc:e=>{let t=ze(xe(e)[0]);return t?`Count lines in ${Re(t)}`:"Count input lines"},ls:e=>{let t=ze(xe(e)[0]);return t&&t!=="."?`List files in ${Co(t)}`:"List files"},find:e=>ze(e[1])&&!Eg(e[1])&&e[1]!=="."?`Find files in ${Co(e[1])}`:"Find files",tree:()=>"List the directory tree",mkdir:e=>{let t=ze(xe(e)[0]);return t?`Create directory ${Co(t)}`:null},touch:e=>{let t=ze(xe(e)[0]);return t?`Create ${Re(t)}`:null},rm:e=>{let t=ze(xe(e)[0]);return t?`Delete ${Co(t)}`:null},mv:e=>{let t=ze(xe(e)[0]);return t?`Move ${Re(t)}`:null},cp:e=>{let t=ze(xe(e)[0]);return t?`Copy ${Re(t)}`:null},chmod:e=>{let t=ze(xe(e)[1]);return t?`Change permissions on ${Re(t)}`:null},diff:e=>{let t=xe(e);return t.length>=2?`Compare ${Re(t[0])} and ${Re(t[1])}`:null},curl:e=>{let t=Tg(e);return t?`Fetch ${Mo(t,56)}`:"Fetch a URL"},wget:e=>{let t=Tg(e);return t?`Fetch ${Mo(t,56)}`:"Fetch a URL"},npm:md,pnpm:md,yarn:md,npx:e=>{let t=xe(e)[0];return t?`Run ${t}`:null},node:e=>hd(e,"Node"),python:e=>hd(e,"Python"),python3:e=>hd(e,"Python"),make:e=>{let t=xe(e)[0];return t?`Run make ${t}`:"Run make"},systemctl:BI,journalctl:e=>{let t=e.findIndex(r=>r==="-u"||r==="--unit"||r==="--user-unit"),n=t!==-1?e[t+1]:null;return n?`Read ${n.replace(/\.service$/,"")} logs`:"Read system logs"},tmux:e=>{let t=xe(e,new Set(["-S","-L","-t","-f"]))[0];return{ls:"List tmux sessions","list-sessions":"List tmux sessions","kill-session":"Kill a tmux session","send-keys":"Send keys to a tmux session","capture-pane":"Capture a tmux pane","new-session":"Start a tmux session"}[t]||null},ps:()=>"List processes",which:e=>{let t=xe(e)[0];return t?`Locate ${t}`:null},command:e=>e[1]==="-v"&&e[2]?`Locate ${e[2]}`:null,fly:e=>{let t=xe(e)[0];return t==="deploy"?"Deploy to Fly":t?`Run fly ${t}`:null}},LI=new Set(["pwd","echo","cd","sleep","true","false","test","[","set","export","exit","read"])});function No(e){let t=e.split(`
55
+ `).map(n=>n.trim()).find(Boolean)||e;return t.length>88?`${t.slice(0,88).trimEnd()}\u2026`:t}function Xn(e,t=""){let n=t.trim();return n||wd(e)||No(e)}function gd(e,t){if(e){if(Array.isArray(e)){for(let n of e)gd(n,t);return}if(typeof e=="object"){if(e.type==="tool_use"&&yd.has(e.name)){let n=String(e.input?.command||"").trim();n&&t.push({id:e.id||null,tool:e.name,command:n,description:String(e.input?.description||"").trim()})}for(let n of Object.values(e))gd(n,t)}}}async function Ig(e,{maxBytes:t=1048576,limit:n=400}={}){let r;try{r=await it(e,t)}catch{return[]}let o=[];for(let s of r.split(`
56
+ `)){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(gd(c.content,l),!l.length)continue;let u=i.timestamp?Date.parse(i.timestamp):null;for(let f of l)o.push({...f,summary:Xn(f.command,f.description),ts:u})}return o.slice(-n)}function Rg(e,t){let n=t.filter(l=>l.role==="assistant"&&(l.text||"").trim()).sort((l,u)=>(l.ts||0)-(u.ts||0)),r=[...e].sort((l,u)=>(l.ts||0)-(u.ts||0)),o=[],s=0,a=0,i=l=>{let u=l.n??a+1;return u>a&&(a=u),u};for(let l of n){let u=r.findIndex((m,h)=>h>=s&&(m.ts||0)>(l.ts||0)),f=u===-1?r.length:u,d=r.slice(s,f);if(s=f,!d.length)continue;let p=d.map(m=>({...m,n:i(m)}));o.push({id:`batch-${l.ts}-${l.box}`,anchorTs:l.ts,anchorBox:l.box,agent:l.agent,boxRole:l.boxRole,commands:p,ts:Math.max(...p.map(m=>m.ts||0)),pending:!1})}let c=r.slice(s);if(c.length){let l=c.map(u=>({...u,n:i(u)}));o.push({id:`batch-pending-${l[0]?.box||"lead"}`,anchorTs:null,anchorBox:l[l.length-1]?.box??null,agent:l[l.length-1]?.agent??"claude",boxRole:l[l.length-1]?.boxRole??"lead",commands:l,ts:Math.max(...l.map(u=>u.ts||0)),pending:!0})}return o}var yd,Po=C(()=>{Nt();_g();yd=new Set(["Bash"])});import $g from"node:fs";import kd from"node:fs/promises";import bd from"node:path";import UI from"node:os";async function Og(e){try{return await kd.realpath(e)}catch{return e}}function WI(e=HI){let t=[],n=r=>{let o;try{o=$g.readdirSync(r,{withFileTypes:!0})}catch{return}for(let s of o){let a=bd.join(r,s.name);if(s.isDirectory())n(a);else if(s.isFile()&&s.name.startsWith("rollout-")&&s.name.endsWith(".jsonl")){let i=/-([0-9a-f-]{36})\.jsonl$/i.exec(s.name);try{t.push({id:i?i[1]:null,file:a,mtimeMs:$g.statSync(a).mtimeMs})}catch{}}}};return n(e),t.sort((r,o)=>o.mtimeMs-r.mtimeMs)}async function qI(e,t=1048576){let n;try{n=await kd.open(e,"r")}catch{return""}try{let r=Buffer.alloc(Math.min(t,65536)),o="",s=0;for(;;){let{bytesRead:a}=await n.read(r,0,r.length,s);if(!a)break;o+=r.toString("utf8",0,a);let i=o.indexOf(`
57
+ `);if(i!==-1)return o.slice(0,i);if(s+=a,o.length>=t)break}return o}finally{await n.close()}}async function KI(e){let t=await qI(e);if(!t)return null;let n;try{n=JSON.parse(t)}catch{return null}return n?.type==="session_meta"&&n?.payload?.cwd||null}async function Nr(e,t){if(!e&&!t)return null;let n=WI();if(t){let o=n.find(s=>s.id===t);return o||null}let r=await Og(e);for(let o of n){let s=await KI(o.file);if(s&&(s===e||await Og(s)===r))return o}return null}async function Cg(e,t,{limit:n=80,maxBytes:r=524288}={}){let o=await Nr(e,t);if(!o)return[];let s;try{s=await it(o.file,r)}catch{return[]}let a=[],i=null,c=[],l=!1,u=!1,f=null;for(let d of s.split(`
58
+ `)){let p=d.trim();if(!p||p[0]!=="{")continue;let m;try{m=JSON.parse(p)}catch{continue}if((m.type==="turn_context"&&m.payload?.model||m.type==="session_meta"&&m.payload?.model)&&(i=m.payload.model),m.type==="event_msg"){let k=m.payload?.type;k==="task_started"?(l=!0,u=!1,f=m.payload?.turn_id||null):k==="task_complete"&&l&&(l=!1,!u&&m.payload?.last_agent_message==null&&a.push({role:"assistant",failed:!0,text:Pr,sourceId:m.payload?.turn_id||f||void 0,ts:m.timestamp?Date.parse(m.timestamp):null,model:i}));continue}if(m.type!=="response_item")continue;let h=m.payload;if(!h)continue;if((h.type==="function_call"||h.type==="custom_tool_call")&&h.name){u=!0,xd.has(h.name)||c.push(h.name);continue}if(h.type!=="message"||h.role!=="assistant")continue;u=!0;let g=VI(h.content),x=c.length?c.slice():null;c=[],!(!g&&!x)&&a.push({role:"assistant",text:g,tools:x||void 0,ts:m.timestamp?Date.parse(m.timestamp):null,model:i})}if(i)for(let d of a)d.model||(d.model=i);return a.slice(-n)}function zI(e){if(typeof e?.cmd=="string"&&e.cmd.trim())return e.cmd.trim();let t=e?.command;return typeof t=="string"&&t.trim()?t.trim():Array.isArray(t)&&t.length?t.length===3&&/^(ba)?sh$/.test(t[0])&&t[1]==="-lc"?String(t[2]).trim():t.map(String).join(" ").trim():null}function JI(e){let t=e[0];if(t!=='"'&&t!=="'"&&t!=="`")return null;let n="";for(let r=1;r<e.length;r++){let o=e[r];if(o==="\\"){let s=e[++r];if(s===void 0)return null;if(s==="n")n+=`
59
+ `;else if(s==="t")n+=" ";else if(s==="r")n+="\r";else if(s==="u")if(e[r+1]==="{"){let a=e.indexOf("}",r+2);if(a===-1)return null;n+=String.fromCodePoint(parseInt(e.slice(r+2,a),16)),r=a}else n+=String.fromCharCode(parseInt(e.slice(r+1,r+5),16)),r+=4;else n+=s}else{if(o===t)return n;if(t==="`"&&o==="$"&&e[r+1]==="{")return null;n+=o}}return null}function XI(e){let t=String(e||""),n=[],r=/exec_command\s*\(/g;for(let s;s=r.exec(t);)n.push(s.index+s[0].length);let o=[];return n.forEach((s,a)=>{let i=t.slice(s,a+1<n.length?n[a+1]:t.length),c=/(?:^|[{,\s])["'`]?cmd["'`]?\s*:\s*/.exec(i);if(!c)return;let l=JI(i.slice(c.index+c[0].length).trimStart());l&&l.trim()&&o.push(l.trim())}),o}async function Mg(e,t,{limit:n=400,maxBytes:r=524288}={}){let o=await Nr(e,t);if(!o)return[];let s;try{s=await it(o.file,r)}catch{return[]}let a=[];for(let i of s.split(`
60
+ `)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.type!=="response_item")continue;let u=l.payload;if(!u)continue;let f=[];if(u.type==="function_call"&&pa.has(u.name)){let p;try{p=JSON.parse(u.arguments||"{}")}catch{continue}let m=zI(p);m&&(f=[m])}else u.type==="custom_tool_call"&&u.name==="exec"&&(f=XI(u.input));if(!f.length)continue;let d=u.call_id||u.id||null;f.forEach((p,m)=>{a.push({id:d?m?`${d}:${m}`:d:null,tool:u.name,command:p,description:"",summary:Xn(p),ts:l.timestamp?Date.parse(l.timestamp):null})})}return a.slice(-n)}async function Ng(e,t){let n=await Nr(e,t);if(!n)return null;try{return Math.round((await kd.stat(n.file)).mtimeMs)}catch{return n.mtimeMs||null}}var HI,GI,VI,pa,xd,Pr,Dr=C(()=>{Nt();Po();HI=process.env.BOSTRAT_CODEX_SESSIONS||bd.join(process.env.CODEX_HOME||bd.join(UI.homedir(),".codex"),"sessions");GI=new Set(["output_text","text"]),VI=e=>typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&typeof t.text=="string"&&GI.has(t.type)).map(t=>t.text).join(`
61
+ `).trim():"";pa=new Set(["exec_command","shell","exec"]),xd=new Set(["wait","write_stdin"]),Pr="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 ma({error:e=null,status:t=null,text:n=""}={}){let r=String(e||"").trim().toLowerCase();if(r&&Pg.has(r))return Pg.get(r);let o=Number(t)||0;if(o===401)return"auth";if(o===403)return"entitlement";if(o===429)return"rate_limit";if(o===529)return"overloaded";if(o>=500)return"server";let s=String(n||"").toLowerCase();return/overloaded/.test(s)?"overloaded":/rate limit|too many requests|quota|usage limit/.test(s)?"rate_limit":/billing|subscription|not allowed|disabled .* access|upgrade your plan|no credits/.test(s)?"entitlement":/log ?in|authenticat|expired|invalid.*key|unauthorized/.test(s)?"auth":/server|internal error|5\d\d/.test(s)?"server":"other"}function Dg(e){if(!e||e.role!=="assistant")return null;if(e.apiError){let t=e.apiError;return{cls:t.cls||ma({error:t.code,status:t.status,text:e.text}),code:t.code||null,status:t.status||null,requestId:t.requestId||null}}if(e.failed){let t=String(e.text||"");return{cls:t===Pr?"other":ma({text:t}),code:null,status:null,requestId:null}}return null}function Bg(e,{codexFailedText:t=null}={}){let n=String(e?.text||"").trim();return n?e?.model==="<synthetic>"?/^No response requested\.$/.test(n)?null:{cls:ma({text:n}),code:null,status:YI(n),requestId:null,text:n}:t&&n===t?{cls:"other",code:null,status:null,requestId:null,text:n}:null:null}function YI(e){let t=/^API Error:\s*(\d{3})\b/.exec(e);return t?Number(t[1]):null}var I2,Pg,xc=C(()=>{Dr();I2=Object.freeze(["entitlement","auth","rate_limit","overloaded","server","other"]),Pg=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 ZI(e,t){return!e||!t?null:Mt(e,t)}function QI(e){return typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&t.type==="text"&&typeof t.text=="string").map(t=>t.text).join(`
62
+ `).trim():""}function eR(e){if(!Array.isArray(e))return null;let t=e.filter(n=>n&&n.type==="tool_use").map(n=>n.name).filter(Boolean);return t.length?t:null}function tR(e){return Array.isArray(e)&&e.length>0&&e.every(t=>t&&t.type==="tool_result")}function Sd(e){let t=[],n=e?.message?.content;if(!Array.isArray(n))return t;for(let r of n)if(r){if(r.type==="image"&&r.source?.type==="base64"&&r.source.data)t.push({mediaType:r.source.media_type||"image/png",data:r.source.data,toolUseId:null});else if(r.type==="tool_result"&&Array.isArray(r.content))for(let o of r.content)o?.type==="image"&&o.source?.type==="base64"&&o.source.data&&t.push({mediaType:o.source.media_type||"image/png",data:o.source.data,toolUseId:r.tool_use_id||null})}return t}function jg(e,t){if(!e.uuid)return null;let n=Sd(e).map((r,o)=>({uuid:e.uuid,index:o,mediaType:r.mediaType,name:r.toolUseId&&t.get(r.toolUseId)||null}));return n.length?n:null}async function vd(e,{maxBytes:t=524288,limit:n=80}={}){let r;try{r=await it(e,t)}catch{return[]}let o=[],s=new Map;for(let a of r.split(`
63
+ `)){let i=a.trim();if(!i||i[0]!=="{")continue;let c;try{c=JSON.parse(i)}catch{continue}if(c.type==="attachment"){let h=c.attachment;h?.type==="queued_command"&&h.commandMode==="task-notification"&&typeof h.prompt=="string"&&h.prompt.trim()&&o.push({role:"user",text:h.prompt.trim(),ts:c.timestamp?Date.parse(c.timestamp):null,model:null});continue}let l=c.message;if(!l)continue;let u=l.role||c.type;if(u!=="user"&&u!=="assistant"||u==="assistant"&&l.model==="<synthetic>"&&!c.isApiErrorMessage)continue;if(u==="assistant"&&Array.isArray(l.content))for(let h of l.content){let g=h?.type==="tool_use"?h.input?.file_path||h.input?.path:null;typeof g=="string"&&nR.test(g)&&s.set(h.id,g.split("/").pop())}if(tR(l.content)){let h=jg(c,s);h&&o.push({role:"assistant",text:"",images:h,ts:c.timestamp?Date.parse(c.timestamp):null,model:null});continue}let f=QI(l.content),d=u==="assistant"?eR(l.content):null,p=u==="user"?jg(c,s):null;if(!f&&!d&&!p)continue;let m=u==="assistant"&&c.isApiErrorMessage?{code:typeof c.error=="string"?c.error:null,status:Number(c.apiErrorStatus)||null,requestId:c.requestId||null,cls:ma({error:c.error,status:c.apiErrorStatus,text:f})}:null;o.push({role:u,text:f,tools:d||void 0,images:p||void 0,ts:c.timestamp?Date.parse(c.timestamp):null,model:l.model||null,apiError:m||void 0})}return o.slice(-n)}async function Lg(e,t,{turns:n=16}={}){let r=ZI(e,t);if(!r)return"";let o=await vd(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}:** ${rR(s.text||c,700)} ${i}`.trim()}).join(`
64
+
65
+ `):""}var nR,rR,Sc=C(()=>{xc();Nt();nR=/\.(png|jpe?g|gif|webp|bmp|svg|tiff?|avif|heic|heif|ico)$/i;rR=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e});import oR from"node:fs/promises";import{execFile as sR}from"node:child_process";import{promisify as aR}from"node:util";function Wg(e){Ed=typeof e=="function"?e:null}function Ad(e){let t=String(e||""),n=t.indexOf("/lib/node_modules/");return n>0?t.slice(0,n):null}function qg({sessionName:e,from:t,to:n}={}){let r=String(n||"").trim();!r||Fg.has(r)||(Fg.add(r),Ug=Ug.then(()=>cR({sessionName:e,from:t,to:r})).catch(()=>{}))}async function cR({sessionName:e,from:t,to:n}){await X({flow:"codex-update",phase:"start",sessionName:e,from:t,to:n}).catch(()=>{});try{let r=(await Td("/bin/sh",["-c","command -v codex"])).stdout.trim();if(!r)throw new Error("codex not on PATH");let o=await oR.realpath(r),s=Ad(o),a=s?{...process.env,PATH:`${s}/bin:${process.env.PATH||""}`}:process.env;await Td("npm",["install","-g","@openai/codex"],{env:a,timeout:iR});let i=(await Td(r,["--version"])).stdout.trim().replace(/^codex-cli\s*/,"")||n;await X({flow:"codex-update",phase:"done",sessionName:e,from:t,to:n,version:i}).catch(()=>{}),await Hg({sessionName:e,from:t,to:n,version:i,status:"updated"})}catch(r){let o=String(r?.message||r).slice(0,300);await X({flow:"codex-update",phase:"failed",sessionName:e,from:t,to:n,error:o}).catch(()=>{}),await Hg({sessionName:e,from:t,to:n,status:"failed",error:o})}}async function Hg(e){if(Ed)try{await Ed(e)}catch{}}var Td,iR,Fg,Ug,Ed,vc=C(()=>{Gt();Td=aR(sR),iR=Number(process.env.BOSTRAT_CODEX_UPDATE_TIMEOUT_MS)||5*6e4,Fg=new Set,Ug=Promise.resolve(),Ed=null});function uR(e,{provider:t,box:n}){let r=String(e).replace(/\r/g,"").split(`
66
+ `);if(!Kg.test(e))return null;let o=[],s=!1;for(let l=r.length-1;l>=0;l--){let u=r[l].match(lR);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"&&Kg.test(a)?a:"The agent is asking for approval";return{provider:t,box:n,promptId:`${t}:${c}:${i.map(l=>l.label).join("|")}`.slice(0,200),questions:[{question:c,header:"Approval",multiSelect:!1,options:i.map(l=>({label:l.label,description:""}))}]}}function Br(e){let t=String(e??"").replace(/\r/g,""),n=t.split(`
67
+ `);for(let r=n.length-1;r>=0;r--)if(zg.test(n[r]))return n.slice(r).join(`
68
+ `);return t}function dR(e){let t=String(e).trim();if(!t)return!1;let n=(t.match(/[A-Za-z]/g)||[]).length;return n>=3&&n/t.length>=.5}function fR(e){return/device code/i.test(e)?"works from the device you're reading this on":/sign in with chatgpt/i.test(e)?"opens a browser link on the node itself \u2014 can't finish from another device":""}function pR(e,t=""){let n=Br(e);if(ha.test(n)||!/Sign in with ChatGPT/.test(n)||!/Press enter to continue/.test(n))return null;let r=n.split(`
69
+ `),o=[],s=-1;for(let l=0;l<r.length;l++){let u=r[l].match(Gg);if(!u)continue;s<0&&(s=l);let f="";for(let d=l+1;d<Math.min(l+3,r.length);d++){let p=r[d].trim();if(p){if(Gg.test(r[d])||/^Press enter/.test(p))break;f=p;break}}o.push({n:Number(u[2]),cursor:!!u[1],label:u[3].trim(),desc:f})}let a=o.sort((l,u)=>l.n-u.n);if(a.length<2||a.some((l,u)=>l.n!==u+1)||!a.some(l=>/Sign in with ChatGPT/.test(l.label)))return null;let i=[];for(let l=0;l<s;l++){let u=r[l].trim();u&&!zg.test(r[l])&&dR(u)&&i.push(u)}let c=i.join(" ").slice(0,400)||"Codex isn't signed in on this box \u2014 choose a sign-in method";return{provider:"codex",box:t,multiSelect:!1,cursorIndex:Math.max(0,a.findIndex(l=>l.cursor)),answerMode:"keys",promptId:`codex:signin:${a.map(l=>l.label).join("|")}`.slice(0,200),questions:[{question:c,header:"Sign in",multiSelect:!1,options:a.map(l=>{let u=fR(l.label);return{label:l.label,description:[l.desc,u].filter(Boolean).join(" \xB7 ")}})}]}}function wR(e,t=""){let n=Br(e);if(ha.test(n)||!mR.test(n))return null;let r=n.trimEnd().split(`
70
+ `).pop()||"";return hR.test(r)?{provider:"codex",box:t,multiSelect:!1,cursorIndex:0,answerMode:"keys",promptId:"codex:signin-complete",questions:[{question:"Codex successfully signed in and is waiting to open the session.",header:"Signed in",multiSelect:!1,options:[{label:"Continue",description:""}]}]}:null}function yR(e,t=""){let n=Br(e);if(ha.test(n)||!Vg.test(n))return null;let r=n.split(`
71
+ `),o=r.findIndex(i=>Vg.test(i)),s="";for(let i=o+1;i<r.length;i++){let c=r[i].match(gR);if(c){s=c[1];break}}if(!s)return null;let a=(n.match(/https:\/\/\S+/)||[])[0]||"https://auth.openai.com/codex/device";return{provider:"codex",box:t,multiSelect:!1,cursorIndex:0,answerMode:"esc",promptId:`codex:device-code:${s}`,questions:[{question:`Codex is waiting for you to finish signing in: open ${a} and enter code ${s} (expires in 15 minutes). The code goes straight to OpenAI \u2014 bostrat never sees your login. This card clears once OpenAI confirms.`,header:"Sign in",multiSelect:!1,options:[{label:"Cancel sign-in",description:"Go back to the sign-in options"}]}]}}function bR(e,t=""){let n=Br(e);return ha.test(n)||!/open the following link to authenticate/.test(n)?null:{provider:"codex",box:t,multiSelect:!1,cursorIndex:0,answerMode:"esc",promptId:"codex:signin-browser",questions:[{question:"Codex started its browser sign-in, which opens on the box itself and can't complete from another device. Go back and choose \u201CSign in with Device Code\u201D instead.",header:"Sign in",multiSelect:!1,options:[{label:"Go back to sign-in options",description:""}]}]}}function kR(e,t=""){let n=Br(e);return ha.test(n)||!/Paste or type your API key/.test(n)?null:{provider:"codex",box:t,multiSelect:!1,cursorIndex:0,answerMode:"esc",promptId:"codex:signin-apikey",questions:[{question:"Codex is asking for an OpenAI API key. For safety a key can only be typed in the Terminal tab, never through chat. To use your ChatGPT subscription instead, go back and pick a sign-in option.",header:"Sign in",multiSelect:!1,options:[{label:"Go back to sign-in options",description:""}]}]}}function xR(e,t=""){let n=String(e);if(!/Press any key to log in/.test(n)||_d.test(n))return null;let r=n.replace(/\r/g,"").split(`
72
+ `).map(a=>a.trim()),o=r.findIndex(a=>/Press any key to log in/.test(a)),s=r.slice(0,o<0?r.length:o).filter(a=>a&&!/^Cursor Agent$/i.test(a)&&!/^v?\d{4}\.\d{2}\.\d{2}/.test(a)).join(" ");return{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,answerMode:"keys",promptId:"cursor:signin-start",questions:[{question:(s?`${s} `:"")+"Cursor isn't signed in on this box \u2014 start the sign-in to get a login link you can open from any device.",header:"Sign in",multiSelect:!1,options:[{label:"Start sign-in",description:"Shows a login link (and a QR option) \u2014 your login goes to cursor.com, never through bostrat"}]}]}}function vR(e,t=""){let n=String(e);if(!SR.test(n)||_d.test(n))return null;let r=n.replace(/\r/g,"").split(`
73
+ `),o="",s=r.findIndex(a=>/https:\/\//.test(a));if(s>=0){o=r[s].slice(r[s].indexOf("https://")).trim();for(let a=s+1;a<r.length;a++){let i=r[a].trim();if(!i||!/^[A-Za-z0-9~%&=?/_.-]+$/.test(i))break;o+=i}}return{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,promptId:`cursor:signin-link:${(o.match(/[?&]challenge=([\w-]+)/)||[])[1]?.slice(0,16)||o.slice(-24)||"pending"}`,questions:[{question:o?`Cursor is waiting for you to finish signing in: open ${o} on any device and log in. Your login goes straight to cursor.com \u2014 bostrat never sees it. This card clears once sign-in completes.`:"Cursor is waiting for you to finish signing in \u2014 open the login link shown in the Terminal tab. This card clears once sign-in completes.",header:"Sign in",multiSelect:!1,options:[]}]}}function TR(e,t=""){let n=String(e);return!/Scan this QR code to log in/.test(n)||_d.test(n)?null:{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,promptId:"cursor:signin-qr",questions:[{question:"Cursor is showing a QR sign-in code in the Terminal tab \u2014 scan it from another device to log in. This card clears once sign-in completes.",header:"Sign in",multiSelect:!1,options:[]}]}}function Jg(e,t,n=""){if(e!=="cursor"&&e!=="codex")return null;if(e==="codex"){let r=wR(t,n)||yR(t,n)||bR(t,n)||kR(t,n)||pR(t,n);if(r)return r}if(e==="cursor"){let r=vR(t,n)||TR(t,n)||xR(t,n);if(r)return r}return uR(t,{provider:e,box:n})}function Xg(e,t){let n=Array.isArray(t?.[0])?t[0]:[],o=(Number.isInteger(n[0])&&n[0]>=0?n[0]:0)+1;return String(o)}var lR,Kg,ha,zg,Gg,mR,hR,Vg,gR,_d,SR,Tc=C(()=>{lR=/^\s*[›>*\-❯]?\s*(\d+)[.)]\s+(.+?)\s*$/,Kg=/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i;ha=/(^|\n)\s*›/,zg=/^\s*Welcome to Codex\b/;Gg=/^\s*(>)?\s*(\d+)\.\s+(.+?)\s*$/;mR=/Successfully logged in\./,hR=/^\s*Press Enter to continue\.\s*$/;Vg=/Enter this one-time code/,gR=/^\s*([A-Z0-9]{2,10}-[A-Z0-9]{2,10})\s*$/;_d=/Run Everything|Add a follow-up|Plan, search, build anything/;SR=/click this link to log in|Signing in with the browser/});function IR(e){let t=String(e||"").replace(/\r/g,"").split(`
74
+ `),n=-1;for(let s=t.length-1;s>=0;s--)if(t[s].trim()){n=s;break}if(n<0)return!1;let r=t[n];if(AR.test(r)||_R.test(r)){for(let s=n-1;s>=0&&n-s<=64;s--)if(/^\s*›/.test(t[s]))return!0}return/esc to interrupt|\bWorking \(/.test(String(e||""))}function MR(e){let t=String(e||"");if(!Ne.codex.block.test(t))return null;let n=Br(t);if(!Ne.codex.block.test(n))return null;let r=n.match(CR);return{from:r?.[1]||null,to:r?.[2]||null}}function Vt(e){return new Promise(t=>setTimeout(t,e))}function Id(e,t){let n=Date.now(),r=NR();for(let[s,a]of Ac)n-a>=r&&Ac.delete(s);let o=`${e}::${t}`;return Ac.has(o)?!1:(Ac.set(o,n),!0)}function ey(e,t){if(e?.busyScope!=="footer")return t;let n=String(t||"").split(`
75
+ `),r=-1;for(let o=n.length-1;o>=0;o--)if(Qg.test(n[o])){r=o;break}return r<0?t:n.slice(r+1).join(`
76
+ `)}function DR(e){let t=0;for(let n of String(e).split(`
77
+ `))Qg.test(n)&&(t=Math.max(t,n.trimEnd().length));return t}function Rd(e,t){let n=Ne[e];if(!n?.busy)return{state:"idle",reason:null};if(Od(e,t))return{state:"unknown",reason:"blocked"};if(n.up&&!n.up.test(t))return{state:"idle",reason:null};if(n.busy.test(ey(n,t)))return{state:"busy",reason:null};if(n.busyAlt&&n.busyAlt.test(t))return{state:"busy",reason:null};let r=DR(t);return e==="claude"&&r>0&&r<PR?{state:"unknown",reason:"narrow"}:{state:"idle",reason:null}}function $d(e,t){return Rd(e,t).state}function ty(e,t){if(e!=="claude")return!1;let n=String(t||"").split(`
78
+ `).slice(-jR).join(`
79
+ `);return BR.test(n)}function Bo(e,t){return $d(e,t)==="busy"}function _c(e,t){return $d(e,t)!=="idle"}function jo(e,t){let n=Ne[e];return n?.up?n.up.test(t):!0}function LR(e,t){let n=Ne[e];return n?Od(e,t)?!1:n.up.test(t)&&$d(e,t)==="idle":!0}function Od(e,t){let n=Ne[e];return n?n.auth?.test(t)&&!n.up.test(t)?!0:n.block?.test(t)?e==="codex"?!0:!n.up.test(t):!1:!1}function Cd(e,t){let n=String(t||"").trim();if(!n)return e;let r=String(e||"").split(`
77
80
  `);for(let o=r.length-1;o>=0;o--)if(r[o].includes(n))return r.slice(o+1).join(`
78
- `);return e}function Jg(e){let t=String(e||"").trim();return t?t.slice(0,32):null}function Gg(e){let t=new Error(`${e} isn't running in this box \u2014 its pane is sitting at a bare shell (the launch command was likely swallowed at shell startup, or the CLI exited). Relaunch it from the Terminal tab, or stop and reopen the box, then send again.`);return t.code="cli-not-running",t}async function Vg(e,t,n,{bailOnDialog:r=!1,launchEcho:o=null}={}){let s=Date.now()+n,a=0,i=null;for(await Nr(e).catch(()=>{});;){let c=Id(await Ae(e),o);if(IR(t,c)){await Yn(fa);return}if(Be[t]?.up&&!Be[t].up.test(c))if(await dn(e)){if(i??=Date.now(),Date.now()-i>=oa()){let l=Gg(t);throw Y({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:e,agent:t,timeoutMs:n,gateAccepts:a,idleMs:Date.now()-i,error:l.message}).catch(()=>{}),l}}else i=null;else i=null;if(r&&t==="claude"&&bR.test(c)&&!Be.claude.up.test(c)){Y({flow:"agent-ready",phase:"dialog",sessionName:e,agent:t,dialog:"resume-confirm"}).catch(()=>{});return}if(t==="cursor"&&yR.test(c)&&!Be.cursor.up.test(c)&&a<3){if(!Kg(e,"cursor-trust")){await Yn(Td);continue}a+=1,await Y({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:a}).catch(()=>{}),await Fe(e,"a",{enter:!1,kind:"cursor-trust-accept"}),await Yn(fa);continue}if(t==="codex"&&a<3){let l=xR(c);if(l){if(!Kg(e,`codex-update:${l.from}->${l.to}`)){await Yn(Td);continue}a+=1,await Y({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:a,update:`${l.from} -> ${l.to}`}).catch(()=>{}),await Fe(e,"3",{enter:!1,kind:"codex-update-skip"}),jg({sessionName:e,from:l.from,to:l.to}),await Yn(fa);continue}}if(Date.now()>s){if(_d(t,c)){let l=`${t} is blocked on an interactive prompt`;throw t==="codex"?l=Be.codex.auth.test(c)?"codex isn't signed in on this box \u2014 answer the Sign in card in chat (Device Code works from any device) or finish signing in from the Terminal tab, then send again":"codex is stuck on its update prompt (auto-skip didn't clear it) \u2014 open the terminal and choose Skip, then send again":t==="cursor"&&Be.cursor.auth.test(c)?l="cursor isn't signed in on this box \u2014 answer the Sign in card in chat (the login link works from any device) or finish signing in from the Terminal tab, then send again":t==="claude"&&Be.claude.auth.test(c)?l="claude isn't signed in on this box \u2014 answer the setup cards in chat (or finish signing in from the Terminal tab), then send again":t==="claude"&&Be.claude.block.test(c)&&(l='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'),Y({flow:"agent-ready",phase:"blocked",sessionName:e,agent:t,timeoutMs:n,gateAccepts:a,error:l}).catch(()=>{}),new Error(l)}if(await dn(e)){let l=Gg(t);throw Y({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:e,agent:t,timeoutMs:n,gateAccepts:a,error:l.message}).catch(()=>{}),l}console.warn(`[agent-ready] ${t} readiness unconfirmed in ${e} after ${n}ms \u2014 driving the box anyway.`),Y({flow:"agent-ready",phase:"timeout",sessionName:e,agent:t,timeoutMs:n,gateAccepts:a,paneBlocked:!!Be[t]?.block?.test(c),paneUp:!!Be[t]?.up?.test(c),paneBusy:!!Be[t]?.busy?.test(c)}).catch(()=>{}),await Yn(fa);return}await Yn(Td)}}function Yg({agent:e,agentCmd:t}={}){let n=t?Gn(t):Gn(e||"");return{label:n,realClaude:t?Mr(t):n==="claude",realCodex:t?/codex/.test(t)&&!/fake-codex|fake-lead/.test(t):n==="codex",realCursor:t?/cursor/.test(t)&&!/fake-cursor|fake-box/.test(t):n==="cursor"}}function ma({cwd:e,sessionName:t,agent:n,agentCmd:r}={}){let{realCodex:o,realCursor:s}=Yg({agent:n,agentCmd:r});return!t||!o&&!s?null:Xn({cwd:e,sessionName:t,agent:n,agentCmd:r}).catch(()=>{})}async function Xn({cwd:e,sessionId:t,sessionName:n,agent:r,agentCmd:o,timeoutMs:s=gR(),bailOnDialog:a=!1,launchEcho:i=null}={}){let{label:c,realClaude:l,realCodex:u,realCursor:f}=Yg({agent:r,agentCmd:o});if(l&&e&&await Ln(e),u&&e&&await go(e),f&&e&&await yo(e),(l||u||f)&&n){await Vg(n,c,s,{bailOnDialog:a,launchEcho:i});return}let d=Be[r]?r:Be[c]?c:null;if(process.env.BOSTRAT_FAKE_POLL_READY==="1"&&n&&d){await Vg(n,d,s,{launchEcho:i});return}await Yn(fa)}var gR,Td,fa,Be,yR,bR,kR,SR,xc,vR,TR,AR,_R,Tc=O(()=>{tt();Us();Wi();qi();bc();kc();un();gR=()=>Number(process.env.BOSTRAT_AGENT_READY_TIMEOUT_MS)||9e4,Td=Number(process.env.BOSTRAT_AGENT_READY_POLL_MS)||500,fa=Number(process.env.BOSTRAT_AGENT_READY_SETTLE_MS)||800,Be={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/}},yR=/Trust this workspace|\[a\]\s*Trust/,bR=/Resume from summary/i,kR=/Update available!\s*([\d][\w.-]*)\s*->\s*([\d][\w.-]*)/;SR=()=>Number(process.env.BOSTRAT_GATE_RESEND_MS)||3e3,xc=new Map;vR=68,TR=/^\s*[─━]{10,}\s*$/;AR=/\bWaiting for \d+\b[^\n]*\bto finish\b|\/workflows to (?:stop|monitor)\b/,_R=15});function CR(e){return typeof e!="string"||!e?!1:e.includes(`
79
- `)?!0:Buffer.byteLength(e,"utf8")>=OR}function Gt(e,t){return e==="codex"?{enter:!0,submitDelayMs:RR,...CR(t)?{paste:!0}:{}}:e==="claude"?{enter:!0,submitDelayMs:$R}:{enter:!0}}var RR,$R,OR,ha=O(()=>{RR=(()=>{let e=Number(process.env.BOSTRAT_CODEX_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),$R=(()=>{let e=Number(process.env.BOSTRAT_CLAUDE_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),OR=(()=>{let e=Number(process.env.BOSTRAT_CODEX_PASTE_MIN_BYTES??512);return Number.isFinite(e)&&e>=0?e:512})()});function Lr(e){let t=String(e||"").toLowerCase();if(!t.trim())return null;let n=null;for(let r of MR){let o=0;for(let s of NR[r])s.test(t)&&o++;o>0&&(!n||o>n.score)&&(n={category:r,score:o})}return n}function Xg(e){let t=0,n=0;for(let[r,o]of Object.entries(e||{}))PR.has(r)&&(t+=o||0),DR.has(r)&&(n+=o||0);return t>=5&&n===0?{category:"research",score:1}:n>=3?{category:"feature-build",score:1}:null}function wa(e){return String(e||"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").replace(/[-_/]+/g," ")}var MR,NR,PR,DR,Rd=O(()=>{MR=["bug-fix","orchestration","design","ops-infra","docs-writing","research","feature-build"],NR={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/]};PR=new Set(["Read","Grep","Glob","LS","WebSearch","WebFetch","NotebookRead"]),DR=new Set(["Edit","Write","MultiEdit","NotebookEdit"])});function ty(e){let t=wa(String(e||"")).toLowerCase(),n=[];for(let r of t.split(/[^a-z0-9]+/))r.length<2||BR.has(r)||n.push(r);return n}function jR(e){let t=[];for(let n of e||[]){let r=n.payload||{},o=String(r.text||"").trim();if(n.type==="turn.user"){if(n.source==="hook"||!o)continue;t.push(ey(n,"user",o))}else if(n.type==="turn.agent"){if(!o)continue;t.push(ey(n,"assistant",o))}}return t}function ey(e,t,n){let r=Lr(n);return{id:e.id,seq:e.seq,ts:e.payload?.ts??e.ts,role:t,boxId:e.boxId??null,provider:e.provider??null,text:n,tags:r?[r.category]:[]}}function ga(e){let t=jR(e),n=new Map,r=new Array(t.length).fill(0),o=0;t.forEach((a,i)=>{let c=ty(a.text);r[i]=c.length,o+=c.length;let l=new Map;for(let u of c)l.set(u,(l.get(u)||0)+1);for(let[u,f]of l){let d=n.get(u);d||n.set(u,d=new Map),d.set(i,f)}});let s=t.length;return{chunks:t,postings:n,lengths:r,N:s,avgdl:s?o/s:0}}function Ec(e,t,n={}){let{k:r=8,role:o=null,tag:s=null,boxId:a=null}=n;if(!e||!e.N)return[];let i=[...new Set(ty(t))];if(!i.length)return[];let c=new Map;for(let u of i){let f=e.postings.get(u);if(!f)continue;let d=f.size,p=Math.log(1+(e.N-d+.5)/(d+.5));for(let[m,h]of f){let g=e.lengths[m],x=h+Zg*(1-Qg+Qg*(g/(e.avgdl||1))),k=p*(h*(Zg+1)/x);c.set(m,(c.get(m)||0)+k)}}let l=[];for(let[u,f]of c){let d=e.chunks[u];o&&d.role!==o||s&&!d.tags.includes(s)||a&&d.boxId!==a||l.push({chunk:d,score:f})}return l.sort((u,f)=>f.score-u.score||f.chunk.seq-u.chunk.seq),l.slice(0,r)}var Zg,Qg,BR,$d=O(()=>{Rd();Zg=1.5,Qg=.75,BR=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 Ac from"node:fs/promises";import ny from"node:path";async function LR(e){let t=ny.join(e,".bostrat","events"),n;try{n=await Ac.readdir(t)}catch{return ga([])}let r=[];for(let o of n)if(o.endsWith(".ndjson"))try{let s=await Ac.readFile(ny.join(t,o),"utf8");for(let a of s.split(`
80
- `))if(a.trim())try{r.push(JSON.parse(a))}catch{}}catch{}return ga(r)}function FR(e){let t=String(e||""),n=a=>{let i=t.match(a);return i?i[1].trim():""},r=n(/#+\s*Objective\s*\n([\s\S]*?)(?:\n#+\s|$)/i),o=n(/#+\s*Next steps?[^\n]*\n([\s\S]*?)(?:\n#+\s|$)/i);return`${r}
81
- ${o}`.trim()||t.slice(0,2e3)}function UR(e,t,{k:n=6,maxChars:r=4e3,exclude:o=null}={}){let s=Ec(e,t,{k:n*2+4}),a=[],i=0;for(let{chunk:c}of s){if(o&&o(c))continue;let l=c.role==="user"?"Operator":`Agent${c.provider?` (${c.provider})`:""}`,u=c.text.trim(),f=u.length>800?u.slice(0,800)+"\u2026":u,d=`- **${l}:** ${f}`;if(i+d.length>r||(a.push(d),i+=d.length,a.length>=n))break}return a.length?["",`## ${ry}, 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(`
82
- `):""}async function oy(e,t,n={}){let{k:r=6,maxChars:o=4e3,exclude:s=null}=n;try{let a=await Ac.readFile(t,"utf8");if(a.includes(ry))return{appended:!1,reason:"already-enriched"};let i=await LR(e);if(!i.N)return{appended:!1,reason:"empty-index"};let c=UR(i,FR(a),{k:r,maxChars:o,exclude:s});return c?(await Ac.appendFile(t,`
81
+ `);return e}function ny(e){let t=String(e||"").trim();return t?t.slice(0,32):null}function Yg(e){let t=new Error(`${e} isn't running in this box \u2014 its pane is sitting at a bare shell (the launch command was likely swallowed at shell startup, or the CLI exited). Relaunch it from the Terminal tab, or stop and reopen the box, then send again.`);return t.code="cli-not-running",t}async function Zg(e,t,n,{bailOnDialog:r=!1,launchEcho:o=null}={}){let s=Date.now()+n,a=0,i=null;for(await Mr(e).catch(()=>{});;){let c=Cd(await Te(e),o);if(LR(t,c)){await Vt(Do);return}if(Ne[t]?.up&&!Ne[t].up.test(c))if(await fn(e)){if(i??=Date.now(),Date.now()-i>=ca()){let l=Yg(t);throw X({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:e,agent:t,timeoutMs:n,gateAccepts:a,idleMs:Date.now()-i,error:l.message}).catch(()=>{}),l}}else i=null;else i=null;if(r&&t==="claude"&&OR.test(c)&&!Ne.claude.up.test(c)){X({flow:"agent-ready",phase:"dialog",sessionName:e,agent:t,dialog:"resume-confirm"}).catch(()=>{});return}if(t==="codex"&&$R.test(c)&&!Ne.codex.up.test(c)&&a<3){if(!Id(e,"codex-trust")){await Vt(Ec);continue}a+=1,await X({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,gate:"codex-trust",attempt:a}).catch(()=>{}),await Le(e,"",{enter:!0,kind:"codex-trust-accept"}),await Vt(Do);continue}if(t==="cursor"&&RR.test(c)&&!Ne.cursor.up.test(c)&&a<3){if(!Id(e,"cursor-trust")){await Vt(Ec);continue}a+=1,await X({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:a}).catch(()=>{}),await Le(e,"a",{enter:!1,kind:"cursor-trust-accept"}),await Vt(Do);continue}if(t==="codex"&&a<3){let l=MR(c);if(l){if(!Id(e,`codex-update:${l.from}->${l.to}`)){await Vt(Ec);continue}a+=1,await X({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:a,update:`${l.from} -> ${l.to}`}).catch(()=>{}),await Le(e,"3",{enter:!1,kind:"codex-update-skip"}),qg({sessionName:e,from:l.from,to:l.to}),await Vt(Do);continue}}if(Date.now()>s){if(Od(t,c)){let l=`${t} is blocked on an interactive prompt`;throw t==="codex"?l=Ne.codex.auth.test(c)?"codex isn't signed in on this box \u2014 answer the Sign in card in chat (Device Code works from any device) or finish signing in from the Terminal tab, then send again":"codex is stuck on its update prompt (auto-skip didn't clear it) \u2014 open the terminal and choose Skip, then send again":t==="cursor"&&Ne.cursor.auth.test(c)?l="cursor isn't signed in on this box \u2014 answer the Sign in card in chat (the login link works from any device) or finish signing in from the Terminal tab, then send again":t==="claude"&&Ne.claude.auth.test(c)?l="claude isn't signed in on this box \u2014 answer the setup cards in chat (or finish signing in from the Terminal tab), then send again":t==="claude"&&Ne.claude.block.test(c)&&(l='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'),X({flow:"agent-ready",phase:"blocked",sessionName:e,agent:t,timeoutMs:n,gateAccepts:a,error:l}).catch(()=>{}),new Error(l)}if(await fn(e)){let l=Yg(t);throw X({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:e,agent:t,timeoutMs:n,gateAccepts:a,error:l.message}).catch(()=>{}),l}console.warn(`[agent-ready] ${t} readiness unconfirmed in ${e} after ${n}ms \u2014 driving the box anyway.`),X({flow:"agent-ready",phase:"timeout",sessionName:e,agent:t,timeoutMs:n,gateAccepts:a,paneBlocked:!!Ne[t]?.block?.test(c),paneUp:!!Ne[t]?.up?.test(c),paneBusy:!!Ne[t]?.busy?.test(ey(Ne[t],c))}).catch(()=>{}),await Vt(Do);return}await Vt(Ec)}}function Md({agent:e,agentCmd:t}={}){let n=t?Vn(t):Vn(e||"");return{label:n,realClaude:t?Cr(t):n==="claude",realCodex:t?/codex/.test(t)&&!/fake-codex|fake-lead/.test(t):n==="codex",realCursor:t?/cursor/.test(t)&&!/fake-cursor|fake-box/.test(t):n==="cursor"}}function ry({agent:e,agentCmd:t}={}){let{realClaude:n,realCodex:r,realCursor:o}=Md({agent:e,agentCmd:t});return n||r||o||process.env.BOSTRAT_FAKE_POLL_READY==="1"}function wa({cwd:e,sessionName:t,agent:n,agentCmd:r}={}){let{realCodex:o,realCursor:s}=Md({agent:n,agentCmd:r});return!t||!o&&!s?null:Yn({cwd:e,sessionName:t,agent:n,agentCmd:r}).catch(()=>{})}async function Yn({cwd:e,sessionId:t,sessionName:n,agent:r,agentCmd:o,timeoutMs:s=ER(),bailOnDialog:a=!1,launchEcho:i=null}={}){let{label:c,realClaude:l,realCodex:u,realCursor:f}=Md({agent:r,agentCmd:o});if(l&&e&&await Fn(e),u&&e&&await go(e),f&&e&&await yo(e),(l||u||f)&&n){await Zg(n,c,s,{bailOnDialog:a,launchEcho:i});return}let d=Ne[r]?r:Ne[c]?c:null;if(process.env.BOSTRAT_FAKE_POLL_READY==="1"&&n&&d){await Zg(n,d,s,{launchEcho:i});return}await Vt(Do)}var ER,Ec,Do,AR,_R,Ne,RR,$R,OR,CR,NR,Ac,PR,Qg,BR,jR,ga=C(()=>{Ve();Ks();Vi();zi();vc();Tc();Gt();ER=()=>Number(process.env.BOSTRAT_AGENT_READY_TIMEOUT_MS)||9e4,Ec=Number(process.env.BOSTRAT_AGENT_READY_POLL_MS)||500,Do=Number(process.env.BOSTRAT_AGENT_READY_SETTLE_MS)||800,AR=/^\s{0,4}[^\s›•■◦╭╰│]\S*(?: \S+){0,3} · \S/,_R=/^\s*tab to queue message\b/;Ne={claude:{up:/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/,busy:/esc to interrupt/,busyScope:"footer",busyAlt:/^[·✢✳✶✻✽✺✹✸✷]\s+[A-Z][\w '’-]{1,40}…/m,auth:/Select login method:|Paste code here if prompted|OAuth error:|Choose the text style that looks best|Quick safety check: Is this a project you created/,block:/Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/m},codex:{up:{test:IR},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/}},RR=/Trust this workspace|\[a\]\s*Trust/,$R=/Do you trust the contents of this directory\?[\s\S]*›\s*1\. Yes, continue[\s\S]*Press enter to continue/,OR=/Resume from summary/i,CR=/Update available!\s*([\d][\w.-]*)\s*->\s*([\d][\w.-]*)/;NR=()=>Number(process.env.BOSTRAT_GATE_RESEND_MS)||3e3,Ac=new Map;PR=68,Qg=/^\s*[─━]{10,}\s*$/;BR=/\bWaiting for \d+\b[^\n]*\bto finish\b|\/workflows to (?:stop|monitor)\b/,jR=15});function WR(e){return typeof e!="string"||!e?!1:e.includes(`
82
+ `)?!0:Buffer.byteLength(e,"utf8")>=HR}function zt(e,t){return e==="codex"?{enter:!0,submitDelayMs:FR,...WR(t)?{paste:!0}:{}}:e==="claude"?{enter:!0,submitDelayMs:UR}:{enter:!0}}var FR,UR,HR,ya=C(()=>{FR=(()=>{let e=Number(process.env.BOSTRAT_CODEX_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),UR=(()=>{let e=Number(process.env.BOSTRAT_CLAUDE_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),HR=(()=>{let e=Number(process.env.BOSTRAT_CODEX_PASTE_MIN_BYTES??512);return Number.isFinite(e)&&e>=0?e:512})()});function ba(e,t){if(e==="codex")return zR(t);if(e!=="claude")return null;let n=String(t).replace(/\r/g,"").split(`
83
+ `).map(c=>c.replace(/\s+$/,"")),r=-1;for(let c=n.length-1;c>=0;c--)if(oy.test(n[c])){r=c;break}if(r<=0)return null;let o=-1;for(let c=r-1;c>=0;c--)if(oy.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(qR);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 zR(e){let t=String(e).replace(/\r/g,"").split(`
84
+ `).map(o=>o.replace(/\s+$/,"")),n=-1;for(let o=t.length-1;o>=0;o--)if(t[o]){(KR.test(t[o])||GR.test(t[o]))&&!Nd.test(t[o])?n=o:Nd.test(t[o])&&/\[Pasted Content \d+ chars\]/.test(t[o])&&(n=o+1);break}if(n<=0)return null;let r=[];for(let o=n-1;o>=0&&n-o<=60;o--){let s=t[o],a=s.match(Nd);if(a){r.unshift(a[1]);let i=r.map(c=>c.trim()).filter(Boolean);return i.length?i.join(" "):null}if(VR.test(s))return null;r.unshift(s)}return null}function Pd(e,t){let n=String(t||"");if(!/\[Pasted Content \d+ chars\]/.test(n))return!1;let r=0,o=Oe(n.replace(JR,(i,c)=>(r+=Number(c)," "))),s=[...String(e||"")].length;return o&&!Oe(e).includes(o)?!1:r+o.length<=s+Math.max(4,Math.round(s*.05))}function Oe(e){return String(e||"").replace(/\s+/g," ").trim()}function sy(e,t,{slackMs:n=2e4}={}){let r=Oe(t?.text);return!r||typeof t?.at!="number"?!1:(Array.isArray(e)?e:[]).some(o=>o?.role==="user"&&typeof o.ts=="number"&&o.ts>=t.at-n&&Oe(o.text).includes(r))}function ay(e,t,n,{busy:r=!1}={}){let o=ba(e,n);return o&&Ic(t,o)||o&&e==="codex"&&Pd(t,o)?"stuck":r&&e!=="codex"||o?"submitted":"unknown"}function Ic(e,t){let n=Oe(e),r=Oe(t).replace(/^…\s*/,"").replace(/\s*…$/,"");return!n||!r||r.length<Math.min(n.length,12)?!1:n===r||n.includes(r)}var oy,qR,Nd,KR,GR,VR,JR,Rc=C(()=>{oy=/^\s*─{8,}\s*$/,qR=/^❯[  ]?(.*)$/,Nd=/^\s*›[  ]?(.*)$/,KR=/\S+ · \S/,GR=/^\s*(?:\? for shortcuts|tab to queue message)\b/,VR=/^\s*(?:[•■◦✶✻⚠]|╭|╰|│)/;JR=/\[Pasted Content (\d+) chars\](?: #\d+)?/g});async function xa({sessionName:e,agent:t,agentCmd:n=null,text:r,trackId:o=null,flow:s="say"},a={}){if(!XR.has(t))return!0;let i=a.waitForUp??ry({agent:t,agentCmd:n}),c=a.capture||(I=>Te(I,{lines:je})),l=a.pressEnter||(I=>Ie(I,["Enter"],{kind:"submit-retry"})),u=a.sleep||e$,f=a.now||Date.now,d=a.log||(I=>X(I).catch(()=>{})),p=a.maxMs??QR(),m=f()+p,h={flow:s,trackId:o,sessionName:e,agent:t,textHead:String(r).slice(0,120)},g=0,x=0,k=0,E=!1;for(await u(ka[0]);;){let I=await c(e).catch(()=>""),M=jo(t,I),N=Bo(t,I),O=ay(t,r,I,{busy:N});if(O==="submitted")return!0;if(i&&(!M||O==="stuck"&&N)){if(f()>=m)return O==="stuck"?(d({...h,phase:"submit-failed",reason:"stuck-at-deadline",retries:g}),!1):(d({...h,phase:"submit-unverified",reason:E?"cli-down":"cli-never-up",retries:g,waitedMs:p}),!0);await u(YR);continue}if(E=!0,O==="stuck"){if(g>=ZR)return d({...h,phase:"submit-failed",retries:g}),!1;g+=1,x=0,k=0,await l(e),d({...h,phase:"submit-retry",attempt:g}),await u(ka[0]);continue}if(x+=1,x>=ka.length||f()>=m)return!0;k+=1,await u(ka[Math.min(k,ka.length-1)])}}var XR,ka,YR,ZR,QR,e$,Dd=C(()=>{Ve();ga();Rc();Gt();XR=new Set(["claude","codex"]),ka=[250,450,700],YR=500,ZR=2,QR=()=>{let e=Number(process.env.BOSTRAT_SUBMIT_VERIFY_MAX_MS);return Number.isFinite(e)&&e>0?e:3e4},e$=e=>new Promise(t=>setTimeout(t,e))});function jr(e){let t=String(e||"").toLowerCase();if(!t.trim())return null;let n=null;for(let r of t$){let o=0;for(let s of n$[r])s.test(t)&&o++;o>0&&(!n||o>n.score)&&(n={category:r,score:o})}return n}function iy(e){let t=0,n=0;for(let[r,o]of Object.entries(e||{}))r$.has(r)&&(t+=o||0),o$.has(r)&&(n+=o||0);return t>=5&&n===0?{category:"research",score:1}:n>=3?{category:"feature-build",score:1}:null}function Sa(e){return String(e||"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").replace(/[-_/]+/g," ")}var t$,n$,r$,o$,Bd=C(()=>{t$=["bug-fix","orchestration","design","ops-infra","docs-writing","research","feature-build"],n$={research:[/\bresearch\b/,/\binvestigat/,/\bverif/,/\bcompar(e|ing|ison)/,/\bcompetit/,/\bdeep[ -]?dive\b/,/\banaly[sz]/,/\bassess/,/\bdiligence\b/,/\bmarket\b/,/\bstrateg/,/\broadmap\b/,/\bnorth star/,/\bwhat('| i)?s the (state|status)\b/,/\bstatus of\b/,/\bexplore\b/,/\bfeasib/,/\bevaluat/,/\bscope out\b/,/\btalk through\b/],"bug-fix":[/\bfix(e[sd]|ing)?\b/,/\bbugs?\b/,/\bbroken\b/,/\bregression\b/,/\bcrash/,/\bincident\b/,/\bdebug/,/\bdoesn'?t (work|render|load|start)/,/\bnot working\b/,/\btroubleshoot/,/\bflaky?\b/,/\brepro(duce|duction)?\b/,/\brace condition\b/,/\bleak\b/],"feature-build":[/\bimplement/,/\bbuild(ing)?\b/,/\badd(ing)?\b/,/\bcreate\b/,/\bwire (it |them )?(up|in)\b/,/\bship(ping)?\b/,/\bintegrat/,/\bsupport for\b/,/\bfeature\b/,/\bendpoint\b/,/\badapter\b/,/\bprototype\b/],design:[/\bdesign/,/\bui\b/,/\bux\b/,/\bstyl(e|es|ing)\b/,/\bcss\b/,/\blayout\b/,/\bmock-?up/,/\brender(ing|s)?\b/,/\bpolish/,/\btheme\b/,/\bfonts?\b/,/\bresponsive\b/,/\banimation/,/\bvisual/,/\bpopover\b/],orchestration:[/\bhand[ -]?(off|over)/,/\bhand (it|the lead|this) (over|off)\b/,/\bdelegat/,/\bsubtask/,/\bmerge[ -]?back\b/,/\borchestrat/,/\b(switch|change) (the )?model\b/,/\bmodel switch/],"docs-writing":[/\bdocs?\b/,/\bdocument/,/\bmemo\b/,/\breadme\b/,/\bwrite-?up\b/,/\bchangelog\b/,/\bclaude\.md\b/,/\bblog/,/\bproofread/,/\bcopy(edit|writ)/],"ops-infra":[/\bdeploy/,/\bsystemd\b/,/\bdaemon\b/,/\btmux\b/,/\bdns\b/,/\bwireguard\b/,/\brestart/,/\bnginx\b/,/\bprovision/,/\binstall/,/\bupgrade/,/\bcron\b/,/\bbackups?\b/,/\bcertificat/,/\bssh\b/,/\bsecrets?\b/]};r$=new Set(["Read","Grep","Glob","LS","WebSearch","WebFetch","NotebookRead"]),o$=new Set(["Edit","Write","MultiEdit","NotebookEdit"])});function dy(e){let t=Sa(String(e||"")).toLowerCase(),n=[];for(let r of t.split(/[^a-z0-9]+/))r.length<2||s$.has(r)||n.push(r);return n}function a$(e){let t=[];for(let n of e||[]){let r=n.payload||{},o=String(r.text||"").trim();if(n.type==="turn.user"){if(n.source==="hook"||!o)continue;t.push(uy(n,"user",o))}else if(n.type==="turn.agent"){if(!o)continue;t.push(uy(n,"assistant",o))}}return t}function uy(e,t,n){let r=jr(n);return{id:e.id,seq:e.seq,ts:e.payload?.ts??e.ts,role:t,boxId:e.boxId??null,provider:e.provider??null,text:n,tags:r?[r.category]:[]}}function va(e){let t=a$(e),n=new Map,r=new Array(t.length).fill(0),o=0;t.forEach((a,i)=>{let c=dy(a.text);r[i]=c.length,o+=c.length;let l=new Map;for(let u of c)l.set(u,(l.get(u)||0)+1);for(let[u,f]of l){let d=n.get(u);d||n.set(u,d=new Map),d.set(i,f)}});let s=t.length;return{chunks:t,postings:n,lengths:r,N:s,avgdl:s?o/s:0}}function $c(e,t,n={}){let{k:r=8,role:o=null,tag:s=null,boxId:a=null}=n;if(!e||!e.N)return[];let i=[...new Set(dy(t))];if(!i.length)return[];let c=new Map;for(let u of i){let f=e.postings.get(u);if(!f)continue;let d=f.size,p=Math.log(1+(e.N-d+.5)/(d+.5));for(let[m,h]of f){let g=e.lengths[m],x=h+cy*(1-ly+ly*(g/(e.avgdl||1))),k=p*(h*(cy+1)/x);c.set(m,(c.get(m)||0)+k)}}let l=[];for(let[u,f]of c){let d=e.chunks[u];o&&d.role!==o||s&&!d.tags.includes(s)||a&&d.boxId!==a||l.push({chunk:d,score:f})}return l.sort((u,f)=>f.score-u.score||f.chunk.seq-u.chunk.seq),l.slice(0,r)}var cy,ly,s$,jd=C(()=>{Bd();cy=1.5,ly=.75,s$=new Set("a an and are as at be been but by for from had has have he her his i if in into is it its of on or our so than that the their them then there these they this those to was were will with would you your we".split(" "))});import Oc from"node:fs/promises";import fy from"node:path";async function i$(e){let t=fy.join(e,".bostrat","events"),n;try{n=await Oc.readdir(t)}catch{return va([])}let r=[];for(let o of n)if(o.endsWith(".ndjson"))try{let s=await Oc.readFile(fy.join(t,o),"utf8");for(let a of s.split(`
85
+ `))if(a.trim())try{r.push(JSON.parse(a))}catch{}}catch{}return va(r)}function c$(e){let t=String(e||""),n=a=>{let i=t.match(a);return i?i[1].trim():""},r=n(/#+\s*Objective\s*\n([\s\S]*?)(?:\n#+\s|$)/i),o=n(/#+\s*Next steps?[^\n]*\n([\s\S]*?)(?:\n#+\s|$)/i);return`${r}
86
+ ${o}`.trim()||t.slice(0,2e3)}function l$(e,t,{k:n=6,maxChars:r=4e3,exclude:o=null}={}){let s=$c(e,t,{k:n*2+4}),a=[],i=0;for(let{chunk:c}of s){if(o&&o(c))continue;let l=c.role==="user"?"Operator":`Agent${c.provider?` (${c.provider})`:""}`,u=c.text.trim(),f=u.length>800?u.slice(0,800)+"\u2026":u,d=`- **${l}:** ${f}`;if(i+d.length>r||(a.push(d),i+=d.length,a.length>=n))break}return a.length?["",`## ${py}, 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(`
87
+ `):""}async function my(e,t,n={}){let{k:r=6,maxChars:o=4e3,exclude:s=null}=n;try{let a=await Oc.readFile(t,"utf8");if(a.includes(py))return{appended:!1,reason:"already-enriched"};let i=await i$(e);if(!i.N)return{appended:!1,reason:"empty-index"};let c=l$(i,c$(a),{k:r,maxChars:o,exclude:s});return c?(await Oc.appendFile(t,`
83
88
  `+c),{appended:!0,chars:c.length,chunks:c.split(`
84
- - `).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 ry,sy=O(()=>{$d();ry="Relevant prior discussion (verbatim, retrieved"});function ya(e,t){if(e==="codex")return KR(t);if(e!=="claude")return null;let n=String(t).replace(/\r/g,"").split(`
85
- `).map(c=>c.replace(/\s+$/,"")),r=-1;for(let c=n.length-1;c>=0;c--)if(ay.test(n[c])){r=c;break}if(r<=0)return null;let o=-1;for(let c=r-1;c>=0;c--)if(ay.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(HR);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 KR(e){let t=String(e).replace(/\r/g,"").split(`
86
- `).map(o=>o.replace(/\s+$/,"")),n=-1;for(let o=t.length-1;o>=0;o--)if(t[o]){WR.test(t[o])&&!iy.test(t[o])&&(n=o);break}if(n<=0)return null;let r=[];for(let o=n-1;o>=0&&n-o<=60;o--){let s=t[o],a=s.match(iy);if(a){r.unshift(a[1]);let i=r.map(c=>c.trim()).filter(Boolean);return i.length?i.join(" "):null}if(qR.test(s))return null;r.unshift(s)}return null}function Od(e,t){let n=String(t||"");if(!/\[Pasted Content \d+ chars\]/.test(n))return!1;let r=0,o=Oe(n.replace(GR,(i,c)=>(r+=Number(c)," "))),s=[...String(e||"")].length;return o&&!Oe(e).includes(o)?!1:r+o.length<=s+Math.max(4,Math.round(s*.05))}function Oe(e){return String(e||"").replace(/\s+/g," ").trim()}function cy(e,t,{slackMs:n=2e4}={}){let r=Oe(t?.text);return!r||typeof t?.at!="number"?!1:(Array.isArray(e)?e:[]).some(o=>o?.role==="user"&&typeof o.ts=="number"&&o.ts>=t.at-n&&Oe(o.text).includes(r))}function ly(e,t,n,{busy:r=!1}={}){let o=ya(e,n);return o&&_c(t,o)||o&&e==="codex"&&Od(t,o)?"stuck":r||o?"submitted":"unknown"}function _c(e,t){let n=Oe(e),r=Oe(t).replace(/^…\s*/,"").replace(/\s*…$/,"");return!n||!r||r.length<Math.min(n.length,12)?!1:n===r||n.includes(r)}var ay,HR,iy,WR,qR,GR,Cd=O(()=>{ay=/^\s*─{8,}\s*$/,HR=/^❯[  ]?(.*)$/,iy=/^\s*›[  ]?(.*)$/,WR=/\S+ · \S/,qR=/^\s*(?:[•■◦✶✻⚠]|╭|╰|│)/;GR=/\[Pasted Content (\d+) chars\](?: #\d+)?/g});function ZR(e){return VR.test(String(e||"").trimStart())}function fy(e){let t=String(e||"");if(!ZR(t.trimStart()))return null;let n=t.replace(zR,"").trim(),r=QR(n),o=[];for(let u of YR){let f=u.from.map(d=>Do(r.get(d))).find(d=>d&&!uy(d));f&&o.push({h:u.h,text:ba(f,JR)})}let s=Do(r.get("Current Work"))||Do(r.get("Primary Request and Intent"))||t$(n),a=Rc(s),i=ba(Ic(Pd(a[0]||"")),XR)||"Context resumed from summary",c=[],l=a.slice(1).join(" ").trim();l&&c.push(ba(Ic(Pd(l)),Nd));for(let u of["Pending Tasks","Optional Next Step"]){let f=Rc(Do(r.get(u)))[0]||"";if(!(!f||uy(f))){c.push(ba(`Left to do: ${Ic(Pd(f))}`,Nd));break}}if(!c.length){let u=Rc(Do(r.get("Problem Solving"))||"")[0];u&&c.push(ba(Ic(u),Nd))}return{kind:"resume-summary",title:i,bullets:c.slice(0,2),sections:o,rawChars:t.length}}function QR(e){let t=new Map,n=[];Md.lastIndex=0;for(let r=Md.exec(e);r;r=Md.exec(e))n.push({name:e$(r[1]),start:r.index,end:r.index+r[0].length});for(let r=0;r<n.length;r++){let o=n[r+1]?.start??e.length;t.has(n[r].name)||t.set(n[r].name,e.slice(n[r].end,o).trim())}return t}function e$(e){return dy.find(n=>n.toLowerCase()===e.toLowerCase())||e}function Do(e){return e?String(e).replace(/```[\s\S]*?(?:```|$)/g," ").split(`
87
- `).map(t=>t.replace(/^[ \t]*(?:[-*•]|\d+[.)]|[a-z][.)])[ \t]+/i,"").trim()).filter(t=>t&&!/^#{1,6}[ \t]/.test(t)).join(" ").replace(/\*\*(.+?)\*\*/g,"$1").replace(/`([^`]+)`/g,"$1").replace(/\s+/g," ").trim():""}function t$(e){let t=e.replace(/^[\s\S]*?\bSummary:\s*/i,"");return Do(t.split(/\n{2,}/).slice(0,2).join(" "))}function Rc(e){let t=String(e||"").trim();if(!t)return[];let r=t.replace(/\b([A-Za-z0-9_-]+)\.(js|ts|tsx|mjs|json|md|css|jsonl|sh|yml|yaml|py|html)\b/g,"$1<DOT>$2").replace(/\b(e\.g|i\.e|etc|vs|approx|no|fig|Dr|Mr|Ms|St)\./gi,"$1<DOT>").split(/(?<=[.!?])["')\]]?\s+(?=[A-Z"“'(\[]|\d)/).map(s=>s.replace(/<DOT>/g,".").trim()).filter(Boolean),o=[];for(let s of r){let a=o[o.length-1];a&&(a.match(/["“”]/g)?.length??0)%2===1?o[o.length-1]=`${a} ${s}`:o.push(s)}return o}function Pd(e){return String(e||"").replace(/^(?:Immediately before (?:this|the) summary(?: request)?[,:]?\s*|At the (?:time|point) of (?:this )?compaction[,:]?\s*|Currently[,:]?\s*|The (?:most recent|immediately preceding|current) work (?:was|is)\s*)/i,"").replace(/^(?:I(?:'m|'d| am| was| had| have)?\s+(?:currently\s+|just\s+)?(?:been\s+)?(?:working on|in the middle of|completing|finishing)\s+|The user(?:'s)?\s+(?:most recent\s+)?(?:request|ask) (?:was|is)\s+(?:to\s+)?)/i,"").replace(/^I(?:'m|'d| am| was| had| have)?\s+(?:just\s+|then\s+)?(?=(?:[a-z]+(?:ed|ing)|ran|wrote|built|made|began|found|left|sent|took|went|did|got|kept|held|brought|caught|chose|came|saw|said|gave|told|set|put|read)\b)/,"").replace(/^["“]|["”]$/g,"").replace(/^(\w)/,t=>t.toUpperCase()).trim()}function Ic(e){return String(e||"").replace(/(?<![:\w/])(?:\/[\w.@+-]+){4,}/g,t=>`\u2026/${t.split("/").slice(-2).join("/")}`)}function uy(e){return/^(none|nothing|n\/a|no pending|there are no)\b/i.test(String(e||"").trim())}function ba(e,t){let n=String(e||"").trim();if(n.length<=t)return n;let r=Rc(n),o="";for(let i of r){let c=o?`${o} ${i}`:i;if(c.length>t)break;o=c}if(o.length>=Math.min(60,t*.4))return o;let s=n.slice(0,t),a=s.lastIndexOf(" ");return`${(a>t*.6?s.slice(0,a):s).replace(/[,;:.\s]+$/,"")}\u2026`}var VR,dy,Md,zR,JR,YR,XR,Nd,py=O(()=>{VR=/^This session is being continued from a previous conversation that ran out of context\./,dy=["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"],Md=new RegExp(String.raw`^[ \t]*#{0,4}[ \t]*(?:\d+[.)][ \t]*)?\*{0,2}(${dy.join("|")})[:*\t ]*$`,"gim"),zR=/\n+If you need specific details from before compaction[\s\S]*$|\n+Continue the conversation from where it left off[\s\S]*$/,JR=420,YR=[{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"]}],XR=116,Nd=168});function hy(e){return Dd.has(String(e||"").replace(/^\//,"").toLowerCase())}function $c(e){let t=String(e||"").trim();if(!t)return null;let n=fy(t);if(n)return n;let r=t.match(n$);if(r)return{kind:"skill",name:r[1].split("/").filter(Boolean).pop()||"skill"};let o=t.match(r$);if(o)return{kind:"skill",name:o[1]};let s=t.match(o$);if(s){let i=s[1].toLowerCase();return Dd.has(i)?{kind:"suppress"}:{kind:"command",command:`/${i}`}}let a=t.match(m$);if(a&&Dd.has(a[1].toLowerCase()))return{kind:"suppress"};if(s$.test(t))return{kind:"suppress"};if(i$.test(t))return{kind:"suppress"};if(a$.test(t))return{kind:"suppress"};if(c$.test(t)){let i=l=>h$(t.match(l)?.[1].trim()||"")||null,c=i(p$);return{kind:"task",summary:i(l$)||"",taskId:i(u$),toolUseId:i(d$),status:i(f$)?.toLowerCase()||null,resultHead:c?c.length>my?`${c.slice(0,my).trimEnd()}\u2026`:c:null}}return null}function h$(e){return e.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&amp;/g,"&")}function wy(e){return e?.kind==="skill"?`Ran the ${e.name} skill`:e?.kind==="command"?`Ran ${e.command}`:e?.kind==="task"?e.summary||"A background task finished":e?.kind==="resume-summary"?e.title?`Context resumed from summary: ${e.title}`:"Context resumed from summary":""}function gy(e){return e?.kind==="skill"?"skill-run":e?.kind==="task"?"task-done":e?.kind==="resume-summary"?"context-resumed":"command-run"}var n$,r$,o$,s$,a$,i$,c$,l$,u$,d$,f$,p$,my,Dd,m$,Bd=O(()=>{py();n$=/^Base directory for this skill:\s*(\S+)/,r$=/^Run the "([^"]+)" workflow\./,o$=/<command-name>\s*\/?([a-z0-9:_-]+)\s*<\/command-name>/i,s$=/^<local-command-(?:stdout|caveat)>/i,a$=/^\[Image: original \d+x\d+, displayed at \d+x\d+\.\s*Multiply coordinates by [\d.]+ to map to original image\.\]$/,i$=/^Continue from where you left off\.$/,c$=/^<task-notification>/i,l$=/<summary>([\s\S]*?)<\/summary>/i,u$=/<task-id>([\s\S]*?)<\/task-id>/i,d$=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i,f$=/<status>([\s\S]*?)<\/status>/i,p$=/<result>([\s\S]*?)(?:<\/result>|$)/i,my=600,Dd=new Set(["model","clear","compact","login","exit","quit"]);m$=/^\/([a-z0-9:_-]+)$/i});import w$ from"node:crypto";function k$(e){let t=Array.isArray(e)?e:Array.isArray(e?.questions)?e.questions:null;if(!t||!t.length)return null;let n=[];for(let r of t.slice(0,by)){let o=ka(r?.question);if(!o)return null;let s=Array.isArray(r?.options)?r.options:[],a=[];for(let i of s.slice(0,g$)){let c=ka(i?.label);if(!c)return null;let l=ka(i?.description);a.push(l?{label:c,description:l}:{label:c})}if(a.length<y$)return null;n.push({question:o,header:ka(r?.header).slice(0,b$),multiSelect:r?.multiSelect===!0,options:a})}return n.length?n:null}function Ld(e){if(typeof e!="string"||!e.includes("```bostrat-question"))return null;yy.lastIndex=0;let t=null;for(let o;o=yy.exec(e);)t=o;if(!t||t.index+t[0].length<e.trimEnd().length)return null;let n;try{n=JSON.parse(t[2])}catch{return null}let r=k$(n);return r?{text:e.slice(0,t.index).trimEnd(),questions:r}:null}function Fd(e,t,n){let r=w$.createHash("sha256").update(JSON.stringify(n)).digest("hex").slice(0,8);return`${e}:ask:${t||"turn"}:${r}`}function Ud(e,{leadBoxId:t,provider:n,isAnswered:r,maxQuestions:o=by}={}){if(!Array.isArray(e)||!t||!jd.has(n))return null;let s=null;for(let l=e.length-1;l>=0;l--){let u=e[l];if(u?.kind==="prompt")return null;if(u?.kind==="message"){if(u.role!=="assistant")return null;s=u;break}}if(!s||s.box!==t||s.agent!==n)return null;let a=s.ask?.questions||Ld(s.text)?.questions;if(!a?.length)return null;let i=a.slice(0,Math.max(1,o)),c=Fd(n,s.sourceId||s.id,a);return typeof r=="function"&&r(c)?null:{provider:n,box:t,promptId:c,groupId:c,answerMode:"say",source:"transcript",multiSelect:i[0].multiSelect,questionIndex:0,questionTotal:i.length,questions:i}}function ky(e,t,n){let r=[];(e?.questions||[]).forEach((a,i)=>{let c=(t?.[i]||[]).map(l=>a.options?.[l]?.label).filter(Boolean);c.length&&r.push({name:a.header||a.question,picks:c.join(", ")})});let o=ka(n),s;return r.length?r.length===1?s=`${r[0].name}: ${r[0].picks}`:s=`Answers:
89
+ - `).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 py,hy=C(()=>{jd();py="Relevant prior discussion (verbatim, retrieved"});function h$(e){return u$.test(String(e||"").trimStart())}function yy(e){let t=String(e||"");if(!h$(t.trimStart()))return null;let n=t.replace(d$,"").trim(),r=w$(n),o=[];for(let u of p$){let f=u.from.map(d=>Lo(r.get(d))).find(d=>d&&!wy(d));f&&o.push({h:u.h,text:Ta(f,f$)})}let s=Lo(r.get("Current Work"))||Lo(r.get("Primary Request and Intent"))||y$(n),a=Mc(s),i=Ta(Cc(Ud(a[0]||"")),m$)||"Context resumed from summary",c=[],l=a.slice(1).join(" ").trim();l&&c.push(Ta(Cc(Ud(l)),Fd));for(let u of["Pending Tasks","Optional Next Step"]){let f=Mc(Lo(r.get(u)))[0]||"";if(!(!f||wy(f))){c.push(Ta(`Left to do: ${Cc(Ud(f))}`,Fd));break}}if(!c.length){let u=Mc(Lo(r.get("Problem Solving"))||"")[0];u&&c.push(Ta(Cc(u),Fd))}return{kind:"resume-summary",title:i,bullets:c.slice(0,2),sections:o,rawChars:t.length}}function w$(e){let t=new Map,n=[];Ld.lastIndex=0;for(let r=Ld.exec(e);r;r=Ld.exec(e))n.push({name:g$(r[1]),start:r.index,end:r.index+r[0].length});for(let r=0;r<n.length;r++){let o=n[r+1]?.start??e.length;t.has(n[r].name)||t.set(n[r].name,e.slice(n[r].end,o).trim())}return t}function g$(e){return gy.find(n=>n.toLowerCase()===e.toLowerCase())||e}function Lo(e){return e?String(e).replace(/```[\s\S]*?(?:```|$)/g," ").split(`
90
+ `).map(t=>t.replace(/^[ \t]*(?:[-*•]|\d+[.)]|[a-z][.)])[ \t]+/i,"").trim()).filter(t=>t&&!/^#{1,6}[ \t]/.test(t)).join(" ").replace(/\*\*(.+?)\*\*/g,"$1").replace(/`([^`]+)`/g,"$1").replace(/\s+/g," ").trim():""}function y$(e){let t=e.replace(/^[\s\S]*?\bSummary:\s*/i,"");return Lo(t.split(/\n{2,}/).slice(0,2).join(" "))}function Mc(e){let t=String(e||"").trim();if(!t)return[];let r=t.replace(/\b([A-Za-z0-9_-]+)\.(js|ts|tsx|mjs|json|md|css|jsonl|sh|yml|yaml|py|html)\b/g,"$1<DOT>$2").replace(/\b(e\.g|i\.e|etc|vs|approx|no|fig|Dr|Mr|Ms|St)\./gi,"$1<DOT>").split(/(?<=[.!?])["')\]]?\s+(?=[A-Z"“'(\[]|\d)/).map(s=>s.replace(/<DOT>/g,".").trim()).filter(Boolean),o=[];for(let s of r){let a=o[o.length-1];a&&(a.match(/["“”]/g)?.length??0)%2===1?o[o.length-1]=`${a} ${s}`:o.push(s)}return o}function Ud(e){return String(e||"").replace(/^(?:Immediately before (?:this|the) summary(?: request)?[,:]?\s*|At the (?:time|point) of (?:this )?compaction[,:]?\s*|Currently[,:]?\s*|The (?:most recent|immediately preceding|current) work (?:was|is)\s*)/i,"").replace(/^(?:I(?:'m|'d| am| was| had| have)?\s+(?:currently\s+|just\s+)?(?:been\s+)?(?:working on|in the middle of|completing|finishing)\s+|The user(?:'s)?\s+(?:most recent\s+)?(?:request|ask) (?:was|is)\s+(?:to\s+)?)/i,"").replace(/^I(?:'m|'d| am| was| had| have)?\s+(?:just\s+|then\s+)?(?=(?:[a-z]+(?:ed|ing)|ran|wrote|built|made|began|found|left|sent|took|went|did|got|kept|held|brought|caught|chose|came|saw|said|gave|told|set|put|read)\b)/,"").replace(/^["“]|["”]$/g,"").replace(/^(\w)/,t=>t.toUpperCase()).trim()}function Cc(e){return String(e||"").replace(/(?<![:\w/])(?:\/[\w.@+-]+){4,}/g,t=>`\u2026/${t.split("/").slice(-2).join("/")}`)}function wy(e){return/^(none|nothing|n\/a|no pending|there are no)\b/i.test(String(e||"").trim())}function Ta(e,t){let n=String(e||"").trim();if(n.length<=t)return n;let r=Mc(n),o="";for(let i of r){let c=o?`${o} ${i}`:i;if(c.length>t)break;o=c}if(o.length>=Math.min(60,t*.4))return o;let s=n.slice(0,t),a=s.lastIndexOf(" ");return`${(a>t*.6?s.slice(0,a):s).replace(/[,;:.\s]+$/,"")}\u2026`}var u$,gy,Ld,d$,f$,p$,m$,Fd,by=C(()=>{u$=/^This session is being continued from a previous conversation that ran out of context\./,gy=["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"],Ld=new RegExp(String.raw`^[ \t]*#{0,4}[ \t]*(?:\d+[.)][ \t]*)?\*{0,2}(${gy.join("|")})[:*\t ]*$`,"gim"),d$=/\n+If you need specific details from before compaction[\s\S]*$|\n+Continue the conversation from where it left off[\s\S]*$/,f$=420,p$=[{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"]}],m$=116,Fd=168});function xy(e){return Hd.has(String(e||"").replace(/^\//,"").toLowerCase())}function Nc(e){let t=String(e||"").trim();if(!t)return null;let n=yy(t);if(n)return n;let r=t.match(b$);if(r)return{kind:"skill",name:r[1].split("/").filter(Boolean).pop()||"skill"};let o=t.match(k$);if(o)return{kind:"skill",name:o[1]};let s=t.match(x$);if(s){let i=s[1].toLowerCase();return Hd.has(i)?{kind:"suppress"}:{kind:"command",command:`/${i}`}}let a=t.match(O$);if(a&&Hd.has(a[1].toLowerCase()))return{kind:"suppress"};if(S$.test(t))return{kind:"suppress"};if(T$.test(t))return{kind:"suppress"};if(v$.test(t))return{kind:"suppress"};if(E$.test(t)){let i=l=>C$(t.match(l)?.[1].trim()||"")||null,c=i($$);return{kind:"task",summary:i(A$)||"",taskId:i(_$),toolUseId:i(I$),status:i(R$)?.toLowerCase()||null,resultHead:c?c.length>ky?`${c.slice(0,ky).trimEnd()}\u2026`:c:null}}return null}function C$(e){return e.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&amp;/g,"&")}function Sy(e){return e?.kind==="skill"?`Ran the ${e.name} skill`:e?.kind==="command"?`Ran ${e.command}`:e?.kind==="task"?e.summary||"A background task finished":e?.kind==="resume-summary"?e.title?`Context resumed from summary: ${e.title}`:"Context resumed from summary":""}function vy(e){return e?.kind==="skill"?"skill-run":e?.kind==="task"?"task-done":e?.kind==="resume-summary"?"context-resumed":"command-run"}var b$,k$,x$,S$,v$,T$,E$,A$,_$,I$,R$,$$,ky,Hd,O$,Wd=C(()=>{by();b$=/^Base directory for this skill:\s*(\S+)/,k$=/^Run the "([^"]+)" workflow\./,x$=/<command-name>\s*\/?([a-z0-9:_-]+)\s*<\/command-name>/i,S$=/^<local-command-(?:stdout|caveat)>/i,v$=/^\[Image: original \d+x\d+, displayed at \d+x\d+\.\s*Multiply coordinates by [\d.]+ to map to original image\.\]$/,T$=/^Continue from where you left off\.$/,E$=/^<task-notification>/i,A$=/<summary>([\s\S]*?)<\/summary>/i,_$=/<task-id>([\s\S]*?)<\/task-id>/i,I$=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i,R$=/<status>([\s\S]*?)<\/status>/i,$$=/<result>([\s\S]*?)(?:<\/result>|$)/i,ky=600,Hd=new Set(["model","clear","compact","login","exit","quit"]);O$=/^\/([a-z0-9:_-]+)$/i});import M$ from"node:crypto";function B$(e){let t=Array.isArray(e)?e:Array.isArray(e?.questions)?e.questions:null;if(!t||!t.length)return null;let n=[];for(let r of t.slice(0,Ey)){let o=Ea(r?.question);if(!o)return null;let s=Array.isArray(r?.options)?r.options:[],a=[];for(let i of s.slice(0,N$)){let c=Ea(i?.label);if(!c)return null;let l=Ea(i?.description);a.push(l?{label:c,description:l}:{label:c})}if(a.length<P$)return null;n.push({question:o,header:Ea(r?.header).slice(0,D$),multiSelect:r?.multiSelect===!0,options:a})}return n.length?n:null}function Kd(e){if(typeof e!="string"||!e.includes("```bostrat-question"))return null;Ty.lastIndex=0;let t=null;for(let o;o=Ty.exec(e);)t=o;if(!t||t.index+t[0].length<e.trimEnd().length)return null;let n;try{n=JSON.parse(t[2])}catch{return null}let r=B$(n);return r?{text:e.slice(0,t.index).trimEnd(),questions:r}:null}function Gd(e,t,n){let r=M$.createHash("sha256").update(JSON.stringify(n)).digest("hex").slice(0,8);return`${e}:ask:${t||"turn"}:${r}`}function Vd(e,{leadBoxId:t,provider:n,isAnswered:r,maxQuestions:o=Ey}={}){if(!Array.isArray(e)||!t||!qd.has(n))return null;let s=null;for(let l=e.length-1;l>=0;l--){let u=e[l];if(u?.kind==="prompt")return null;if(u?.kind==="message"){if(u.role!=="assistant")return null;s=u;break}}if(!s||s.box!==t||s.agent!==n)return null;let a=s.ask?.questions||Kd(s.text)?.questions;if(!a?.length)return null;let i=a.slice(0,Math.max(1,o)),c=Gd(n,s.sourceId||s.id,a);return typeof r=="function"&&r(c)?null:{provider:n,box:t,promptId:c,groupId:c,answerMode:"say",source:"transcript",multiSelect:i[0].multiSelect,questionIndex:0,questionTotal:i.length,questions:i}}function Ay(e,t,n){let r=[];(e?.questions||[]).forEach((a,i)=>{let c=(t?.[i]||[]).map(l=>a.options?.[l]?.label).filter(Boolean);c.length&&r.push({name:a.header||a.question,picks:c.join(", ")})});let o=Ea(n),s;return r.length?r.length===1?s=`${r[0].name}: ${r[0].picks}`:s=`Answers:
88
91
  ${r.map(a=>`- ${a.name}: ${a.picks}`).join(`
89
92
  `)}`:s=o,r.length&&o&&(s+=`
90
- ${o}`),s||""}var jd,by,g$,y$,b$,yy,ka,xy,Hd=O(()=>{jd=new Set(["cursor","codex"]),by=4,g$=4,y$=2,b$=24,yy=/^[ \t]{0,3}(`{3,})bostrat-question[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]{0,3}\1`*[ \t]*$/gm,ka=e=>typeof e=="string"?e.trim():"";xy=`
93
+ ${o}`),s||""}var qd,Ey,N$,P$,D$,Ty,Ea,_y,zd=C(()=>{qd=new Set(["cursor","codex"]),Ey=4,N$=4,P$=2,D$=24,Ty=/^[ \t]{0,3}(`{3,})bostrat-question[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]{0,3}\1`*[ \t]*$/gm,Ea=e=>typeof e=="string"?e.trim():"";_y=`
91
94
  When you are BLOCKED on a decision only the operator can make \u2014 an ambiguous
92
95
  requirement, an irreversible choice, several valid approaches \u2014 do not bury the
93
96
  question in prose. End your message with exactly ONE fenced code block tagged
@@ -107,67 +110,67 @@ your turn. The operator sees the questions as an interactive card in their chat
107
110
  answer. Never use the block for rhetorical questions, progress updates, or
108
111
  anything you can decide yourself; keep asking in prose for questions without
109
112
  enumerable options.
110
- `});function x$(e){return{id:e.id,kind:"prompt",groupId:e.groupId,provider:e.provider,box:e.box,agent:e.provider,questionTotal:e.questions.length,answeredVia:"chat",questions:e.questions.map((t,n)=>({index:n,header:t.header||"",question:t.question,multiSelect:!!t.multiSelect,chosen:[]})),ts:e.ts}}function v$(e,t,n){let r=Sy(n),o=e.has(r)?r:null;if(!o&&n.number!=null)for(let[i,c]of e){if(Number(c.number)!==Number(n.number))continue;let l=!!(n.url&&c.url&&n.url===c.url),u=!c.repo&&!!n.repo||!!c.repo&&!n.repo;if(l||u&&(!c.url||!n.url||c.url===n.url)){o=i;break}}let s=n.repo||!o?r:o,a=o?e.get(o):e.get(s);if(o&&o!==s){e.delete(o);let i=t.get(o);if(t.delete(o),i?.length){let c=t.get(s)??[];t.set(s,c.concat(i))}}return e.set(s,{number:n.number,url:n.url??a?.url??null,title:n.title??a?.title??null,repo:n.repo??a?.repo??null,branch:n.branch??a?.branch??null}),s}function Zn(e){let t=[],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=new Map,f=(y,w)=>{u.set(y,w),t.push(w)},d=y=>{let w=u.get(y);w&&(w.retired=!0)},p=/^Agent "([\s\S]+)" finished$/,m=new Map;for(let y of e||[]){if(y.type!=="tool.called"||y.source!=="transcript")continue;let w=String(y.payload?.command||"");if(/\bbostrat-mock\s+(?:add|update)\b/.test(w))for(let v of w.matchAll(/[\w./~-]+\.(?:png|jpe?g|gif|webp|bmp|svg)\b/gi)){let $=v[0].split("/").pop().toLowerCase();m.has($)||m.set($,[]),m.get($).push(y.payload?.ts??y.ts)}}let h=3*6e4,g=20*6e4,x=(y,w)=>!!(y?.name&&m.get(String(y.name).toLowerCase()))?.some($=>$>=w-h&&$<=w+g);for(let y of e||[])if(y.type==="turn.retracted"){r.add(`${y.boxId}|${y.payload?.saidTs}`);let w=Oe(y.payload?.text);w&&(o.has(y.boxId)||o.set(y.boxId,[]),o.get(y.boxId).push(w))}else if(y.type==="turn.user"&&y.source==="orchestrator"){let w=Oe(y.payload?.text);w&&(s.has(y.boxId)||s.set(y.boxId,new Set),s.get(y.boxId).add(w))}else if(y.type==="job.started"&&y.payload?.id)a.add(y.payload.id),(y.payload.kind||"agent")==="agent"&&y.payload.name&&c.add(y.payload.name);else if(y.type==="turn.user"&&y.payload?.note?.kind==="task"){let w=y.payload.note,v={status:w.status||null,summary:w.summary||null,resultHead:w.resultHead??null,ts:de(y)};w.toolUseId&&i.set(w.toolUseId,v);let $=String(w.summary||"").match(p);$&&l.set($[1],v)}let k=new Map,E=new Map,I=null,M=new Map,N=new Map,C=new Map,T=new Map,j=new Map,Z=new Map,fe=new Map,ie=new Map,D=new Map,R=new Map,U=new Map,pe=new Map,Se=new Map,He=()=>{for(let y of Se.values())y.questions.length&&t.push(y);Se.clear()},le=null,q=6e4,J=new Map,ee=(y,w)=>{let v=o.get(y);if(!v?.length)return!1;let $=Oe(w),ve=s.get(y);return v.some(b=>{if(!$.startsWith(b))return!1;let P=Oe($.slice(b.length));return!!P&&!!ve?.has(P)})};for(let y of e||[]){let w=y.payload||{};switch(y.type){case"turn.user":{if(y.source==="hook"||!String(w.text||"").trim()&&!w.images?.length&&!w.attachments?.length)break;{let v=w.note||$c(w.text);if(v){if(v.kind==="task"){if(v.toolUseId&&a.has(v.toolUseId))break;let $=String(v.summary||"").match(p);if(!v.toolUseId&&$&&c.has($[1]))break}if(v.kind==="command"&&hy(v.command))break;if(v.kind==="resume-summary"){t.push({id:y.id,kind:"resume-summary",title:v.title||"Context resumed from summary",bullets:v.bullets||[],sections:v.sections||[],rawChars:v.rawChars??null,ts:de(y),box:y.boxId,agent:y.provider});break}v.kind!=="suppress"&&t.push({id:y.id,kind:"event",type:gy(v),name:v.name??null,command:v.command??null,summary:v.summary??null,status:v.status??null,ts:de(y),box:y.boxId,agent:y.provider});break}}if(r.has(`${y.boxId}|${de(y)}`)||y.source==="transcript"&&ee(y.boxId,w.text))break;if(w.kind==="merge-notify"||w.kind==="ship-notify"){t.push({id:y.id,kind:"event",type:w.kind==="ship-notify"?"ship-notified":"merge-notified",text:w.text,ts:de(y),box:y.boxId,agent:y.provider});break}if(w.kind==="mock-picked"||w.kind==="ci-fix"||w.kind==="reconcile"||w.kind==="pr-go"||w.kind==="push-go"||w.kind==="spin-up-view"||w.kind==="prompt-answer"){w.kind==="prompt-answer"&&(le=null);break}for(let v of M.values())v.status="stale";M.clear();for(let v of C.values())v.status="stale";C.clear(),le&&le.box===y.boxId&&(t.push(x$(le)),le=null),t.push({id:y.id,kind:"message",role:"user",text:w.text,ts:de(y),box:y.boxId,agent:y.provider,boxRole:w.boxRole,...y.actor==="orchestrator"?{orchestration:w.kind||!0}:{},...w.sourceId?{sourceId:w.sourceId}:{},...w.attachments?.length?{attachments:w.attachments}:{},...w.images?.length?{images:w.images}:{}});break}case"peer.message":{let v=w.from||{};t.push({id:y.id,kind:"event",type:"peer-message",text:w.text,from:v.trackName||v.boxId||v.name||null,fromTrackId:v.trackId||null,ts:de(y),box:y.boxId,agent:y.provider});break}case"turn.agent":{if(w.model==="<synthetic>"&&/^No response requested\.$/.test(String(w.text||"").trim()))break;let v=Og(w,{codexFailedText:Dr});if(v){t.push({id:y.id,kind:"event",type:"provider-error",cls:v.cls,status:v.status??void 0,text:v.text,provider:y.provider,legacy:!0,at:de(y),ts:de(y),box:y.boxId,agent:y.provider});break}He();let $=(w.images||[]).filter(Me=>!x(Me,de(y)));if(!String(w.text||"").trim()&&!$.length)break;if(y.provider==="cursor"){let Me=`${y.boxId}|${w.text}`;if(n.has(Me))break;n.add(Me)}(!le||le.box===y.boxId)&&(le=null);let ve=y.provider==="codex"?(w.tools||[]).filter(Me=>!gd.has(Me)&&!la.has(Me)):w.tools||[],b=w.text,P=null;if(jd.has(y.provider)){let Me=Ld(String(w.text||""));Me&&(b=Me.text,P={questions:Me.questions})}t.push({id:y.id,kind:"message",role:"assistant",text:b,ts:de(y),box:y.boxId,agent:y.provider,boxRole:w.boxRole,...P?{ask:P}:{},...ve.length?{tools:ve}:{},...w.model?{model:w.model}:{},...w.sourceId?{sourceId:w.sourceId}:{},...$.length?{images:$}:{}}),P&&(le={id:y.id,groupId:Fd(y.provider,w.sourceId||y.id,P.questions),provider:y.provider,box:y.boxId,questions:P.questions,ts:de(y)});break}case"job.started":{if(!w.id)break;let v=de(y),$=i.get(w.id);if(!$&&(w.kind||"agent")==="agent"&&w.name){let We=l.get(w.name);We&&We.ts>=v&&($=We)}let ve={jobId:w.id,jobKind:w.kind||"agent",name:w.name||null,detail:w.detail||null,status:$?$.status==="killed"?"stopped":$.status&&$.status!=="completed"?"failed":"done":"running",startedTs:v,finishedTs:$?.ts??null,summary:$?.summary??null,resultHead:$?.resultHead??null},b=J.get(y.boxId),P=b?.jobs[b.jobs.length-1]?.startedTs;if(b&&P!=null&&v-P<=q)b.jobs.push(ve);else{let We={id:y.id,kind:"job-dock",dockId:w.id,ts:v,box:y.boxId,agent:y.provider,jobs:[ve]};J.set(y.boxId,We),t.push(We)}break}case"handoff.done":t.push(St(y,"lead-handoff"));break;case"subtask.delegated":t.push({...St(y,"subtask-delegated"),to:y.boxId,toAgent:y.provider});break;case"subtask.merged":t.push(St(y,"subtask-merged"));break;case"pr.state.changed":{if(!w.change)break;if(w.change==="opened"){for(let $ of M.values())$.status="stale";M.clear();for(let $ of C.values())$.status="stale";C.clear()}let v=St(y,`pr-${w.change}`);if(v.box=y.boxId??null,S$.has(w.change)&&w.number!=null){let $=v$(k,E,w);if(k.size>=2){for(let b of E.values())for(let P of b)P.grouped=!0;v.groupPrs=[...k.values()];let ve=[v];for(let b of k.keys())E.set(b,ve)}else{let ve=E.get($)??[];ve.push(v),E.set($,ve)}}else if(w.change==="merged"||w.change==="closed"||w.change==="lost"){let $=Sy(w),ve=I&&!I.complete||k.size>=2;if(k.has($))k.delete($),E.delete($);else if(w.number!=null)for(let b of[...k.keys()])b.endsWith(`#${w.number}`)&&(k.delete(b),E.delete(b));if(ve&&w.number!=null){(!I||I.complete)&&(I={id:y.id,kind:"event",type:"pr-group-settled",prs:[],remaining:[],complete:!1,at:de(y),ts:de(y),box:y.boxId,agent:y.provider},t.push(I)),I.prs.push({number:w.number,url:w.url??null,title:w.title??null,repo:w.repo??null,branch:w.branch??null,change:w.change,ts:de(y)}),I.remaining=[...k.values()],I.complete=k.size===0;break}}t.push(v);break}case"pr.offered":{if(!w.offerId)break;for(let $ of M.values())$.status="stale";M.clear();for(let $ of C.values())$.status="stale";C.clear();let v={id:y.id,kind:"pr-offer",offerId:w.offerId,excerpt:w.excerpt||null,branch:w.branch||null,base:w.base||null,offered:Array.isArray(w.offered)&&w.offered.length?w.offered:null,toPr:w.toPr&&typeof w.toPr=="object"?{number:w.toPr.number??null}:null,available:Array.isArray(w.available)?w.available:null,defaults:Array.isArray(w.defaults)?w.defaults:null,prState:w.prState||null,openPr:w.openPr&&typeof w.openPr=="object"?w.openPr:null,repos:Array.isArray(w.repos)&&w.repos.length?w.repos:null,status:"open",ts:de(y),box:y.boxId,agent:y.provider};M.set(w.offerId,v),N.set(w.offerId,v),t.push(v);break}case"pr.offer.answered":{let v=N.get(w.offerId);v&&(v.status=w.action||"dismiss",v.actions=Array.isArray(w.actions)?w.actions:null,v.notify=w.notify===!0,w.existingPr&&typeof w.existingPr=="object"&&(v.existingPr={number:w.existingPr.number??null}),M.delete(w.offerId));break}case"pr.exists.offered":{if(!w.offerId)break;for(let $ of C.values())$.status="stale";C.clear();let v={id:y.id,kind:"pr-exists-offer",offerId:w.offerId,srcOfferId:w.srcOfferId??null,branch:w.branch||null,base:w.base||null,pr:w.pr&&typeof w.pr=="object"?{number:w.pr.number??null,url:w.pr.url??null,title:w.pr.title??null}:null,actions:Array.isArray(w.actions)&&w.actions.length?w.actions:null,notify:w.notify===!0,status:"open",ts:de(y),box:y.boxId,agent:y.provider};C.set(w.offerId,v),T.set(w.offerId,v),t.push(v);break}case"pr.exists.answered":{let v=T.get(w.offerId);v&&(v.status=w.choice||"dismiss",C.delete(w.offerId));break}case"box.state.changed":{let v=w.change==="model"?"model-change":w.change;if(!v)break;let $=St(y,v);if(v==="model-change"&&($.to=w.model),v==="node-update"&&$.latest){let ve=t.findIndex(b=>b.kind==="event"&&b.type==="node-update"&&b.latest===$.latest);if(ve>=0){let b=t[ve];t[ve]={...$,ts:b.ts,at:b.at,firstAt:b.firstAt??b.ts,updatedAt:$.ts};break}}t.push($);break}case"track.transferred":case"track.recovered":t.push(St(y,"track-moved"));break;case"view.state.changed":{if(w.change==="deleted"){d(`view:${w.viewId}`);break}if(w.change!=="created"||w.restarted)break;f(`view:${w.viewId}`,{id:y.id,kind:"view-card",viewId:w.viewId,name:w.name,slug:w.slug,port:w.port,origin:w.origin,ts:de(y),box:y.boxId,agent:y.provider});break}case"view.spinup.failed":{t.push({id:y.id,kind:"view-spinup-failed",name:w.name||null,reason:w.reason||"no-view",ts:de(y),box:y.boxId,agent:y.provider});break}case"mock.state.changed":{if(w.change==="picked"){t.push({id:y.id,kind:"mock-picked",mockId:w.mockId,name:w.name,group:w.group??null,version:w.version??null,siblings:w.siblings??[],ts:de(y),box:y.boxId,agent:y.provider});break}if(w.change==="deleted"){d(`mock:${w.mockId}`);break}if(w.change!=="created")break;f(`mock:${w.mockId}`,{id:y.id,kind:"mock-card",mockId:w.mockId,name:w.name,group:w.group??null,ts:de(y),box:y.boxId,agent:y.provider});break}case"flow.state.changed":{if(w.change==="deleted"){d(`flow:${w.flowId}`);break}if(w.change!=="created")break;f(`flow:${w.flowId}`,{id:y.id,kind:"flow-card",flowId:w.flowId,name:w.name,stepCount:w.stepCount??null,mockIds:w.mockIds??[],ts:de(y),box:y.boxId,agent:y.provider});break}case"runbook.state.changed":{if(w.change==="deleted"){d(`runbook:${w.runbookId}`);break}if(w.change!=="created")break;f(`runbook:${w.runbookId}`,{id:y.id,kind:"runbook-card",runbookId:w.runbookId,name:w.name,ts:de(y),box:y.boxId,agent:y.provider});break}case"ticket.linked":{t.push({id:y.id,kind:"ticket-card",provider:w.provider||"linear",key:w.key,url:w.url,title:w.title??null,linkSource:w.linkSource??null,ts:de(y),box:y.boxId,agent:y.provider});break}case"box.fullscreen.detected":{if(!w.offerId)break;for(let $ of fe.values())$.box===(w.box||y.boxId)&&($.status="stale",fe.delete($.offerId));let v={id:y.id,kind:"fullscreen-offer",offerId:w.offerId,status:"open",ts:de(y),box:w.box||y.boxId,agent:w.agent||y.provider};fe.set(w.offerId,v),ie.set(w.offerId,v),t.push(v);break}case"box.fullscreen.answered":{let v=ie.get(w.offerId);v&&(v.status=w.action==="restarted"?"restarted":w.action==="cleared"?"cleared":"dismiss",fe.delete(w.offerId));break}case"ticket.move.offered":{if(!w.offerId)break;for(let $ of j.values())$.key===w.key&&($.status="stale",j.delete($.offerId));let v={id:y.id,kind:"ticket-offer",offerId:w.offerId,provider:w.provider||"linear",key:w.key,url:w.url??null,phase:w.phase??null,from:w.from??null,to:w.to?.name??null,prNumber:w.prNumber??null,status:"open",ts:de(y),box:y.boxId,agent:y.provider};j.set(w.offerId,v),Z.set(w.offerId,v),t.push(v);break}case"ticket.move.answered":{let v=Z.get(w.offerId);v&&(v.status=w.action==="moved"?"moved":"dismiss",j.delete(w.offerId));break}case"ticket.state.changed":{for(let v of j.values())v.key===w.key&&v.to===w.to&&(v.status="stale",j.delete(v.offerId));if(w.mode==="offer")break;t.push(St(y,"ticket-state"));break}case"ticket.commented":{t.push({id:y.id,kind:"ticket-comment",key:w.key,url:w.url??null,excerpt:w.excerpt??null,ts:de(y),box:y.boxId,agent:y.provider});break}case"ticket.flow.changed":t.push(St(y,"ticket-flow"));break;case"ticket.create.offered":{if(!w.proposalId)break;for(let $ of D.values())$.status="stale";D.clear();let v={id:y.id,kind:"ticket-create-offer",proposalId:w.proposalId,provider:w.provider||"linear",epic:w.epic??null,issues:Array.isArray(w.issues)?w.issues:[],team:w.team??null,needsTeam:!!w.needsTeam,linkCurrentTrack:!!w.linkCurrentTrack,status:"open",ts:de(y),box:y.boxId,agent:y.provider};D.set(w.proposalId,v),R.set(w.proposalId,v),t.push(v);break}case"ticket.create.answered":{let v=R.get(w.proposalId);v&&(v.status=w.action==="created"?"created":"dismiss",v.createdCount=w.createdCount??null,v.failedCount=w.failedCount??null,D.delete(w.proposalId));break}case"loop.create.offered":{if(!w.proposalId)break;for(let $ of U.values())$.status="stale";U.clear();let v={id:y.id,kind:"loop-create-offer",proposalId:w.proposalId,name:w.name??"",schedule:w.schedule??"",prompt:w.prompt??"",expectation:w.expectation??null,notify:w.notify??"off",assignment:w.assignment??{provider:"claude"},repo:w.repo??null,nodeId:w.nodeId??null,nodeName:w.nodeName??null,status:"open",ts:de(y),box:y.boxId,agent:y.provider};U.set(w.proposalId,v),pe.set(w.proposalId,v),t.push(v);break}case"loop.create.answered":{let v=pe.get(w.proposalId);v&&(v.status=w.action==="created"?"created":"dismiss",U.delete(w.proposalId));break}case"loop.created":{let v=w.proposalId?pe.get(w.proposalId):null;v&&(v.created={loopId:w.loopId??null,nextFireAt:Number.isFinite(Number(w.nextFireAt))?Number(w.nextFireAt):null});break}case"ticket.created":{let v={items:Array.isArray(w.items)?w.items:[],failed:Array.isArray(w.failed)?w.failed:[],team:w.team??null},$=w.proposalId?R.get(w.proposalId):null;if($){$.created=v;break}t.push({id:y.id,kind:"ticket-created",...v,ts:de(y),box:y.boxId,agent:y.provider});break}case"error":{if(!w.kind)break;t.push(St(y,w.kind));break}case"provider.error":t.push({...St(y,"provider-error"),provider:y.provider,box:y.boxId,agent:y.provider});break;case"usage.cap.hit":t.push(St(y,"usage-cap-hit"));break;case"usage.cap.warning":t.push(St(y,"usage-cap-warning"));break;case"provider.connected":{t.push({id:y.id,kind:"event",type:"provider-connected",provider:w.provider||y.provider,ts:de(y),at:de(y),box:y.boxId,agent:y.provider});break}case"prompt.answered":{if(le=null,w.control||!w.question)break;let v=w.groupId||w.promptId;if(!v)break;let $=Se.get(v);$||($={id:y.id,kind:"prompt",groupId:v,provider:y.provider,box:y.boxId,agent:y.provider,questionTotal:w.questionTotal??1,questions:[],ts:de(y)},Se.set(v,$));let ve=w.questionIndex??0,b={index:ve,header:w.header||"",question:w.question,multiSelect:!!w.multiSelect,chosen:Array.isArray(w.chosen)?w.chosen:[]},P=$.questions.findIndex(We=>We.index===ve&&Oe(We.question)===Oe(b.question));P>=0?$.questions[P]=b:$.questions.push(b),$.questions.sort((We,Ht)=>We.index-Ht.index),$.questionTotal=Math.max($.questionTotal,w.questionTotal??1),$.questions.length>=$.questionTotal&&(t.push($),Se.delete(v));break}default:break}}let Xe=u.size?t.filter(y=>!y.retired):t;return E$(Xe.sort((y,w)=>(y.ts??0)-(w.ts??0)))}function E$(e){let t=new Map,n=[];for(let r of e){if(r.kind!=="message"||!r.box){n.push(r);continue}let o=r.role==="assistant"&&!String(r.text||"").trim()&&r.images?.length,s=t.get(r.box);if(o&&s&&(r.ts??0)-s.lastTs<=T$){s.item.images.push(...r.images),s.lastTs=r.ts??s.lastTs;continue}if(o){let a={...r,images:[...r.images]};t.set(r.box,{item:a,lastTs:r.ts??0}),n.push(a)}else t.delete(r.box),n.push(r)}return n}function Wd(e,t=null){let n=[];for(let o of e||[]){if(o.type!=="tool.called"||o.source!=="transcript")continue;let s=o.payload||{};String(s.command||"").trim()&&n.push({id:s.id??null,tool:s.tool||null,command:s.command,description:s.description||"",summary:A$(s),ts:s.ts??o.ts,n:s.n,box:o.boxId,agent:o.provider,boxRole:s.boxRole})}if(!n.length)return[];let r=(t??Zn(e)).filter(o=>o.kind==="message");return vg(n,r)}function A$(e){let t=String(e.summary||"").trim();return t&&t!==e.command&&t!==No(e.command)?t:Jn(e.command,e.description||"")}function St(e,t){let{ts:n,change:r,...o}=e.payload||{};return{id:e.id,kind:"event",type:t,...o,at:de(e),ts:de(e)}}function vy(e){let t=[...e];for(let n=0;n<t.length;n++){let r=t[n];if(r?.kind!=="event"||r.type!=="archived")continue;let o=(r.ts??0)+_$,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||a?.kind==="event"&&I$.has(a.type))break;s++}s>n&&t.splice(s,0,...t.splice(n,1)),n=s}return t}function Ty(e){let t=[...e];for(let n=0;n<t.length;n++){let r=t[n];if(r?.kind!=="event"||!$$.has(r.type)||!r.box)continue;let o=(r.ts??0)+R$,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||!(a?.kind==="message"&&a.role==="assistant"&&a.box===r.box||a?.kind==="command-batch"&&a.anchorBox===r.box))break;s++}s>n&&t.splice(s,0,...t.splice(n,1)),n=s}return t}function Ey(e){return(e||[]).filter(t=>O$.has(t?.kind)&&t.status==="open")}var de,S$,Sy,T$,_$,I$,R$,$$,O$,qd=O(()=>{Po();Br();gc();Cd();Bd();Hd();de=e=>e.payload?.ts??e.ts;S$=new Set(["opened","ci-fixed","reconciled","pushed"]),Sy=e=>`${e.repo??""}#${e.number}`;T$=2*6e4;_$=12e4,I$=new Set(["archived","unarchived","opened"]);R$=2500,$$=new Set(["pr-opened","pr-merged","pr-auto-armed"]);O$=new Set(["pr-offer","pr-exists-offer","ticket-offer","ticket-create-offer","loop-create-offer","fullscreen-offer"])});function D$(e){let t=null,n=null,r=null;for(let o of e??[]){let s=o?.ts??null;s&&(r=Math.max(r??0,s)),o?.type==="handoff.artifact"&&(t={ts:o.payload?.ts??s,truncated:!!o.payload?.truncated,...o.payload?.reconstructed?{reconstructed:!0}:{}}),o?.type==="code.pushed"&&(n={ts:o.payload?.ts??s,sha:o.payload?.sha??null,ref:o.payload?.ref??null,wip:!!o.payload?.wip})}return{lastArtifact:t,lastPush:n,lastEventAt:r}}function j$(e){for(let t=(e?.length??0)-1;t>=0;t--){let n=e[t];if(n?.type==="handoff.artifact"&&!n.payload?.reconstructed)return n}return null}function L$(e,t){let n=[],r=[],o=new Set,s=new Set;for(let a=(e?.length??0)-1;a>=0;a--){let i=e[a];if(i?.type!=="tool.called")continue;if(t!=null&&(i.ts??0)<=t)break;let c=i.payload||{};c.path&&!o.has(c.path)&&n.length<N$&&(o.add(c.path),n.push(c.path)),c.head&&!s.has(c.head)&&r.length<P$&&(s.add(c.head),r.push(c.head))}return{files:n,heads:r}}function Ry(e,{trackName:t="this Track",now:n=null,mode:r="failover"}={}){let o=D$(e),s=j$(e),a=s?.payload?.content??null,i=s?s.payload?.ts??s.ts??null:null,c=Zn(e??[]).filter(d=>d?.kind==="message"&&typeof d.text=="string"&&d.text.trim()).slice(-C$);if(!a&&!c.length)return null;let l=[];if(l.push(`# Reconstructed resume brief \u2014 ${t}`),l.push(""),l.push(Iy[r]??Iy.failover),l.push(""),o.lastPush?.sha){let d=_y(n,o.lastPush.ts),p=d?` (~${d} min before the loss)`:"";l.push(`**Code state:** last pushed ref \`${o.lastPush.ref}\` @ \`${o.lastPush.sha.slice(0,12)}\`${p}`+(o.lastPush.wip?" \u2014 a bostrat WIP snapshot (full working tree incl. uncommitted edits at push time).":"."))}else r==="in-place"?l.push("**Code state:** no push recorded \u2014 the working tree in this workspace is the only copy; commit early."):l.push("**Code state:** no push was ever recorded for this Track \u2014 work since the branch's last known state stayed on the offline node.");if(l.push(""),a){let d=_y(n,i);l.push(`## Last real checkpoint (written by the previous agent${d?`, ~${d} min before this reconstruction`:""})`),l.push(""),l.push(a.trim()),l.push("")}let u=L$(e??[],i);if((u.files.length||u.heads.length)&&(l.push(`## Work since ${a?"that checkpoint":"the start of the log"} (from the event log)`),l.push(""),u.files.length&&l.push(`Files touched (most recent first): ${u.files.map(d=>`\`${d}\``).join(", ")}`),u.heads.length&&(u.files.length&&l.push(""),l.push(`Commands run (most recent first): ${u.heads.map(d=>`\`${d}\``).join(" \xB7 ")}`)),l.push("")),c.length){l.push(`## Recent conversation (last ${c.length} message${c.length===1?"":"s"})`),l.push("");for(let d of c)l.push(`**${d.role==="user"?"operator":"agent"}:** ${B$(d.text,M$)}`),l.push("")}l.push("---"),l.push("Resume: continue the objective above from the verified repository state; ask the operator before redoing anything the log says was already done.");let f=l.join(`
111
- `);return f.length<=Ay?f:`${f.slice(0,Ay)}
112
-
113
- [\u2026 brief truncated]`}var C$,M$,Ay,N$,P$,B$,_y,Iy,$y=O(()=>{qd();C$=12,M$=2e3,Ay=48e3,N$=30,P$=10;B$=(e,t)=>{let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1)}\u2026`},_y=(e,t)=>e&&t?Math.max(1,Math.round((e-t)/6e4)):null;Iy={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 F$ from"node:fs";import Qn from"node:fs/promises";import er from"node:path";function By(e){let t=Cr(String(e??"")),n=Buffer.byteLength(t,"utf8");return n<=Oy?{content:t,bytes:n,truncated:!1}:{content:`${Buffer.from(t,"utf8").subarray(0,Oy).toString("utf8").replace(/�+$/,"")}
114
-
115
- [\u2026 truncated by bostrat at 32 KiB \u2014 full artifact in the workspace]`,bytes:n,truncated:!0}}function J$(e){let t=String(e||"").split(/\r?\n/).map(s=>s.trim()).filter(Boolean),n=[],r=[];for(let s of t)if(My.test(s)){if(r.length>=Wy)continue;let a=z$(s.replace(My,"").replace(/[.;,:]+$/,""),qy,G$);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>Cy&&(o=`${o.slice(0,Cy-1).trimEnd()}\u2026`),{text:o,items:r.length>1?r:[]}}async function Ky(e,t,{timeoutMs:n=9e4}={}){let r=er.join(t,q$),o=er.join(r,K$);await Qn.mkdir(r,{recursive:!0});let s=await Oc(o),a=await se(e);if(!a)throw new Error(`session "${e}" not found`);return await Cc(e,a,V$(o)),await Zy(o,s,n),J$(await Qn.readFile(o,"utf8"))}function Gy(e,t){let n=(t||"").trim();if(!n)return!1;if(e==="assistant")return n===Ly||n===Hy;let r=n.replace(/^\/[a-z0-9:_-]+\s+/i,"");return r.startsWith(jy)||n===U$||r.startsWith(Fy)||r.startsWith(Uy)}function Vy(e){let t=[];for(let r of e?.events||[]){if(r.type!=="lead-handoff"||!r.from)continue;let o=r.at??Date.now(),s=r.handoffStartedAt??o-Y$;t.push({box:r.from,from:s,to:o}),r.to&&r.to!==r.from&&t.push({box:r.to,from:s,to:o})}let n=e?.handoff;return n?.fromBox&&n.startedAt&&n.finishedAt&&t.push({box:n.fromBox,from:n.startedAt,to:n.finishedAt}),n?.toBox&&n.startedAt&&n.finishedAt&&t.push({box:n.toBox,from:n.startedAt,to:n.finishedAt}),t}function zy(e,t){let n=[];for(let r of e?.boxes||[]){let o=t?.(r.name);o?.startedAt&&n.push({box:r.name,from:o.startedAt,to:o.finishedAt||Date.now()+1e12})}return n}function Jy(e,{windows:t=[]}={}){if(Gy(e.role,e.text))return!0;if(e.role!=="assistant"||!e.ts)return!1;for(let n of t)if(e.box===n.box&&e.ts>=n.from&&e.ts<=n.to)return!0;return!1}function Mc(e){return Kd.get(e)||null}async function Yy(e){let t=Kd.get(e);if(t&&!t.finishedAt)throw new Error("a handoff is already running for this session");let n=await se(e);if(!n)throw new Error(`session "${e}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${e}"`);let r={name:e,step:"summarize",startedAt:Date.now(),finishedAt:null,error:null,file:er.join(n.cwd,Py,Dy)};return Kd.set(e,r),Q$(r,n.cwd).catch(o=>{r.error=o?.message||String(o),r.finishedAt=Date.now()}),r}async function Q$(e,t){e.step="summarize",await Xy(e.name,t),e.step="clear";let n=await se(e.name);await Cc(e.name,n,"/clear"),await zd(X$),e.step="resume",await Cc(e.name,n,W$),e.step="done",e.finishedAt=Date.now()}async function Xy(e,t,{timeoutMs:n=Z$}={}){let r=er.join(t,Py),o=er.join(r,Dy);await Qn.mkdir(r,{recursive:!0});let s=await Oc(o),a=await se(e);await Y({flow:"checkpoint",phase:"summarize-start",sessionName:e,cwd:t,file:o,beforeMtime:s}),await Cc(e,a,H$(o)),await Zy(o,s,n),await Y({flow:"checkpoint",phase:"summarize-done",sessionName:e,file:o,afterMtime:await Oc(o)});let i=await oy(t,o,{exclude:u=>Gy(u.role,u.text)});await Y({flow:"checkpoint",phase:"seed-enriched",sessionName:e,file:o,...i});let c=/workspaces[/\\]([0-9a-f]{8})$/.exec(t||"")?.[1];if(c){await _({id:c,cwd:t},{type:"memory.seed",actor:"orchestrator",payload:{...i,tokensEst:i.chars?Math.round(i.chars/4):0,ts:Date.now()}}).catch(()=>{});try{let u=await Qn.readFile(o,"utf8");await _({id:c,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...By(u),ts:Date.now()}})}catch{}}await Vu(t);let l=await eO(r,o);return c&&await Jw(c,l||o,{box:e,agent:a?.agent??null}),o}async function Gd(e,{timeoutMs:t}={}){let n=await se(e);if(!n)throw new Error(`session "${e}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${e}"`);return Xy(e,n.cwd,t?{timeoutMs:t}:void 0)}async function Vd(e,t,{trackName:n="this Track"}={}){let r=await L({id:e,cwd:t}),o=Ry(r,{trackName:n,now:Date.now(),mode:"in-place"});if(!o)return null;let s=er.join(t,Ny);return await Qn.mkdir(er.dirname(s),{recursive:!0}),await Qn.writeFile(s,o,"utf8"),await _({id:e,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...By(o),reconstructed:!0,ts:Date.now()}}).catch(()=>{}),Ny}async function Oc(e){try{return(await Qn.stat(e)).mtimeMs}catch{return 0}}async function Zy(e,t,n){let r=Date.now()+n;for(;;){if(await Oc(e)>t)return;if(Date.now()>r)throw new Error(`timed out waiting for the handoff file to be written (${e})`);await zd(2e3)}}async function eO(e,t){try{if(!F$.existsSync(t))return null;let n=new Date().toISOString().replace(/[:.]/g,"-"),r=er.join(e,`${n}.md`);return await Qn.copyFile(t,r),r}catch{return null}}function zd(e){return new Promise(t=>setTimeout(t,e))}async function Cc(e,t,n){if(t){let o=t.agent==="claude"?process.env.BOSTRAT_AGENT_CMD||"claude":t.agent==="cursor"?process.env.BOSTRAT_CURSOR_CMD||"cursor-agent":t.agent==="codex"?process.env.BOSTRAT_CODEX_CMD||"codex":"";await Xn({cwd:t.cwd,sessionId:t.sessionId,sessionName:e,agent:t.agent,agentCmd:o})}let r=await se(e);if(!r)throw new Error(`session "${e}" disappeared before the orchestration prompt could be sent`);await $e(e,["Escape"],{kind:"drive-wipe"}),await zd(150),await $o(e,mc,{kind:"drive-wipe"}),await Fe(e,n,{kind:"orchestration-drive",...Gt(r.agent,n)})}var Py,Dy,Oy,jy,Ly,Fy,U$,H$,W$,Uy,Hy,q$,K$,Cy,Wy,qy,G$,V$,My,z$,Y$,X$,Z$,Kd,Ny,Jd=O(()=>{tt();Tc();un();ha();sy();zs();ue();ac();$y();Py=".bostrat/handoff",Dy="latest.md",Oy=32*1024;jy="Checkpoint: write a work-in-progress handoff",Ly="HANDOFF WRITTEN",Fy="Resume from .bostrat/handoff/latest.md",U$="/clear",H$=e=>`${jy} to the EXACT absolute path ${e} (write it there specifically \u2014 NOT into any sub-project or other directory; create the directory if needed, overwrite the file) so a FRESH Claude context with none of this conversation can resume seamlessly. Use these sections: Objective; Done (with file paths); In progress (exact state); Next steps (ordered); Key files & commands; Open decisions/blockers; Resume instruction (one line). Be concrete and self-contained \u2014 assume the reader has none of this chat. When the file is written, reply only with ${Ly} and take no further action.`,W$=`${Fy}: read it, restate the Objective and the single next step in one line, then continue the work from 'Next steps'.`,Uy="Beat: write a",Hy="BEAT WRITTEN",q$=".bostrat/arc",K$="beat.txt",Cy=200,Wy=4,qy=5,G$=36,V$=e=>`${Uy} short summary of what this workstream accomplished, to the EXACT absolute path ${e} (write it there specifically \u2014 NOT into any sub-project or other directory; create the directory if needed, overwrite the file). Format the file as: FIRST LINE = one sentence of at most 18 words, plain past tense, saying the outcome \u2014 no heading, no bullet, no trailing list. THEN, only if this workstream covered several separable pieces of work, up to ${Wy} further lines, each starting with "- " and naming ONE piece in at most ${qy} 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 ${Hy} and take no further action.`,My=/^(?:[-–—*•·]|\d+[.)])\s+/,z$=(e,t,n)=>{let r=e.split(/\s+/).filter(Boolean).slice(0,t).join(" ");return r.length>n?`${r.slice(0,n-1).trimEnd()}\u2026`:r};Y$=6e5;X$=3500,Z$=3e5,Kd=new Map;Ny=".bostrat/handoff/status-latest.md"});function eb(e,t,n){if(e==null)return t==="from"?-1/0:1/0;if(!tO.test(String(e)))throw new Error(`pricing.js: ${n} window ${t} must be YYYY-MM-DD, got ${JSON.stringify(e)}`);let r=Date.parse(`${e}T${t==="from"?"00:00:00.000":"23:59:59.999"}Z`);if(!Number.isFinite(r))throw new Error(`pricing.js: ${n} window ${t} is not a real date: ${e}`);return r}function nO(e){let t={};for(let[n,r]of Object.entries(e)){if(!Array.isArray(r)||r.length===0)throw new Error(`pricing.js: ${n} must be a non-empty array of rate windows`);t[n]=r.map(o=>({...o,fromMs:eb(o.from,"from",n),toMs:eb(o.to,"to",n)}))}return t}function oO(e){if(e==null)return Date.now();if(typeof e=="number")return Number.isFinite(e)?e:null;if(e instanceof Date){let n=e.getTime();return Number.isFinite(n)?n:null}let t=Date.parse(String(e));return Number.isFinite(t)?t:null}function sO(e){if(!e)return null;let t=String(e).trim();return Yd[t]?t:Qy[t]?Qy[t]:Object.keys(Yd).find(r=>t.startsWith(r))||null}function tb(e,t){let n=sO(e);if(!n)return null;let r=oO(t);return r===null?null:rO[n].find(o=>r>=o.fromMs&&r<=o.toMs)||null}function tr(e,t={},n){let r=tb(e,n);return r?((t.input||0)*r.input+(t.output||0)*r.output+(t.cacheWrite||0)*r.cacheWrite+(t.cacheRead||0)*r.cacheRead)/1e6:0}var Yd,Qy,tO,rO,nb,xa=O(()=>{Yd={"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)."}]},Qy={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"},tO=/^\d{4}-\d{2}-\d{2}$/;rO=nO(Yd);nb=(e,t)=>tb(e,t)!==null});function aO(e){return e?{input:e.input||0,output:e.output||0,cacheRead:e.cacheRead||0,cacheWrite:e.cacheWrite??e.cacheCreation??0}:null}function ob(e,t){t&&(e.input+=t.input,e.output+=t.output,e.cacheRead+=t.cacheRead,e.cacheCreation+=t.cacheWrite)}function pn(e){let t=e.payload?.model||"unknown",n=aO(e.payload?.tokens),r=Number(e.payload?.usd)||0,o=e.source==="vendor",s=r,a=!1;if(n&&!o){let l=tr(t,n,e.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&&!nb(t,e.ts);return{usd:s,model:t,tokens:n,repriced:a,unpriced:c,asRecorded:r}}function nr(e,{boxLabels:t={}}={}){let n=(e||[]).filter(d=>d.type==="cost.recorded"),r={},o={},s={},a=0,i=0,c=0,l=0,u=new Set,f=rb();for(let d of n){let{usd:p,model:m,tokens:h,repriced:g,unpriced:x,asRecorded:k}=pn(d);i+=k;let E=d.provider||"unknown",I=d.boxId||"unattributed";if(g&&c++,x&&(l++,u.add(m)),a+=p,ob(f,h),r[m]||={usd:0,tokens:rb(),events:0},r[m].usd+=p,r[m].events+=1,ob(r[m].tokens,h),o[E]||={usd:0,events:0},o[E].usd+=p,o[E].events+=1,s[I]||={usd:0,events:0,provider:E,models:new Set,label:t[I]||I},s[I].usd+=p,s[I].events+=1,m!=="unknown"&&s[I].models.add(m),d.epoch!=null){let M=(s[I].epochs||={})[d.epoch]||={usd:0,events:0,provider:E,models:new Set};M.usd+=p,M.events+=1,M.provider=E,m!=="unknown"&&M.models.add(m)}}return{totalUsd:Bo(a),asRecordedUsd:Bo(i),totalTokens:f,turns:n.length,repricedTurns:c,unpricedTurns:l,unpricedModels:[...u],byModel:Nc(r,d=>({...d,usd:Bo(d.usd)})),byProvider:Nc(o,d=>({...d,usd:Bo(d.usd)})),byBox:Nc(s,d=>({usd:Bo(d.usd),events:d.events,provider:d.provider,label:d.label,models:[...d.models],...d.epochs?{epochs:Nc(d.epochs,p=>({usd:Bo(p.usd),events:p.events,provider:p.provider,models:[...p.models]}))}:{}}))}}var rb,Bo,Nc,Fr=O(()=>{xa();rb=()=>({input:0,output:0,cacheRead:0,cacheCreation:0});Bo=e=>Math.round(e*1e4)/1e4,Nc=(e,t)=>Object.fromEntries(Object.entries(e).map(([n,r])=>[n,t(r)]))});function iO(e){if(!Number.isFinite(e)||e<=0)return null;let t=e/864e5;if(t>=1)return`${Math.round(t)}d`;let n=e/36e5;return n>=1?`${Math.round(n)}h`:`${Math.max(1,Math.round(e/6e4))}m`}function sb(e,t=[]){let n=[],r=e?.events||[],o=new Map,s=0;for(let u of t){if(u.type!=="pr.state.changed")continue;let f=u.payload||{};!f.repo||f.number==null||(f.change==="merged"?o.set(`${f.repo}#${f.number}`,f):f.change==="opened"&&s++)}if(o.size){let u=[...o.keys()].map(f=>{let[d,p]=f.split("#");return`${d.split("/").pop()}#${p}`});n.push(`Merged ${u.slice(0,4).join(", ")}${u.length>4?` +${u.length-4}`:""}`)}else s&&n.push(Xd(s,"PR")+" opened");let a=Object.keys(e?.subtasks||{}).length||r.filter(u=>u.type==="subtask-delegated").length;a&&n.push(Xd(a,"subtask"));let i=r.filter(u=>u.type==="lead-handoff"&&u.fromAgent&&u.toAgent);if(i.length){let u=i.slice(0,3).map(f=>`${f.fromAgent}\u2192${f.toAgent}`).join(", ");n.push(`${Xd(i.length,"handoff")} ${u}${i.length>3?"\u2026":""}`)}let c=nr(t);c.totalUsd>=.01&&n.push(`$${c.totalUsd.toFixed(2)}`);let l=Number.isFinite(e?.archivedAt)&&Number.isFinite(e?.createdAt)?iO(e.archivedAt-e.createdAt):null;return n.length&&l&&n.push(l),n.length?n.join(" \xB7 "):null}var Xd,ab=O(()=>{Fr();Xd=(e,t)=>`${e} ${t}${e===1?"":"s"}`});import{execFile as cO}from"node:child_process";import{promisify as lO}from"node:util";import{randomUUID as uO}from"node:crypto";async function Zd(e,t){let n=Date.now()+t;for(;;){if(await dn(e))return!0;if(Date.now()>n)return!1;await Sa(fO)}}async function mO(e,t){let n=cb[t]||cb.default;n.escape&&(await $e(e,["Escape"],{kind:"swap-exit"}),await Sa(150)),n.wipe&&await $o(e,mc,{kind:"swap-exit"}),await hc(e,n.text,{perCharDelayMs:90,kind:"swap-exit"});let r=Gt(t).submitDelayMs||0;await Sa(Math.max(r,250)),await $e(e,["Enter"],{kind:"swap-exit"})}async function lb(e,t){try{let{stdout:n}=await Ur(F,H("show-environment","-t",e,t));return!String(n||"").trimStart().startsWith("-")}catch{return!1}}async function ub(e){await Ur(F,H("respawn-pane","-k","-t",e))}async function Qd(e,t={}){if(!_e(e))throw new Error("invalid session name");let n=String(t.agentCmd||"").trim();if(!n)throw new Error("agentCmd is required");let r=await se(e);if(!r)throw new Error(`session "${e}" not found`);if(!r.cwd)throw new Error(`can't resolve cwd for "${e}"`);let o=r.agent||"agent",s=t.agent||Gn(n),a=Number(t.exitTimeoutMs)||dO;await Y({flow:"swap",phase:"start",sessionName:e,from:o,to:s,cwd:r.cwd});let i=!1;if(!await dn(e)&&(await mO(e,o),!await Zd(e,a)&&(i=!0,await Y({flow:"swap",phase:"respawn-forced",sessionName:e,from:o}),await ub(e),!await Zd(e,ib))))throw new Error(`pane shell did not come back after respawn-pane in "${e}"`);let c=s==="claude"&&Mr(n),l=c?Ui():null,u=await lb(e,"ANTHROPIC_API_KEY"),f=!1;try{l?(await Ur(F,H("set-environment","-t",e,"ANTHROPIC_API_KEY",l)),f=!0):u&&(await Ur(F,H("set-environment","-u","-t",e,"ANTHROPIC_API_KEY")),f=!0)}catch(g){throw l?cc(g,l):g}if(f&&!i&&(await ub(e),!await Zd(e,ib)))throw new Error(`pane shell did not come back after env respawn in "${e}"`);let d=!!t.resumeSessionId,p=t.resumeSessionId||uO(),m=d?n:rd(n,p,e),h=d?t.pinned===!0:/(^|\s)--session-id(\s|=)/.test(m);return c&&await Ln(r.cwd),s==="codex"&&await go(r.cwd),s==="cursor"&&await yo(r.cwd),await Nr(e),await Ur(F,H("set-option","-t",e,"@bostrat-sid",p)),await Ur(F,H("set-option","-t",e,"@bostrat-agent",s)),await Sa(pO),c&&na().length&&(await lb(e,ta)||await Ur(F,H("set-environment","-t",e,ta,"1")).catch(()=>{}),await Fe(e,`export ${ta}=1`,{kind:"swap-env"}),await Sa(150)),await Fe(e,m,{kind:"swap-launch"}),await Y({flow:"swap",phase:"done",sessionName:e,from:o,to:s,sid:p,forced:i,envRespawned:f}),{name:e,cwd:r.cwd,sessionId:p,agent:s,pinned:h,forced:i,envRespawned:f,launchCmd:m}}var Ur,Sa,dO,ib,fO,pO,cb,db=O(()=>{tt();Us();Wi();qi();ha();un();Ur=lO(cO),Sa=e=>new Promise(t=>setTimeout(t,e)),dO=Number(process.env.BOSTRAT_SWAP_EXIT_TIMEOUT_MS)||15e3,ib=Number(process.env.BOSTRAT_SWAP_SHELL_TIMEOUT_MS)||8e3,fO=250,pO=400,cb={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 fb(e,{maxBytes:t=2097152,limit:n=100}={}){let r;try{r=await it(e,t)}catch{return[]}let o=new Map,s=new Set;for(let i of r.split(`
116
- `)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.isSidechain)continue;let u=l.message?.content;if(!Array.isArray(u))continue;let f=l.timestamp?Date.parse(l.timestamp):null;for(let d of u)if(!(!d||typeof d!="object"))if(d.type==="tool_use"&&d.id){if(d.name==="Agent"){let p=d.input||{};o.set(d.id,{id:d.id,kind:"agent",name:String(p.description||"").trim()||null,detail:String(p.subagent_type||"").trim()||null,ts:f,proven:!1})}else if(d.name==="Bash"&&d.input?.run_in_background===!0){let p=String(d.input.command||"").trim();o.set(d.id,{id:d.id,kind:"command",name:String(d.input.description||"").trim()||(p?No(p):null),detail:p?No(p):null,ts:f,proven:!0})}}else d.type==="tool_result"&&d.tool_use_id&&hO.test(wO(d.content))&&s.add(d.tool_use_id)}let a=[];for(let i of o.values()){if(!i.proven&&!s.has(i.id))continue;let{proven:c,...l}=i;a.push(l)}return a.slice(-n)}var hO,wO,pb=O(()=>{Nt();Po();hO=/^Async (?:agent|task) launched/i,wO=e=>{if(typeof e=="string")return e.trim();if(!Array.isArray(e))return"";let t=e.find(n=>n&&n.type==="text"&&typeof n.text=="string");return t?t.text.trim():""}});function rr(e,t){if(!e)return null;let n=String(e);if(t){let o=t.endsWith("/")?t:`${t}/`;if(n===t)return".";if(n.startsWith(o))return n.slice(o.length)||"."}let r=n.split("/").filter(Boolean);return n.startsWith("/")&&r.length>2?r.slice(-2).join("/"):n}function gO(e){let t=typeof e=="string"?e:String(e?.patch??e?.input??""),n=[];for(let r of t.matchAll(/^\*{3} (?:Update|Add|Delete) File: (.+)$/gm))n.push(r[1].trim());return n}function mb(e,t,n){switch(e){case"Shell":{let r=String(t?.command||"").trim();return r?{command:r,description:String(t?.description||"").trim()}:null}case"Read":{let r=t?.path;if(!r)return null;let o=Number(t?.offset)||null,s=o&&Number(t?.limit)?o+Number(t.limit)-1:null;return{command:Pt(`read ${rr(r,n)}${o?` (lines ${o}\u2013${s??"end"})`:""}`,140),description:o?`Read lines ${o}\u2013${s??"end"} of ${jo(r)}`:`Read ${jo(r)}`}}case"Grep":{let r=t?.pattern;if(!r)return null;let o=t?.path?rr(t.path,n):null,s=t?.glob?` --glob ${ef(t.glob)}`:"",a=Pt(String(r),40);return{command:Pt(`grep ${ef(r)}${o&&o!=="."?` ${o}`:""}${s}`,140),description:o&&o!=="."?`Search for \u201C${a}\u201D in ${o}`:`Search for \u201C${a}\u201D`}}case"Glob":{let r=t?.glob_pattern;if(!r)return null;let o=t?.target_directory?rr(t.target_directory,n):null;return{command:Pt(`glob ${ef(r)}${o&&o!=="."?` ${o}`:""}`,140),description:`Find files matching \u201C${Pt(String(r),40)}\u201D`}}case"StrReplace":return t?.path?{command:Pt(`edit ${rr(t.path,n)}`,140),description:`Edit ${jo(t.path)}`}:null;case"Write":return t?.path?{command:Pt(`write ${rr(t.path,n)}`,140),description:`Write ${jo(t.path)}`}:null;case"Delete":return t?.path?{command:Pt(`delete ${rr(t.path,n)}`,140),description:`Delete ${jo(t.path)}`}:null;case"ReadLints":{let o=(Array.isArray(t?.paths)?t.paths:[]).map(s=>rr(s,n)).filter(Boolean);return{command:Pt(o.length?`lints ${o.join(" ")}`:"lints",140),description:"Check lints"}}case"ApplyPatch":{let r=gO(t);if(!r.length)return null;let o=r.length>1?` (+${r.length-1} more)`:"";return{command:Pt(`apply_patch ${rr(r[0],n)}${o}`,140),description:r.length>1?`Patch ${r.length} files`:`Patch ${jo(r[0])}`}}case"Await":{let r=t?.shell_id??t?.task_id;return{command:Pt(`await ${r??"background output"}`,140),description:"Wait for a background command"}}default:return null}}var Pc,Pt,jo,ef,hb=O(()=>{Pc=new Set(["Shell","Read","Grep","Glob","StrReplace","Write","ReadLints","Delete","ApplyPatch","Await"]),Pt=(e,t=88)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,jo=e=>String(e).replace(/\/+$/,"").split("/").pop()||String(e);ef=e=>`"${String(e).replace(/"/g,'\\"')}"`});import va from"node:fs";import yO from"node:fs/promises";import Hr from"node:path";import bO from"node:os";import kO from"node:crypto";import xO from"node:zlib";function yb(e){let t=kO.createHash("md5").update(String(e)).digest("hex");return Hr.join(SO,t)}function bb(e){try{let t=JSON.parse(va.readFileSync(Hr.join(e,"meta.json"),"utf8"));return{createdAtMs:Number(t.createdAtMs)||null,updatedAtMs:Number(t.updatedAtMs)||Number(t.createdAtMs)||null,hasConversation:t.hasConversation===!0}}catch{return null}}function vO(e){let t=yb(e),n;try{n=va.readdirSync(t,{withFileTypes:!0}).filter(o=>o.isDirectory())}catch{return null}let r=null;for(let o of n){let s=Hr.join(t,o.name),a=Hr.join(s,"store.db");if(!va.existsSync(a))continue;let i=bb(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 Dc(e,t){if(!e)return null;if(t){let n=Hr.join(yb(e),t),r=Hr.join(n,"store.db");if(va.existsSync(r))return{id:t,dir:n,store:r,...bb(n)||{createdAtMs:null,updatedAtMs:null}}}return vO(e)}function wb(e,t){let n=e.prepare("SELECT data FROM blobs WHERE id = ?").get(t);return n?Buffer.from(n.data):null}function TO(e){if(!e)return null;let t=e;if(t.length>1&&t[0]===31&&t[1]===139)try{t=xO.gunzipSync(t)}catch{}try{return JSON.parse(t.toString("utf8"))}catch{return null}}function EO(e){let t=[],n=0,r=e.length,o=()=>{let s=0,a=0;for(;n<r;){let i=e[n++];if(s+=(i&127)*2**a,!(i&128))break;a+=7}return s};for(;n<r;){let s=o(),a=s>>>3,i=s&7;if(i===2){let c=o(),l=e.subarray(n,n+c);n+=c,a===1&&c===32&&t.push(l.toString("hex"))}else if(i===0)o();else if(i===5)n+=4;else if(i===1)n+=8;else break}return t}function AO(e,t){if(!Array.isArray(e))return[];let n=[];for(let r of e){if(!r||r.type!=="tool-call"||!Pc.has(r.toolName))continue;let o=mb(r.toolName,r.args,t);!o||!o.command||n.push({id:r.toolCallId||null,tool:r.toolName,command:o.command,description:o.description||""})}return n}async function tf(e,t){if(!gb)return Lo;let{DatabaseSync:n}=gb,r;try{r=new n(e,{readOnly:!0})}catch{return Lo}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 Lo;let s;try{s=JSON.parse(Buffer.from(String(o.value),"hex").toString("utf8"))}catch{return Lo}let a=s.lastUsedModel||null,i=s.latestRootBlobId?wb(r,s.latestRootBlobId):null;if(!i)return{...Lo,model:a};let c=[],l=[],u=[],f=null,d=[];for(let p of EO(i)){let m=TO(wb(r,p));if(!m)continue;let h=m.providerOptions?.cursor;if(h?.requestId&&d.push(h.requestId),h?.modelProviderMessageId&&d.push(h.modelProviderMessageId),m.role!=="assistant")continue;if(Array.isArray(m.content))for(let k of m.content){let E=k?.providerOptions?.cursor?.modelName;E&&(f=E)}l.push(...AO(m.content,t).map((k,E)=>({...k,id:k.id||`${p}:${E}`}))),u.push(...IO(m.content));let g=_O(m.content);if(!g)continue;let x=[...new Set(u)];u=[],c.push({id:p,text:g,tools:x.length?x:void 0,commands:l,model:f}),l=[]}return{turns:c,trailingCommands:l,model:a,requestIds:d}}catch{return Lo}finally{try{r.close()}catch{}}}function kb(e,t){let n=e.updatedAtMs;if(!n)try{n=Math.round(va.statSync(e.store).mtimeMs)}catch{n=Date.now()}let r=e.createdAtMs;(!r||r>n)&&(r=n-t*1e3);let o=Math.max(0,n-r);return{end:n,tsAt:s=>Math.round(r+o*(s+1)/t)}}async function xb(e,t,{limit:n=80}={}){let r=Dc(e,t);if(!r)return[];let{turns:o,model:s}=await tf(r.store,e);if(!o.length)return[];let a=o.slice(-n),{tsAt:i}=kb(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 Sb(e,t){let n=Dc(e,t);if(!n)return null;let{turns:r,requestIds:o,model:s}=await tf(n.store,e);return{chatId:n.id,requestIds:o,models:[...new Set(r.map(a=>a.model).filter(Boolean))],configuredModel:s,updatedAtMs:n.updatedAtMs||null}}async function vb(e,t,{limit:n=80}={}){let r=Dc(e,t);if(!r)return[];let{turns:o,trailingCommands:s}=await tf(r.store,e);if(!o.length&&!s.length)return[];let a=o.slice(-n),{end:i,tsAt:c}=kb(r,a.length||1),l=[];a.forEach((u,f)=>{for(let d of u.commands)l.push({...d,summary:Jn(d.command,d.description),ts:c(f)})});for(let u of s)l.push({...u,summary:Jn(u.command,u.description),ts:i+1});return l}async function Tb(e,t){let n=Dc(e,t);if(!n)return null;if(n.updatedAtMs)return n.updatedAtMs;try{return Math.round((await yO.stat(n.store)).mtimeMs)}catch{return null}}var SO,_O,IO,gb,Lo,nf=O(()=>{Po();hb();SO=process.env.BOSTRAT_CURSOR_CHATS||Hr.join(bO.homedir(),".cursor","chats");_O=e=>typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&t.type==="text"&&typeof t.text=="string").map(t=>t.text).join(`
117
- `).trim():"",IO=e=>Array.isArray(e)?e.filter(t=>t&&t.type==="tool-call"&&t.toolName).map(t=>t.toolName):[],gb=process.getBuiltinModule?.("node:sqlite"),Lo={turns:[],trailingCommands:[],model:null,requestIds:[]}});import RO from"node:fs/promises";function af(e){return Eb.set(e.agent,e),e}function Ta(e){return Eb.get(e)||$O}async function lf(e,t={}){return(await Ta(e.agent).readMessages(e,t)).map(cf(e))}async function Ab(e,t={}){return(await Ta(e.agent).readCommands(e,t)).map(cf(e))}async function _b(e,t={}){return(await Ta(e.agent).readJobs(e,t)).map(cf(e))}var Fo,rf,of,sf,$O,Eb,cf,Ib=O(()=>{Nt();yc();Po();pb();nf();Br();Fo=class{constructor(t,n=new Set){this.agent=t,this.cliTools=n}async readMessages(){return[]}async readCommands(){return[]}async readJobs(){return[]}async updatedAt(){return null}},rf=class extends Fo{transcript(t){return!t?.cwd||!t?.sessionId?null:Mt(t.cwd,t.sessionId)}async readMessages(t,n){let r=this.transcript(t);return r?bd(r,n):[]}async readCommands(t,n){let r=this.transcript(t);return r?Sg(r,n):[]}async readJobs(t,n){let r=this.transcript(t);return r?fb(r,n):[]}async updatedAt(t){let n=this.transcript(t);if(!n)return null;try{return Math.round((await RO.stat(n)).mtimeMs)}catch{return null}}},of=class extends Fo{async readMessages(t,n){return xb(t.cwd,t.sessionId,n)}async readCommands(t,n){return vb(t.cwd,t.sessionId,n)}async updatedAt(t){return Tb(t.cwd,t.sessionId)}},sf=class extends Fo{sessionId(t){return t?.pinned?t.sessionId:null}async readMessages(t,n){return Ag(t.cwd,this.sessionId(t),n)}async readCommands(t,n){return _g(t.cwd,this.sessionId(t),n)}async updatedAt(t){return Ig(t.cwd,this.sessionId(t))}},$O=new Fo("unknown"),Eb=new Map;af(new rf("claude",md));af(new of("cursor",Pc));af(new sf("codex",la));cf=e=>t=>({...t,box:e.name,agent:e.agent,boxRole:e.role})});function Kr(e){let t=e.search(pf);return(t>=0?e.slice(0,t):e).trim()}function OO(e){if(!e)return"";let t=e.replace(/[│┌└├─┘┤┬┴┼─✂].*$/,"").trim();return!t||/hidden|\d+\s+lines?/i.test(t)?"":t}function CO(e){let t=String(e).trim();return!!(!t||qr.test(e)||pf.test(t)||/hidden|\d+\s+lines?/i.test(t)||/notespress|press n to add/i.test(t)||/^\s*notes?\s*$/i.test(t))}function MO(e,t=""){let n=[],r=/([☐☒])\s+([^☐☒←→✔]+)/g,o;for(;(o=r.exec(e))!==null;)n.push({label:o[2].trim(),answered:o[1]==="\u2612",current:!1});if(!n.length)return null;let s=NO(n,t);return n.forEach((a,i)=>{a.current=i===s}),{tabs:n,questionIndex:s,questionTotal:n.length,currentTabLabel:n[s].label}}function NO(e,t){let n=String(t).toLowerCase(),r=e.findIndex(c=>!c.answered),o=r>=0?r:e.length-1;if(!n)return o;let s=e.map(c=>{let l=c.label.toLowerCase(),u=l.split(/\s+/).filter(d=>d.length>3&&n.includes(d)).length;if(u)return u;let f=l.slice(0,8).trim();return f.length>=4&&n.includes(f)?1:0}),a=Math.max(...s);if(a===0||s[o]===a)return o;let i=s.flatMap((c,l)=>c===a?[l]:[]);return i.length===1?i[0]:o}function $b(e){return e.replace(/[←→✔☐☒●▶]/g," ").replace(/\bSubmit\b/g," ").replace(/\s+/g," ").trim()}function PO(e,t=""){let n=String(e);if(!Cb.test(n))return null;let r=n.replace(/\r/g,"").split(`
118
- `),o=-1;for(let u=r.length-1;u>=0;u--)if(/^\s*Switch model\?\s*$/.test(r[u])){o=u;break}if(o<0)return null;let s=[],a=[];for(let u=o+1;u<r.length;u++){let f=r[u].match(Wr);if(f)s.push({cursor:!!f[1],label:f[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let d=r[u].trim();d&&!qr.test(r[u])&&a.push(d)}}if(s.length<2)return null;let i=s.map(u=>({label:Kr(u.label),description:""})),c=Math.max(0,s.findIndex(u=>u.cursor)),l=["Switch model?",...a].join(" ");return{provider:"claude",box:t,multiSelect:!1,cursorIndex:c,promptId:`claude:model-confirm:${i.map(u=>u.label).join("|")}`.slice(0,240),questions:[{question:l,header:"Model",multiSelect:!1,options:i}]}}function BO(e,t=""){let n=String(e).replace(/\r/g,"").split(`
119
- `),r=n.length-1;for(;r>=0&&n[r].trim()==="";)r--;if(r<0||!Mb.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(Wr);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&&!(DO.test(n[c])||qr.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:t,multiSelect:!1,cursorIndex:Math.max(0,s.findIndex(c=>c.cursor)),promptId:`claude:confirm-gate:${i.map(c=>c.label).join("|")}`.slice(0,240),questions:[{question:a.join(" ")||"Claude Code is asking you to confirm",header:"Confirm",multiSelect:!1,options:i}]}}function jO(e,t=""){let n=String(e);if(!/ready to submit your answers/i.test(n))return null;let r=n.replace(/\r/g,"").split(`
120
- `),o=[];for(let c=0;c<r.length;c++){let l=r[c].match(Wr);l&&o.push({cursor:!!l[1],label:l[4].trim()})}let s=o.filter(c=>/^(submit answers|cancel)$/i.test(c.label));if(s.length<2)return null;let a=s.map(c=>({label:c.label,description:""})),i=Math.max(0,s.findIndex(c=>c.cursor));return{provider:"claude",box:t,multiSelect:!1,cursorIndex:i,review:!0,promptId:"claude:review:submit-answers",questions:[{question:"Ready to submit your answers?",header:"Review",multiSelect:!1,options:a}]}}function FO(e,t=""){let n=String(e);if(!uf.test(n))return null;let r=n.replace(/\r/g,"").split(`
121
- `),o=-1;for(let u=r.length-1;u>=0;u--)if(LO.test(r[u])){o=u;break}if(o<0)return null;let s=[],a=[r[o].trim()];for(let u=o+1;u<r.length;u++){let f=r[u].match(Wr);if(f)s.push({cursor:!!f[1],label:f[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let d=r[u].trim();d&&!qr.test(r[u])&&a.push(d)}}if(s.length<2||!s.some(u=>uf.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:t,multiSelect:!1,cursorIndex:c,promptId:`claude:resume-confirm:${i.map(u=>u.label).join("|")}`.slice(0,240),questions:[{question:l,header:"Resume",multiSelect:!1,options:i}]}}function mf(e){let t=[];for(let r=0;r<e.length;r++){let o=e[r].match(Wr);o&&t.push({line:r,cursor:!!o[1],n:Number(o[2]),label:o[4].trim()})}let n=t.sort((r,o)=>r.n-o.n);return n.length<2||n.some((r,o)=>r.n!==o+1)?null:n}function UO(e,t=""){let n=String(e);if(!Nb.test(n)||!Pb.test(n)||Gr.test(n))return null;let r=n.replace(/\r/g,"").split(`
122
- `),o=mf(r);return o?{provider:"claude",box:t,multiSelect:!1,cursorIndex:Math.max(0,o.findIndex(s=>s.cursor)),setup:"theme",promptId:`claude:setup:theme:${o.map(s=>s.label).join("|")}`.slice(0,200),questions:[{question:"Claude Code asks: choose the text style that looks best with your terminal. You can change it later with /theme.",header:"Theme",multiSelect:!1,options:o.map(s=>({label:Kr(s.label),description:""}))}]}:null}function HO(e,t=""){let n=String(e);if(!Db.test(n)||Gr.test(n))return null;let r=n.replace(/\r/g,"").split(`
123
- `),o=mf(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:t,multiSelect:!1,cursorIndex:Math.max(0,o.findIndex(a=>a.cursor)),setup:"login-method",promptId:`claude:setup:login-method:${s.map(a=>a.label).join("|")}`.slice(0,200),questions:[{question:"How do you want to sign in to Claude? A Claude subscription (Pro/Max/Team) uses your existing plan; a Console account bills API usage. Your login stays on this box \u2014 bostrat never sees it.",header:"Log in",multiSelect:!1,options:s}]}}function qO(e,t){let n=e[t].trim();for(let r=t+1;r<e.length;r++){let o=e[r].trim();if(!o||!WO.test(o)||hf.test(e[r]))break;n+=o}return n}function KO(e,t=""){let n=String(e);if(!hf.test(n)||Gr.test(n))return null;let r=n.replace(/\r/g,"").split(`
124
- `),o="";for(let s=0;s<r.length;s++)if(/^\s*https:\/\//.test(r[s])){o=qO(r,s);break}return o?{provider:"claude",box:t,multiSelect:!1,cursorIndex:0,answerMode:"text",setup:"oauth",url:o,inputLabel:"Paste your sign-in code",promptId:"claude:setup:oauth",questions:[{question:"Open the sign-in link, approve access, then paste the code you're shown back here. The code goes straight to the Claude CLI on your box \u2014 bostrat relays the keystrokes and never stores it.",header:"Log in",multiSelect:!1,options:[]}]}:null}function VO(e,t=""){let n=String(e);if(!df.test(n)||!GO.test(n)||Gr.test(n))return null;let s=([...n.replace(/\r/g,"").split(`
125
- `)].reverse().find(a=>df.test(a))||"OAuth error").trim();return{provider:"claude",box:t,multiSelect:!1,cursorIndex:0,setup:"oauth-error",promptId:`claude:setup:oauth-error:${s}`.slice(0,200),questions:[{question:`${s} \u2014 retry to get a fresh sign-in link.`,header:"Log in",multiSelect:!1,options:[{label:"Retry sign-in",description:"Mints a new sign-in link and code"}]}]}}function zO(e,t=""){let n=String(e);if(!Bb.test(n)||Gr.test(n))return null;let r=n.replace(/\r/g,"").split(`
126
- `),o=mf(r);return o?{provider:"claude",box:t,multiSelect:!1,cursorIndex:Math.max(0,o.findIndex(s=>s.cursor)),setup:"trust",promptId:`claude:setup:trust:${o.map(s=>s.label).join("|")}`.slice(0,200),questions:[{question:"Claude Code asks whether it can read, edit, and run files in this workspace. This box's workspace is bostrat-managed scratch space, so trusting it is safe.",header:"Folder trust",multiSelect:!1,options:o.map(s=>({label:Kr(s.label),description:""}))}]}:null}function JO(e,t=""){let n=String(e);if(Gr.test(n))return null;let r=n.replace(/\r/g,"").split(`
127
- `),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(jb);if(!s)return null;let a=[];for(let l=o-1;l>=0&&a.length<3;l--){let u=r[l].trim();if(!u){if(a.length)break;continue}if(qr.test(r[l])||pf.test(u))break;a.unshift(u)}let i=s[1].trim();i&&a.push(i);let c=a.join(" ")||"Claude Code is waiting for you to continue.";return{provider:"claude",box:t,multiSelect:!1,cursorIndex:0,setup:"continue",promptId:`claude:setup:continue:${c}`.slice(0,200),questions:[{question:c,header:"Continue",multiSelect:!1,options:[{label:"Continue",description:""}]}]}}function YO(e){let t=-1;for(let r=e.length-1;r>=0;r--)if(ff.test(e[r])){t=r;break}if(t<0)return null;let n=-1;for(let r=t-1;r>=0;r--)if(/[☐☒]/.test(e[r])){n=r;break}return n<0?null:{headerLine:n,chatLine:t,optStart:n+1,optEnd:t}}function XO(e,t=""){let n=String(e);if(!Ob.test(n)||!ff.test(n))return null;let r=n.replace(/\r/g,"").split(`
128
- `),o=YO(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 j=r[T].match(Wr);j&&(u<0&&(u=T),l.push({line:T,cursor:!!j[1],checked:j[3]!=null&&j[3]!==" ",hasCheckbox:j[3]!=null,label:j[4].trim(),desc:""}))}if(!l.length)return null;for(let T of l)for(let j=T.line+1;j<Math.min(r.length,T.line+4)&&!(Wr.test(r[j])||qr.test(r[j]));j++){let Z=r[j].trim();if(!(!Z||CO(r[j])||Rb.test(Z))){T.desc=OO(Z);break}}let f=l.filter(T=>!Rb.test(T.label));if(!f.length)return null;let d=f.some(T=>T.hasCheckbox),p=Math.max(0,f.findIndex(T=>T.cursor)),m=s>=0?s+1:0,h=[];for(let T=m;T<u;T++){let j=r[T].trim();j&&!qr.test(r[T])&&!/[☐☒]/.test(r[T])&&h.push(j)}let g=h.join(" ")||(s>=0?$b(r[s]):"")||"The agent is asking a question",x=s>=0?MO(r[s],g):null,k=x?.currentTabLabel||(s>=0?$b(r[s]):""),E=f.map(T=>({label:Kr(T.label),description:T.desc})),I=E.map(T=>T.label).join("|"),N=`claude:${x?`q${x.questionIndex+1}/${x.questionTotal}`:"q1/1"}:${k}:${g}:${I}`.slice(0,240),C=x?`claude:ask:${x.tabs.map(T=>T.label).join("|")}`.slice(0,240):N;return{provider:"claude",box:t,multiSelect:d,cursorIndex:p,promptId:N,groupId:C,...x?{questionIndex:x.questionIndex,questionTotal:x.questionTotal,currentTabLabel:x.currentTabLabel,tabs:x.tabs}:{},questions:[{question:g,header:k,multiSelect:d,options:E}]}}function Vr(e,t){let n=String(t||"");return n?e==="claude"?Ob.test(n)&&ff.test(n)||Cb.test(n)||uf.test(n)||Mb.test(n.trimEnd().split(`
129
- `).pop()||"")?!0:Gr.test(n)?!1:Nb.test(n)&&Pb.test(n)||Db.test(n)||hf.test(n)||df.test(n)||Bb.test(n)||jb.test(n.trimEnd().split(`
130
- `).pop()||""):e==="codex"&&/Sign in with ChatGPT|one-time code|Paste or type your API key|link to authenticate|Successfully logged in\.[\s\S]*Press Enter to continue\./i.test(n)?!0:e==="cursor"||e==="codex"?/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i.test(n):!1:!1}function or(e,t){return!e||!t?null:e.agent==="claude"?jO(t,e.name)||XO(t,e.name)||PO(t,e.name)||FO(t,e.name)||VO(t,e.name)||KO(t,e.name)||HO(t,e.name)||UO(t,e.name)||zO(t,e.name)||JO(t,e.name)||BO(t,e.name):e.agent==="cursor"||e.agent==="codex"?Wg(e.agent,t,e.name):null}async function wf(e){if(!e)return null;let t=await fn(e.name).catch(()=>"");return or(e,t)}function Lb(e,t){let n=Array.isArray(t?.[0])?t[0].filter(a=>Number.isInteger(a)&&a>=0):[],r=Number.isInteger(e?.cursorIndex)?e.cursorIndex:0,o=(a,i)=>{let c=i-a;return Array.from({length:Math.abs(c)},()=>c>0?"Down":"Up")},s=[];if(e?.multiSelect){let a=r;for(let i of[...n].sort((c,l)=>c-l))s.push(...o(a,i),"Enter"),a=i;s.push("Tab","Enter")}else{let a=n.length?n[0]:0;s.push(...o(r,a),"Enter")}return s}function Fb(e,t){let n=Number.isInteger(e?.questionIndex)?e.questionIndex:0,o=(Number.isInteger(t)?t:n)-n;if(!o)return[];let s=o>0?"Tab":"BTab";return Array.from({length:Math.abs(o)},()=>s)}var Ob,ff,Wr,Rb,qr,pf,Cb,Mb,DO,uf,LO,Gr,Nb,Pb,Db,hf,WO,df,GO,Bb,jb,gf=O(()=>{tt();kc();Ob=/to navigate\b.*\bEsc to cancel|Enter to select\b/,ff=/Chat about this/i,Wr=/^\s*(❯)?\s*(\d+)\.\s+(?:\[([ xX✔])\]\s+)?(.+?)\s*$/,Rb=/^(type something|chat about this|submit)\b/i,qr=/^[─—-]{6,}\s*$/,pf=/[\u2500-\u257F\u2550-\u256F┌┐└┘├┤│┬┴┼─✂]/;Cb=/^\s*Switch model\?\s*$/m;Mb=/^\s*Enter to confirm\s*·\s*Esc to cancel\s*$/,DO=/^\s*[─—▔-]{6,}\s*$/;uf=/Resume from summary/i,LO=/^\s*This session is\b/;Gr=/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/;Nb=/Choose the text style that looks best with your terminal/,Pb=/Let's get started\./;Db=/Select login method:/;hf=/Paste code here if prompted/,WO=/^[A-Za-z0-9%&=+._~#?/:\-]+$/;df=/OAuth error:/,GO=/Press Enter to retry\./;Bb=/Quick safety check: Is this a project you created or one you trust/;jb=/^(.{0,60}?)Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/});function Bc(e,t,n){if(!e||!t)return null;for(let r of ZO)if(r.provider===e.agent)try{if(r.match(t,n))return r}catch{}return null}function eC(e){let t=yf.get(e);return t||(t={sentAt:[],last:0,emitted:new Set},yf.set(e,t)),t}function Wb(e,t,n=Date.now()){let r=eC(e);if(r.sentAt=r.sentAt.filter(s=>n-s<Hb),r.sentAt.length>=Ub)return{action:"give-up"};if(n-r.last<QO)return{action:"wait"};r.last=n,r.sentAt.push(n);let o=!r.emitted.has(t);return o&&r.emitted.add(t),{action:"send",first:o}}function qb(e,t=Date.now()){let n=yf.get(e);return n?n.sentAt.filter(r=>t-r<Hb).length>=Ub:!1}var ZO,QO,Ub,Hb,yf,bf=O(()=>{ZO=[{provider:"claude",id:"fullscreen-upsell",match(e,t){let n=e?.questions?.[0],r=(n?.options||[]).map(s=>String(s.label||"").trim());if(r.length!==2||!/^Yes, try it$/.test(r[0])||!/^Not now$/.test(r[1]))return!1;let o=`${n?.question||""}
131
- ${String(t||"")}`;return/Try the new fullscreen renderer|Flicker-free output/i.test(o)},keys:["Escape"]}];QO=5e3,Ub=5,Hb=3600*1e3,yf=new Map});function Uo(e){return typeof e=="string"?e.trim():""}var Kb=O(()=>{});import{execFile as tC}from"node:child_process";import{promisify as nC}from"node:util";async function Re(e,t,{input:n}={}){let r=xf("git",["-C",e,...t],{maxBuffer:Gb});return n!==void 0&&r.child.stdin&&(r.child.stdin.on("error",()=>{}),r.child.stdin.end(n)),r}async function Ho(e){if(!e)return!1;try{let{stdout:t}=await Re(e,["rev-parse","--is-inside-work-tree"]);return t.trim()==="true"}catch{return!1}}async function Vb(e){let{stdout:t}=await Re(e,["rev-parse","--show-toplevel"]);return t.trim()}async function rC(e){try{return await Re(e,["rev-parse","--verify","HEAD"]),!0}catch{return!1}}async function Wo(e,t="bostrat: subtask snapshot"){let{stdout:n}=await Re(e,["rev-parse","--absolute-git-dir"]),r=`${n.trim()}/bostrat-snapshot-index`,o={...process.env,GIT_INDEX_FILE:r},s=(a,i)=>xf("git",["-C",e,...a],{maxBuffer:Gb,env:o,...i});try{let a=await rC(e);a&&await s(["read-tree","HEAD"]),await s(["add","-A"]);let{stdout:i}=await s(["write-tree"]),c=i.trim(),l=a?["commit-tree",c,"-p","HEAD","-m",t]:["commit-tree",c,"-m",t],{stdout:u}=await s(l);return u.trim()}finally{try{await xf("rm",["-f",r])}catch{}}}async function Sf(e,t){let{stdout:n}=await Re(e,["status","--porcelain"]);return n.trim()?(await Re(e,["add","-A"]),await Re(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","-m",t]),!0):!1}async function Ea(e,{ignorePlumbing:t=!1}={}){let{stdout:n}=await Re(e,["status","--porcelain"]),r=n.split(`
132
- `).filter(Boolean);return t&&(r=r.filter(o=>{let s=o.slice(3);return!(s===".bostrat"||s===".bostrat/"||s.startsWith(".bostrat/")||o.startsWith("??")&&(s==="AGENTS.md"||s==="CLAUDE.md"))})),r.length>0}async function Aa(e,t){if(!t)return 0;try{let{stdout:n}=await Re(e,["rev-list","--count",`${t}..HEAD`]);return Number(n.trim())||0}catch{return 0}}async function qo(e,t,n,r){return await Re(e,["worktree","add","--no-track","-b",n,t,r]),t}async function zb(e,t){try{return await Re(e,["rev-parse","--verify","--quiet",`refs/heads/${t}`]),!0}catch{return!1}}async function jc(e,t,n){return await Re(e,["worktree","add",t,n]),t}async function Ko(e){if(process.env.BOSTRAT_TRACK_BASE_REF)return process.env.BOSTRAT_TRACK_BASE_REF;try{let{stdout:t}=await Re(e,["symbolic-ref","--short","refs/remotes/origin/HEAD"]);if(t.trim())return t.trim()}catch{}for(let[t,n]of[["refs/remotes/origin/main","origin/main"],["refs/remotes/origin/master","origin/master"],["refs/heads/main","main"],["refs/heads/master","master"]])try{return await Re(e,["rev-parse","--verify","--quiet",t]),n}catch{}return"HEAD"}async function vf(e){await Re(e,["init","-q"]),await Re(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","--allow-empty","-qm","bostrat: track workspace"])}async function pt(e,t){try{await Re(e,["worktree","remove","--force",t])}catch{try{await Re(e,["worktree","prune"])}catch{}}}function oC(e){let t=/(\d+) files? changed/.exec(e),n=/(\d+) insertions?\(\+\)/.exec(e),r=/(\d+) deletions?\(-\)/.exec(e);return{files:t?Number(t[1]):0,insertions:n?Number(n[1]):0,deletions:r?Number(r[1]):0}}function Tf(e,t){return!t||!t.length?e:[...e,"--",".",...t.map(n=>`:(exclude)${n}`)]}async function Ef(e,t,n,r){let{stdout:o}=await Re(e,Tf(["diff","--shortstat",t,n],r));return oC(o)}async function Af(e,t,n,r){let{stdout:o}=await Re(e,Tf(["diff","--name-only",t,n],r));return o.split(`
133
- `).map(s=>s.trim()).filter(Boolean)}async function _f(e,t,n,r){let{stdout:o}=await Re(e,Tf(["diff","--binary",t,n],r));if(!o.trim())return{applied:!0,empty:!0,conflicts:[]};if((await kf(e,o,["--whitespace=nowarn"])).ok)return{applied:!0,empty:!1,conflicts:[]};let s=await kf(e,o,["--3way","--whitespace=nowarn"]),a=await sC(e);return a.length>0?{applied:!1,empty:!1,conflicts:a}:s.ok?{applied:!0,empty:!1,conflicts:[]}:(await kf(e,o,["--reject","--whitespace=nowarn"]),{applied:!1,empty:!1,conflicts:[`patch did not apply cleanly: ${s.err}`]})}async function kf(e,t,n){try{return await Re(e,["apply",...n,"-"],{input:t}),{ok:!0}}catch(r){return{ok:!1,err:r?.stderr?.trim()||r?.message||String(r)}}}async function sC(e){try{let{stdout:t}=await Re(e,["diff","--name-only","--diff-filter=U"]);return t.split(`
134
- `).map(n=>n.trim()).filter(Boolean)}catch{return[]}}var xf,Gb,Lc=O(()=>{xf=nC(tC),Gb=64*1024*1024});import If from"node:fs/promises";import Yb from"node:path";import aC from"node:os";function ek(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(t.getDate()-(t.getDay()+6)%7),t.getTime()}function tk(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(1),t.getTime()}function nk(e){let t=new Date(ek(e));return t.setDate(t.getDate()+7),t.getTime()}function rk(e){let t=new Date(tk(e));return t.setMonth(t.getMonth()+1),t.getTime()}function Uc(e=Date.now()){for(let[t,n]of Object.entries(Go)){let r=n.startOf(e);if(r!==mn[t]){mn[t]=r;for(let o of zr.values())o[t]=0;for(let o of Vo)o.includes(`:${t}:`)&&!o.endsWith(`:${r}`)&&Vo.delete(o)}}}function ok(e,t){let n=Dt?.caps?.[e]?.[Go[t].capKey];return Number.isFinite(n)&&n>0?n:null}function Jr(e,t=Date.now()){if(!e||!$f||!Dt?.caps)return null;Uc(t);let n=zr.get(e);for(let r of Object.keys(Go)){let o=ok(e,r);if(o==null)continue;let s=n?.[r]||0;if(s>=o)return{provider:e,window:r,limitUsd:o,spentUsd:Fc(s),resetsAt:Go[r].nextStart(t)}}return null}function sk(e,t){let n=`hit:${e}:${t.provider}:${t.window}:${mn[t.window]}`;return Vo.has(n)?!1:(Vo.add(n),!0)}function Jb(e,t,n,r=Date.now()){if(!e||!t)return;Uc(r);let o=iC(e);for(let[s,a]of Object.entries(Go))n>=mn[s]&&n<a.nextStart(r)&&(o[s]+=t)}async function cC(e,t,n=Date.now()){if(!Dt?.caps||!Rf)return;let r=zr.get(e);if(r)for(let[o,s]of Object.entries(Go)){let a=ok(e,o);if(a==null)continue;let i=r[o]||0;if(i<a*Qb||i>=a)continue;let c=`warn:${e}:${o}:${mn[o]}`;if(!Vo.has(c)){Vo.add(c);try{let l=await Rf(t);if(!l)continue;await _(l,{type:"usage.cap.warning",actor:"system",provider:e,payload:{provider:e,window:o,limitUsd:a,spentUsd:Fc(i),pct:Math.round(i/a*100),resetsAt:s.nextStart(n)}})}catch{}}}}function ak(e){let t={};for(let[n,r]of Object.entries(e||{})){if(typeof n!="string"||!/^[a-z][a-z0-9-]{0,31}$/.test(n))throw new Error(`bad provider key "${n}"`);let o={};for(let s of["weeklyUsd","monthlyUsd"]){let a=r?.[s];if(a==null||a==="")continue;let i=Number(a);if(!Number.isFinite(i)||i<=0)throw new Error(`${n}.${s} must be a positive number or null`);o[s]=i}Object.keys(o).length&&(t[n]=o)}return t}async function Hc(e,{source:t="local",updatedAt:n=Date.now()}={}){Dt={caps:ak(e),updatedAt:n,source:t};try{await If.mkdir(Xb,{recursive:!0}),await If.writeFile(Zb(),JSON.stringify(Dt,null,2))}catch{}return _a()}function _a(e=Date.now()){Uc(e);let t=new Set([...zr.keys(),...Object.keys(Dt?.caps||{})]),n={};for(let r of t){let o=zr.get(r);n[r]={weeklyUsd:Fc(o?.weekly||0),monthlyUsd:Fc(o?.monthly||0)}}return{caps:Dt?.caps||{},configured:!!Dt,seeded:$f,updatedAt:Dt?.updatedAt??null,spent:n,windows:{weekly:{start:mn.weekly,resetsAt:nk(e)},monthly:{start:mn.monthly,resetsAt:rk(e)}},warnPct:Qb}}async function ik({listTracks:e,getTrack:t}={}){Rf=t||null,Uc();try{let o=JSON.parse(await If.readFile(Zb(),"utf8"));Dt={caps:ak(o?.caps),updatedAt:o?.updatedAt??null,source:o?.source??"file"}}catch{Dt=null}let n=Date.now();st.on("event",o=>{if(o?.type!=="cost.recorded")return;let{usd:s}=pn(o);Jb(o.provider||"unknown",s,o.ts??Date.now()),cC(o.provider||"unknown",o.trackId).catch(()=>{})});let r=Math.min(mn.weekly,mn.monthly);for(let o of await e?.()||[]){let s;try{s=await L(o)}catch{continue}for(let a of s){if(a.type!=="cost.recorded")continue;let i=a.ts??0;i<r||i>=n||Jb(a.provider||"unknown",pn(a).usd,i,n)}}return $f=!0,_a()}var Xb,Zb,Qb,Go,Dt,$f,mn,zr,Vo,Rf,iC,Fc,Wc=O(()=>{ue();Fr();Xb=process.env.BOSTRAT_STATE_DIR||Yb.join(process.env.HOME||aC.tmpdir(),".bostrat"),Zb=()=>Yb.join(Xb,"usage-caps.json"),Qb=.8;Go={weekly:{startOf:ek,nextStart:nk,capKey:"weeklyUsd"},monthly:{startOf:tk,nextStart:rk,capKey:"monthlyUsd"}},Dt=null,$f=!1,mn={weekly:0,monthly:0},zr=new Map,Vo=new Set,Rf=null,iC=e=>{let t=zr.get(e);return t||(t={weekly:0,monthly:0},zr.set(e,t)),t};Fc=e=>Math.round(e*1e4)/1e4});import lC from"node:fs/promises";import uC from"node:os";import ck from"node:path";function hk(e){return e==="codex"?mC:e==="cursor"?mk:fk}function lk(e){let t=String(e||"").split(`
135
- `),n=t.findIndex(o=>/Select Model and Effort/i.test(o));if(n<0)return null;let r=[];for(let o=n+1;o<t.length;o++){let s=t[o].match(/^\s*(›\s*)?(\d+)\.\s+(\S+?)(?:\s+\((current|default)\))?(?:\s{2,}|\s*$)/);if(s)r.push({n:Number(s[2]),id:s[3],current:s[4]==="current",active:!!s[1]});else if(r.length&&/Press enter|esc to go back/i.test(t[o]))break}return r.length?r:null}function uk(e){let t=String(e||"").split(`
136
- `),n=t.findIndex(o=>/Select Reasoning Level/i.test(o));if(n<0)return null;let r=[];for(let o=n+1;o<t.length;o++){let s=t[o].match(/^\s*(›\s*)?(\d+)\.\s+([A-Za-z ]+?)(?:\s+\((default|current)\))?(?:\s{2,}|\s*$)/);if(s)r.push({n:Number(s[2]),label:s[3].trim(),isDefault:!!s[4],active:!!s[1]});else if(r.length&&/Press enter|esc to go back/i.test(t[o]))break}return r.length?r:null}function hC(e){let t=String(e||"").split(`
137
- `);for(let n=t.length-1;n>=0;n--){let r=t[n].match(/Model changed to\s+(\S+)(?:\s+(\S+))?\s*$/i);if(r)return{model:r[1],effort:r[2]||null}}return null}function dk(e){let t=String(e||"").split(`
138
- `),n=t.findIndex(s=>/Available models|Models matching/i.test(s));if(n<0)return null;let r=/Models matching/i.test(t[n]),o=[];for(let s=n+1;s<t.length;s++){let a=t[s];if(/^\s*Filter:/i.test(a)||!a.trim())continue;if(/to filter|Enter to select|^\s*\d+-\d+ of \d+/i.test(a))break;let i=a.match(/^\s*(→\s+)?(.+?)\s*$/);if(!i)continue;let c=i[2].replace(/\s*\(Tab to modify\)\s*$/i,""),l=null,u=c.split(/\s{2,}/);u.length>1&&(c=u[0],l=u.slice(1).join(" ").trim()||null),c&&o.push({label:c.trim(),params:l,active:!!i[1]})}return o.length?{filtered:r,rows:o}:null}function wk(e,t){if(typeof t!="string"||!t.trim())throw new Error("model (string) required");let n=t.trim();if(e==="codex"){let[r,o]=n.split(/[\s:]+/);if(o&&!pk.has(o))throw new Error(`unknown codex effort "${o}" (low | medium | high | xhigh)`);return{model:r,effort:o||null}}if(e==="cursor"){let r=mk.find(o=>o.alias===n);return{model:n,filter:r?r.label:n}}if(!pC.has(n))throw new Error(`unknown model "${n}"`);return{model:n}}async function Ia(e,t,{timeoutMs:n=dC}={}){let r=Date.now()+n;for(;;){let o=await Ae(e,{lines:80}).catch(()=>""),s=t(o);if(s)return s;if(Date.now()>r)return null;await qc(fC)}}async function wC(e,t){return await Fe(e,`/model ${t.model}`,Gt("claude")),{verified:!1,note:"confirmed when the next turn's transcript model flips"}}async function gC(e,t){await pc(e),await Fe(e,"/model",{enter:!1}),await qc(250),await $e(e,["Enter"],{kind:"model-switch"});let n=await Ia(e,lk);if(!n)throw new Error("codex model picker didn't open");let r=n.find(i=>i.id===t.model);if(!r)throw await $e(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`unknown model "${t.model}" \u2014 codex offers: ${n.map(i=>i.id).join(", ")}`);let o=i=>{let c=hC(i);return!c||c.model!==t.model||t.effort&&c.effort&&c.effort.toLowerCase()!==t.effort.toLowerCase()?null:c};await Fe(e,String(r.n),{enter:!1,kind:"model-switch"});let s=await Ia(e,i=>uk(i)||!lk(i)&&o(i)&&{done:o(i)});if(!s)throw await $e(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error("codex reasoning-level picker didn't open");if(!s.done){let i=t.effort?pk.get(t.effort):null,c=i?s.find(l=>l.label.toLowerCase()===i.toLowerCase()):s.find(l=>l.isDefault)||s[0];if(!c)throw await $e(e,["Escape","Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`codex doesn't offer effort "${t.effort}" for ${t.model}`);await Fe(e,String(c.n),{enter:!1,kind:"model-switch"})}let a=s.done||await Ia(e,i=>!uk(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 yC(){let e=ck.join(process.env.CURSOR_CONFIG_DIR||ck.join(uC.homedir(),".cursor"),"cli-config.json");try{return JSON.parse(await lC.readFile(e,"utf8"))?.model||null}catch{return null}}async function bC(e,t){await pc(e),await hc(e,`/model ${t.filter}`,{kind:"model-switch"});let n=await Ia(e,dk),r=c=>String(c||"").toLowerCase(),o=c=>r(c.label).startsWith(r(t.filter)),s=n?.rows.find(c=>c.active)||null;if(n&&!(s&&o(s)))for(let c=0;c<12;c++){let l=await Ia(e,dk,{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 $e(e,["Down"],{kind:"model-switch"}),await qc(250)}if(!n||!s||!o(s)){await $e(e,["Escape"],{kind:"model-switch"}).catch(()=>{});let c=Array(`/model ${t.filter}`.length).fill("BSpace");throw await $e(e,c,{settleMs:15,kind:"model-switch"}).catch(()=>{}),new Error(n?`cursor picker has no model matching "${t.filter}"`:"cursor model picker didn't open")}await $e(e,["Enter"],{kind:"model-switch"}),await qc(800);let a=await yC();return{verified:!!a&&(a.modelId===t.model||a.displayModelId===t.model||r(a.displayName).startsWith(r(t.filter))),model:a?.modelId||null,note:"cursor applies this as the global default for new sessions too"}}async function gk(e,t,n){return e==="codex"?gC(t,n):e==="cursor"?bC(t,n):wC(t,n)}var qc,dC,fC,fk,pC,mC,pk,mk,yk=O(()=>{tt();ha();qc=e=>new Promise(t=>setTimeout(t,e)),dC=Number(process.env.BOSTRAT_MODEL_PICKER_TIMEOUT_MS)||8e3,fC=300,fk=[{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"}],pC=new Set([...fk.map(e=>e.alias),"best","opus[1m]","sonnet[1m]","claude-opus-5","claude-opus-4-8","claude-sonnet-5","claude-sonnet-4-6","claude-haiku-4-5","claude-fable-5"]),mC=[{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"}],pk=new Map([["low","Low"],["medium","Medium"],["high","High"],["xhigh","Extra high"]]),mk=[{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 Gc(e){let t=e||{},n=kC(t);return n&&(n.payload={ts:t.at,...n.payload}),n}function kC(e){switch(e.type){case"said":return{type:"turn.user",actor:"user",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{text:e.text,boxRole:e.boxRole,...e.kind?{kind:e.kind}:{},...e.attachments?.length?{attachments:e.attachments}:{}}};case"unsaid":return{type:"turn.retracted",actor:"user",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{saidTs:e.saidTs,text:e.text,boxRole:e.boxRole}};case"orchestration-prompt":return{type:"turn.user",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{text:e.prompt,kind:e.kind,boxRole:e.boxRole}};case"lead-handoff":return{type:"handoff.done",actor:"orchestrator",source:"orchestrator",boxId:e.to,provider:ct(e.toAgent),payload:{from:e.from,fromAgent:e.fromAgent,to:e.to,toAgent:e.toAgent,reason:e.reason,handoffStartedAt:e.handoffStartedAt,fromSessionId:e.fromSessionId,toSessionId:e.toSessionId,epoch:e.epoch,singleBox:e.singleBox,forced:e.forced,recovered:e.recovered,checkpoint:e.checkpoint}};case"lead-handoff-failed":return{type:"handoff.failed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:ct(e.toAgent),payload:{box:e.box,fromAgent:e.fromAgent,toAgent:e.toAgent,reason:e.reason,error:e.error,rolledBack:e.rolledBack,handoffStartedAt:e.handoffStartedAt}};case"subtask-delegated":return{type:"subtask.delegated",actor:"orchestrator",source:"orchestrator",boxId:e.to,provider:ct(e.toAgent),payload:{task:e.task,subtaskId:e.subtaskId,reason:e.reason}};case"subtask-merged":return{type:"subtask.merged",actor:"orchestrator",source:"orchestrator",boxId:e.box||e.from,provider:ct(e.agent),payload:{...sr(e)}};case"subtask-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box||e.to,provider:ct(e.agent||e.toAgent),payload:{kind:"subtask-failed",...sr(e)}};case"subtask-resumed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{change:"subtask-resumed",...sr(e)}};case"model-change":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:e.box,payload:{change:"model",model:e.to,from:e.from??null,verified:e.verified??null}};case"codex-update":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:"codex",payload:{change:"cli-update",from:e.from??null,to:e.to??null,status:e.status,...e.error?{error:e.error}:{}}};case"node-update":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",payload:{change:"node-update",...sr(e)}};case"opened":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:e.box,payload:{change:"opened",...sr(e)}};case"archived":case"unarchived":case"track-deleted":case"renamed":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:e.type,...sr(e)}};case"rehydrated":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{change:"rehydrated"}};case"transferred-in":return{type:e.mode==="recover"?"track.recovered":"track.transferred",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{...sr(e)}};case"transferred-out":return null;case"retagged":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:"retagged",...sr(e)}};case"rehydrate-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{kind:"rehydrate-failed",reason:e.reason}};default:return null}}function xk(e,t){let n=Gc(t);if(!n)return;let r=t?.type==="track-deleted"?{id:e.id}:e;Cf(()=>_(r,n))}async function Sk(e){if(!(!e?.id||bk.has(e.id))){bk.add(e.id);try{let t=await L(e),n=new Set(t.filter(r=>r.source==="orchestrator").map(r=>`${r.type}|${r.payload?.ts??"?"}`));for(let r of e.events||[]){let o=Gc(r);!o||n.has(`${o.type}|${o.payload?.ts??"?"}`)||await _(e,o)}}catch{}}}function sr(e){let{type:t,at:n,...r}=e;return r}function vk(e,t,n){!n?.promptId||Of.get(e.id)===n.promptId||(Of.set(e.id,n.promptId),Cf(()=>_(e,{type:"prompt.raised",actor:"agent",source:"pane",boxId:t?.name,provider:ct(n.provider||t?.agent),payload:{promptId:n.promptId,question:n.question||n.title||null,options:(n.options||[]).map(r=>r?.label??r).slice(0,12)}})))}function Mf(e,t,n,r={}){Of.delete(e.id),Cf(()=>_(e,{type:"prompt.answered",actor:"user",source:"orchestrator",boxId:t?.name,provider:ct(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}var ct,Kc,Cf,kk,bk,Of,Nf=O(()=>{ue();ct=e=>e||null;Kc=Promise.resolve(),Cf=e=>(Kc=Kc.then(e).catch(()=>{}),Kc),kk=()=>Kc;bk=new Set;Of=new Map});function EC(e){return String(e).split(/(?<=[.?!])\s+|\n+/).map(t=>t.trim()).filter(Boolean)}function Rk(e){let t=String(e||"").trim();if(!t)return null;let n=t.slice(-600);for(let r of EC(n).reverse()){if(!xC.test(r))continue;let o=r.endsWith("?")&&r.length<=TC&&vC.test(r);if(SC.test(r)||o)return r.length>200?r.slice(0,197)+"\u2026":r}return null}function Ok(e){let t=String(e||""),n=[];AC.test(t)&&n.push("commit"),$k.test(t)&&n.push("rebase"),_C.test(t)&&n.push("push");let r=RC.test(t);!r&&IC.test(t)&&n.push("pr");let o=null;if(r){let s=t.match(/(?:pr|pull\s+request)\s*\(?\s*#(\d+)\)?/i)||t.match(/#(\d+)/);o={number:s?Number(s[1]):null}}return{offered:n.length?n:null,toPr:o}}function Ck(e){return $k.test(String(e||""))}function Jo(e,{branch:t=null,base:n=null,toPr:r=null,repos:o=null,offeredRebase:s=!1}={}){Array.isArray(e)||(e=e==="push"?["commit","push"]:["commit","push","pr"]);let a=new Set(e),i=Array.isArray(o)&&o.length>0,c=i?o.map(p=>`${p.name}/`).join(", "):null,l=t?` on this branch (${t})`:"",u=[];if(a.has("commit")&&u.push(i?`commit the work in each changed checkout (${c})${l} with a clear commit message per repo`:`commit the work${l} with a clear commit message`),a.has("rebase")){let p=a.has("commit")?"the branch":`this branch${t?` (${t})`:""}`;u.push(i?`rebase ${p} in each changed checkout (${c}) onto its own base branch (fetch origin first), resolving any conflicts so both sides' intent is preserved`:`rebase ${p} onto ${n?`the latest ${n}`:"its base branch"} (fetch origin first), resolving any conflicts so both sides' intent is preserved`)}if(a.has("push")||a.has("pr")){let p=r&&!a.has("pr")?` (the open PR${r.number?` #${r.number}`:""} picks it up)`:"",m=a.has("rebase")?" with `--force-with-lease` (the rebase rewrote history)":"";i?u.push(a.has("commit")||a.has("rebase")?`push each one to its remote${m}${p}`:`push this branch${t?` (${t})`:""} from each changed checkout (${c}) to its remote${p}`):u.push(a.has("commit")||a.has("rebase")?`push it to the remote${m}${p}`:`push this branch${l} to the remote${p}`)}a.has("pr")&&u.push(i?"open a pull request in each changed repo with a concise title and a description of what changed and why (run `gh pr create` inside each checkout)":`open a pull request${n?` against ${n}`:""} with a concise title and a description of what changed and why (use \`gh pr create\`)`);let f=[];a.has("commit")||f.push("don't create any new commits \u2014 ship what's already committed"),s&&!a.has("rebase")&&f.push("don't rebase \u2014 leave the branch's history as it is"),!a.has("push")&&!a.has("pr")&&f.push("don't push"),a.has("pr")||f.push("don't open a pull request");let d=`Yes \u2014 go ahead: ${u.join(", then ")}.`;return f.length&&(d+=` ${f.join(", and ").replace(/^./,p=>p.toUpperCase())}.`),a.has("pr")&&(d+=i?" If a repo's PR for this branch is already open, just push that repo's update instead.":" If a PR for this branch is already open, just push the update instead."),d}function Mk(e,{branch:t=null,base:n=null,prNumber:r=null,offeredRebase:o=!1}={}){let s=new Set(Array.isArray(e)?e:["commit","push","pr"]),a=t?` on this branch (${t})`:"",i=[];s.has("commit")&&i.push(`commit the work${a} with a clear commit message`),s.has("rebase")&&i.push(`rebase ${s.has("commit")?"the branch":`this branch${t?` (${t})`:""}`} onto ${n?`the latest ${n}`:"its base branch"} (fetch origin first), resolving any conflicts so both sides' intent is preserved`),i.push("move the work to a fresh branch (branch off the current HEAD with a clear new name)"),i.push("push the new branch to the remote"),i.push(`open a pull request${n?` against ${n}`:""} from the new branch with a concise title and a description of what changed and why (use \`gh pr create\`)`);let c=[];s.has("commit")||c.push("don't create any new commits \u2014 ship what's already committed"),o&&!s.has("rebase")&&c.push("don't rebase \u2014 leave the branch's history as it is");let l=`Yes \u2014 go ahead, as a NEW pull request: ${i.join(", then ")}.`;return c.length&&(l+=` ${c.join(", and ").replace(/^./,u=>u.toUpperCase())}.`),l+=` Leave the existing open PR${r?` #${r}`:""}${t?` and its remote branch (${t})`:" and its remote branch"} exactly as they are \u2014 don't push ${t||"the old branch"} itself.`,l}function Nk(e,t=Date.now()){let n=[],r=null;for(let o of e||[]){let s=o.payload||{},a=s.ts??o.ts;if(o.type==="pr.offer.answered"&&s.action==="pr"){r={box:o.boxId,from:a,lastActivity:a};continue}if(o.type==="pr.exists.answered"&&s.choice==="new"){r={box:o.boxId,from:a,lastActivity:a};continue}!r||a==null||a<r.from||(o.type==="pr.offer.answered"||o.type==="pr.exists.answered"?r=null:o.type==="pr.state.changed"&&s.change==="opened"?(n.push({box:r.box,from:r.from,to:a,settled:!0}),r=null):o.type==="turn.user"&&o.source!=="hook"&&!s.kind&&String(s.text||"").trim()?r=null:o.boxId===r.box&&/^(?:turn|tool)\./.test(o.type)&&(r.lastActivity=Math.max(r.lastActivity,a)))}return r&&t-r.lastActivity<=$C&&n.push({box:r.box,from:r.from,to:t+1e12}),n}function Pk(e,t){let n=new Set;for(let r of t||[]){if(!r.settled)continue;let o=null;for(let s of e||[])s.kind!=="message"||s.role!=="assistant"||s.box!==r.box||s.ts==null||s.ts<r.from||s.ts>r.to+OC||(!o||s.ts>=o.ts)&&(o=s);o&&n.add(o)}return n}function Dk(e){let t=(Array.isArray(e)?e:[]).filter(r=>Tk[r]).map(r=>Tk[r]);return`The ship you were given the go-ahead for${t.length?` (${t.join(", then ")})`:""} should now be complete. This is an automated ship notification the operator armed on the offer: carry straight on with this Track's follow-up work (dependent tasks, cleanup, next steps) \u2014 don't wait for review or merge. If a ship step failed or is unfinished, finish the ship first. If nothing needs doing, say so briefly.`}var Ek,Ak,_k,Ik,xC,SC,vC,TC,zo,AC,$k,_C,IC,RC,$C,OC,Tk,Yo=O(()=>{Ek=/(?<!\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,Ak=/(?<!\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,_k=/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,Ik=/(?<!\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,xC=new RegExp(`\\b(?:${Ek}|${Ak}|${_k}|${Ik})\\b`,"i"),SC=/\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,vC=/^(?:commit|push|open|create|raise|rebase|ready|ok(?:ay)?\s+to|good\s+to)\b/i,TC=90;zo=["commit","rebase","push","pr"],AC=new RegExp(`\\b(?:${Ek})\\b`,"i"),$k=new RegExp(`\\b(?:${Ik})\\b`,"i"),_C=new RegExp(`\\b(?:${Ak})\\b`,"i"),IC=new RegExp(`\\b(?:${_k})\\b`,"i"),RC=/\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;$C=3e4;OC=2500;Tk={commit:"commit",rebase:"rebase",push:"push",pr:"open a PR"}});import CC from"node:crypto";import Vc from"node:fs/promises";import Bk from"node:path";import MC from"node:os";async function Ce(){return ar||(Pf??=Vc.readFile(Bf,"utf8").then(e=>({links:JSON.parse(e)?.links??{},existed:!0})).catch(()=>({links:{},existed:!1})).then(async({links:e,existed:t})=>{if(ar=e,!t&&Ee()){let{records:n,source:r}=await je("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;ar[Q(i.repo,i.number)]=i}Object.keys(ar).length&&await jf().catch(()=>{})}}return ar}).finally(()=>Pf=null),Pf)}async function jf(){let e=JSON.stringify({links:ar},null,2),t=`${Bf}.${process.pid}.tmp`;await Vc.mkdir(jk,{recursive:!0}),await Vc.writeFile(t,e),await Vc.rename(t,Bf)}async function Ue(e){Df=Df.then(jf,jf),await Df.catch(()=>{});let t=ar?.[e];t&&et("prlinks",{id:Lk(e),updatedAt:Date.now(),...t},{trackId:t.trackId??null}).catch(()=>{})}async function mt({repo:e,number:t,trackId:n,url:r=null,headRef:o=null,title:s=null,source:a="matched"}){if(!e||!Number.isInteger(Number(t))||!n)return{link:null,created:!1};let i=await Ce(),c=Q(e,t);return i[c]?{link:i[c],created:!1}:(i[c]={repo:e,number:Number(t),trackId:n,url:r,headRef:o,title:s,source:a,announced:NC.has(a),firstSeen:Date.now()},await Ue(Q(e,t)),{link:i[c],created:!0})}async function hn(e,t){if(!e||t==null)return null;let n=(await Ce())[Q(e,t)];return!n||n.announced?null:(n.announced=!0,await Ue(Q(e,t)),n)}async function qe(e,t){return!e||t==null?null:(await Ce())[Q(e,t)]??null}async function ir(e,t,n){if(!e||t==null)return null;let r=(await Ce())[Q(e,t)];return r?(r.state=n,r.resolvedAt=Date.now(),delete r.armedAt,delete r.autoMerge,delete r.archiveOnMerge,delete r.notifyOnMerge,delete r.notifyPending,await Ue(Q(e,t)),r):null}async function Fk(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await Ce())[Q(e,t)];return o?(o.ciFix={delegatedAt:Date.now(),headSha:n,trackId:r},await Ue(Q(e,t)),o):null}async function Uk(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await Ce())[Q(e,t)];return o?(o.reconcile={delegatedAt:Date.now(),headSha:n,trackId:r},await Ue(Q(e,t)),o):null}async function zc(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await Ce())[Q(e,t)];return!r||!r.ciFix?null:(r.ciFixAwait={since:Date.now(),trackId:r.ciFix.trackId??null,headSha:n},delete r.ciFix,await Ue(Q(e,t)),r)}async function Jc(e,t){if(!e||t==null)return null;let n=(await Ce())[Q(e,t)];return!n||!n.ciFixAwait?null:(delete n.ciFixAwait,await Ue(Q(e,t)),n)}async function Yc(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await Ce())[Q(e,t)];return!r||!r.reconcile?null:(r.reconcileAwait={since:Date.now(),trackId:r.reconcile.trackId??null,headSha:n},delete r.reconcile,await Ue(Q(e,t)),r)}async function Xc(e,t){if(!e||t==null)return null;let n=(await Ce())[Q(e,t)];return!n||!n.reconcileAwait?null:(delete n.reconcileAwait,await Ue(Q(e,t)),n)}async function Hk(e,t,{at:n=Date.now()}={}){if(!e||t==null)return null;let r=(await Ce())[Q(e,t)];return r?(r.baseFoldAt=n,await Ue(Q(e,t)),r):null}async function Wk(e,t){if(!e||t==null)return null;let n=(await Ce())[Q(e,t)];return!n||!n.baseFoldAt?null:(delete n.baseFoldAt,await Ue(Q(e,t)),n)}async function qk(e,t,n){if(!e||t==null||!n)return null;let r=(await Ce())[Q(e,t)];return r?(r.lastHeadSha=n,await Ue(Q(e,t)),r):null}async function Kk(e,t,n){if(!e||t==null||!n)return{prev:null,link:null};let r=(await Ce())[Q(e,t)];if(!r)return{prev:null,link:null};let o=r.verdict??null;return o&&o.blocked===(n.blocked??null)&&(o.sha??null)===(n.sha??null)||(r.verdict={blocked:n.blocked??null,sha:n.sha??null,at:n.at??Date.now()},await Ue(Q(e,t))),{prev:o,link:r}}async function Ra(e,t,{merge:n=null}={}){if(!e||t==null)return null;let r=(await Ce())[Q(e,t)];return r?(r.armedAt=Date.now(),n&&(r.autoMerge={method:n.method||"merge",armedAt:r.armedAt}),await Ue(Q(e,t)),r):null}async function Yr(e,t,n=!0){if(!e||t==null)return null;let r=(await Ce())[Q(e,t)];return r?(n?r.archiveOnMerge=!0:delete r.archiveOnMerge,await Ue(Q(e,t)),r):null}async function $a(e,t,n=!0){if(!e||t==null)return null;let r=(await Ce())[Q(e,t)];return r?(n?r.notifyOnMerge=!0:delete r.notifyOnMerge,await Ue(Q(e,t)),r):null}async function Gk(e,t,n){if(!e||t==null)return null;let r=(await Ce())[Q(e,t)];if(!r)return null;r.notifyOnMerge=!0;let o=new Map((r.notifyPending||[]).map(s=>[`${s.repo}#${s.number}`,s]));for(let s of n||[])s&&s.number!=null&&o.set(`${s.repo}#${s.number}`,s);return r.notifyPending=[...o.values()],await Ue(Q(e,t)),r}async function Oa(e,t){if(!e||t==null)return null;let n=(await Ce())[Q(e,t)];return!n||!n.armedAt&&!n.autoMerge?null:(delete n.armedAt,delete n.autoMerge,delete n.archiveOnMerge,delete n.notifyOnMerge,delete n.notifyPending,await Ue(Q(e,t)),n)}async function Vk(){return Object.values(await Ce()).filter(e=>!PC.has(e.state))}async function Xr(){return Object.values(await Ce()).sort((e,t)=>t.firstSeen-e.firstSeen)}async function zk(){if(!Ee())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await je("prlinks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Ce(),r=0;for(let[o,s]of Object.entries(n))await et("prlinks",{id:Lk(o),updatedAt:Date.now(),...s},{trackId:s.trackId??null}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}var jk,Bf,Q,Lk,ar,Pf,Df,NC,PC,wn=O(()=>{Kn();jk=process.env.BOSTRAT_STATE_DIR||Bk.join(process.env.HOME||MC.tmpdir(),".bostrat"),Bf=Bk.join(jk,"pr-links.json"),Q=(e,t)=>`${e}#${Number(t)}`,Lk=e=>{let t=e.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^[^A-Za-z0-9]+/,"").slice(0,55),n=CC.createHash("sha256").update(e).digest("hex").slice(0,8);return`${t||"pr"}-${n}`},ar=null,Pf=null,Df=Promise.resolve();NC=new Set(["api","observed","reconciled"]);PC=new Set(["merged","closed","lost"])});import DC from"node:fs";import Lf from"node:fs/promises";import Zk from"node:path";import BC from"node:os";function t0(e,t=!1){if(!t&&e-Yk<jC)return;Yk=e;let n=JSON.stringify({windowStart:Xo,byCaller:Object.fromEntries(gn),lastHour:cr});Xk=Xk.then(()=>Lf.mkdir(Qk,{recursive:!0})).then(()=>Lf.writeFile(`${Zc}.tmp`,n)).then(()=>Lf.rename(`${Zc}.tmp`,Zc)).catch(()=>{})}function n0(e){e-Xo<e0||(cr={start:Xo,total:Qc(gn),byCaller:Object.fromEntries(gn)},cr.total&&console.log(`[github] ${cr.total} calls last hour`,cr.byCaller),Xo=e,gn=new Map,t0(e,!0))}function yn(e="other",t=Date.now()){n0(t),gn.set(e,(gn.get(e)||0)+1),t0(t)}function r0(e=Date.now()){return n0(e),{windowStart:Xo,total:Qc(gn),byCaller:Object.fromEntries(gn),lastHour:cr,backoffUntil:Zr>e?Zr:null}}function lr(e){return LC.test(String(e?.message||e||""))}function ur(e,t=Date.now()){return Zr<=t&&console.warn(`[github] rate limited \u2014 backing off ${Jk/6e4} min:`,String(e?.message||e||"").slice(0,200)),Zr=Math.max(Zr,t+Jk),Zr}function el(e=Date.now()){return Math.max(0,Zr-e)}var Qk,Zc,e0,Jk,jC,Xo,gn,cr,Zr,Yk,Qc,Xk,LC,Ca=O(()=>{Qk=process.env.BOSTRAT_STATE_DIR||Zk.join(process.env.HOME||BC.tmpdir(),".bostrat"),Zc=Zk.join(Qk,"github-metrics.json"),e0=60*6e4,Jk=5*6e4,jC=6e4,Xo=Date.now(),gn=new Map,cr=null,Zr=0,Yk=0,Qc=e=>[...e.values()].reduce((t,n)=>t+n,0);try{let e=JSON.parse(DC.readFileSync(Zc,"utf8"));e?.windowStart&&(Date.now()-e.windowStart<e0?(Xo=e.windowStart,gn=new Map(Object.entries(e.byCaller||{})),cr=e.lastHour||null):Qc(new Map(Object.entries(e.byCaller||{})))&&(cr={start:e.windowStart,total:Qc(new Map(Object.entries(e.byCaller||{}))),byCaller:e.byCaller||{}}))}catch{}Xk=Promise.resolve();LC=/rate limit|too quickly|abuse detection|HTTP 429/i});import o0 from"node:fs/promises";import s0 from"node:path";import FC from"node:os";function nl({change:e,repo:t=null,number:n=null,githubAt:r=null,observedAt:o=Date.now(),lane:s=null,intervalMs:a=null,source:i=null}){let c=r?o-r:null,l={change:e,repo:t,number:n,githubAt:r,observedAt:o,latencyMs:c,lane:s,intervalMs:a,source:i};tl.push(l),tl.length>HC&&tl.shift();let u=Ff.get(e)||{count:0,measured:0,totalMs:0,maxMs:0};return u.count+=1,c!=null&&(u.measured+=1,u.totalMs+=c,u.maxMs=Math.max(u.maxMs,c)),Ff.set(e,u),WC(l),l}async function WC(e){try{await o0.mkdir(a0,{recursive:!0}),await o0.appendFile(UC,JSON.stringify(e)+`
139
- `)}catch{}}function i0(){let e={};for(let[t,n]of Ff)e[t]={count:n.count,measured:n.measured,avgMs:n.measured?Math.round(n.totalMs/n.measured):null,maxMs:n.measured?n.maxMs:null};return{byChange:e,recent:tl.slice(-20)}}var a0,UC,HC,tl,Ff,rl=O(()=>{a0=process.env.BOSTRAT_STATE_DIR||s0.join(process.env.HOME||FC.tmpdir(),".bostrat"),UC=s0.join(a0,"github-latency.ndjson"),HC=100,tl=[],Ff=new Map});import{execFile as qC}from"node:child_process";import{promisify as KC}from"node:util";async function GC(e){let t=/workspaces[/\\]([0-9a-f]{8})(?:[/\\]|$)/.exec(e||"")?.[1];if(t)try{let[{stdout:n},{stdout:r}]=await Promise.all([Qo("git",["-C",e,"rev-parse","HEAD"]),Qo("git",["-C",e,"rev-parse","--abbrev-ref","HEAD"])]);await _({id:t,cwd:e},{type:"code.pushed",actor:"orchestrator",payload:{ref:r.trim(),sha:n.trim(),wip:!1,ts:Date.now()}})}catch{}}async function vt(e,t,n={}){let{caller:r="prs",...o}=n,s=await qt({cwd:e});yn(r);try{let{stdout:a}=await Qo("gh",t,{cwd:e,...VC,...o,env:{...process.env,...s,...o.env||{}}});return String(a||"")}catch(a){throw lr(a)&&ur(a),a}}async function Wf(){if(ol&&Date.now()-ol.at<6e4)return ol.data;let e;try{yn("auth");let t=await Qo("gh",["auth","status"],{timeout:1e4});e={installed:!0,authenticated:!0,login:`${t.stdout||""}${t.stderr||""}`.match(/account\s+(\S+)/)?.[1]??null}}catch(t){e=t?.code==="ENOENT"||t?.code===127?{installed:!1,authenticated:!1,login:null}:{installed:!0,authenticated:!1,login:null}}if(e.installed&&!e.authenticated)try{let t=await qs();t.configured&&(e={installed:!0,authenticated:!0,login:t.username,via:"broker"})}catch{}return ol={at:Date.now(),data:e},e}async function zC(e){try{let{stdout:t}=await Qo("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});return/github\.com/.test(t)}catch{return!1}}function l0(e){let t=e.name||e.context||"check",n=e.detailsUrl||e.targetUrl||null,r=e.completedAt||e.createdAt||null,o;return e.__typename==="StatusContext"?o=e.state==="SUCCESS"?"pass":e.state==="PENDING"||e.state==="EXPECTED"?"pending":"fail":e.status&&e.status!=="COMPLETED"?o="pending":["SUCCESS","NEUTRAL","SKIPPED"].includes(e.conclusion)?o="pass":o="fail",{name:t,state:o,url:n,completedAt:r}}function Uf(e){let t=(e||[]).map(l0),n=t.filter(s=>s.state==="pending").length,r=t.map(s=>Date.parse(s.completedAt||"")).filter(s=>s>0),o=t.length&&!n&&r.length?Math.max(...r):null;return{total:t.length,passed:t.filter(s=>s.state==="pass").length,failed:t.filter(s=>s.state==="fail").length,pending:n,failing:t.filter(s=>s.state==="fail").map(({name:s,url:a})=>({name:s,url:a})),settledAt:o}}function Kf(e){return/Resource not accessible by personal access token/.test(String(e?.stderr||e?.message||""))}async function d0(e,t){if(!t)return null;let n=await me(e);if(!n)return null;try{let r=await vt(e,["api",`repos/${n}/actions/runs?head_sha=${encodeURIComponent(t)}&per_page=100`,"--jq",".workflow_runs"]),o=new Map;for(let s of JSON.parse(r||"[]"))o.has(s.name)||o.set(s.name,s);return[...o.values()]}catch{return null}}function f0(e){return(e||[]).map(t=>({name:t.name,detailsUrl:t.html_url||null,status:String(t.status||"").toUpperCase(),conclusion:t.conclusion?String(t.conclusion).toUpperCase():null,completedAt:t.status==="completed"&&t.updated_at||null}))}async function p0(e,t){let n=await d0(e,t);return n===null?{...Uf([]),unavailable:!0}:Uf(f0(n))}function sl(e,t=Uf(e.statusCheckRollup)){return{number:e.number,title:e.title,url:e.url,author:e.author?.login??null,headRefName:e.headRefName,headSha:e.headRefOid??null,baseRefName:e.baseRefName,isDraft:!!e.isDraft,reviewDecision:e.reviewDecision||null,mergeable:e.mergeable||"UNKNOWN",mergeStateStatus:e.mergeStateStatus||"UNKNOWN",additions:e.additions??0,deletions:e.deletions??0,createdAt:e.createdAt,updatedAt:e.updatedAt,checks:t,green:t.failed===0&&t.pending===0&&e.mergeStateStatus==="CLEAN",autoMergeArmed:!!e.autoMergeRequest,mergeabilityPending:!1}}function YC(e,t,n){let r=new Set;for(let o of t){let s=`${e}#${o.number}`;if(o.mergeable!=="UNKNOWN"&&o.mergeStateStatus!=="UNKNOWN"){Zo.delete(s);continue}r.add(s),Zo.has(s)||Zo.set(s,n),o.mergeabilityPending=n-Zo.get(s)<JC}for(let o of Zo.keys())o.startsWith(`${e}#`)&&!r.has(o)&&Zo.delete(o);return t}async function es(e,t){let n=await bn(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{let o=await vt(n.path,["pr","view",String(r),"--json",qf]);return sl(JSON.parse(o))}catch(o){if(!Kf(o))throw o;let s=await vt(n.path,["pr","view",String(r),"--json",u0]),a=JSON.parse(s);return sl(a,await p0(n.path,a.headRefOid))}}async function Vt(e,{caller:t="prs"}={}){try{let n=await vt(e,["pr","list","--json",qf,"--limit","50"],{caller:t});return JSON.parse(n||"[]").map(r=>sl(r)).sort(c0)}catch(n){if(!Kf(n))throw n;let r=await vt(e,["pr","list","--json",u0,"--limit","50"],{caller:t});return(await Promise.all(JSON.parse(r||"[]").map(async o=>sl(o,await p0(e,o.headRefOid))))).sort(c0)}}function Jt(){Ma.clear()}async function QC(e,t){if(!e)return t;for(let n of t){let r=await qe(e,n.number).catch(()=>null);if(!r)continue;r.trackId&&(n.trackId=r.trackId),r.autoMerge&&(n.autoMergeArmed=!0),r.archiveOnMerge&&(n.archiveOnMerge=!0),r.notifyOnMerge&&(n.notifyOnMerge=!0);let o=s=>n.headSha&&s.headSha&&n.headSha!==s.headSha;r.ciFix&&(o(r.ciFix)?await zc(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.ciFix={delegatedAt:r.ciFix.delegatedAt,trackId:r.ciFix.trackId??null}),r.reconcile&&(o(r.reconcile)?await Yc(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.reconcile={delegatedAt:r.reconcile.delegatedAt,trackId:r.reconcile.trackId??null})}return t}async function m0(){let e=await Wf();if(!e.authenticated)return{auth:e,repos:[]};let t=[];for(let a of await cn())await zC(a.path)&&t.push(a);let n=Date.now(),r=el(n)>0,o=await Promise.all(t.map(async a=>{let i=Ma.get(a.path),c=i?.pending?ZC:XC;if(i&&(r||n-i.at<c))return i.entry;try{let l=await me(a.path).catch(()=>null),u=YC(a.path,await Vt(a.path,{caller:"tab"}),n);if(await QC(l,u),i?.entry?.prs)for(let p of u)i.entry.prs.find(h=>h.number===p.number)?.checks?.pending>0&&p.checks.total>0&&p.checks.pending===0&&nl({change:p.checks.failed>0?"checks-failed":"checks-green",repo:l||a.name,number:p.number,githubAt:p.checks.settledAt,source:"tab"});let f={name:a.name,path:a.path,prs:u},d=u.some(p=>p.mergeabilityPending||p.checks.pending>0||p.autoMergeArmed);return Ma.set(a.path,{at:Date.now(),entry:f,pending:d}),f}catch(l){return i?i.entry:{name:a.name,path:a.path,prs:[],error:zt(l)}}})),s=new Set(t.map(a=>a.path));for(let a of Ma.keys())s.has(a)||Ma.delete(a);return{auth:e,repos:o}}async function bn(e){let t=(await cn()).find(n=>n.path===e);if(!t)throw new Error(`unknown repo: ${e}`);return t}async function Qr(e){return bo(e)}async function ts(e,t,{method:n="squash"}={}){let r=await bn(e);if(!Na.has(n))throw new Error(`invalid merge method: ${n}`);let o=Number(t);if(!Number.isInteger(o)||o<=0)throw new Error("invalid PR number");let s=["pr","merge",String(o),`--${n}`];if(n!=="rebase"&&(await qt({cwd:r.path})).GH_TOKEN){let a=await Bu().catch(()=>null);a&&s.push("--body",`Merged by bostrat on behalf of @${a}`)}try{await vt(r.path,s)}catch(a){throw new Error(zt(a))}finally{Jt()}return{ok:!0,number:o}}async function Pa(e,t){let n=await bn(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await vt(n.path,["api","-X","PUT",`repos/{owner}/{repo}/pulls/${r}/update-branch`])}catch(s){throw new Error(zt(s))}finally{Jt()}let o=await me(n.path).catch(()=>null);return o&&await Hk(o,r).catch(()=>{}),{ok:!0,number:r}}async function Gf(e,t){let n=await bn(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await vt(n.path,["pr","merge",String(r),"--disable-auto"])}catch(o){throw new Error(zt(o))}finally{Jt()}return{ok:!0,number:r}}function Vf(e){return e.green&&!e.isDraft}function rM(e){return e.isDraft?"draft":e.mergeable==="CONFLICTING"?`conflicts with ${e.baseRefName}`:e.checks.failed>0?"checks failing":e.checks.pending>0?"checks running":e.mergeable==="UNKNOWN"||e.mergeStateStatus==="UNKNOWN"?"mergeability unresolved":e.mergeStateStatus==="BEHIND"?`behind ${e.baseRefName}`:e.mergeStateStatus==="BLOCKED"?"blocked by branch protection":`not clean (${e.mergeStateStatus})`}function h0(e,{update:t=!0}={}){return e.isDraft?{action:"skip",reason:"draft"}:Vf(e)?{action:"merge"}:t&&e.mergeStateStatus==="BEHIND"&&e.mergeable!=="CONFLICTING"&&e.checks.failed===0?{action:"update-arm"}:{action:"arm"}}function w0(e){return[...e.filter(t=>t.plan.action!=="merge"),...e.filter(t=>t.plan.action==="merge")]}function g0(){let e={};for(let[t,n]of Hf)e[t]={...n};return e}async function y0(e,{method:t="merge",onMerged:n=null}={}){let r=await bn(e);if(!Na.has(t))throw new Error(`invalid merge method: ${t}`);if(Hf.get(r.path)?.running)throw new Error("a merge-all is already running for this repo");let o=(await Vt(r.path)).filter(Vf).sort((a,i)=>Date.parse(a.createdAt)-Date.parse(i.createdAt));if(!o.length)throw new Error("no PRs ready to merge");let s={running:!0,startedAt:Date.now(),finishedAt:null,method:t,total:o.length,current:o[0].number,queue:o.map(a=>({number:a.number,title:a.title})),merged:[],skipped:[],failed:[]};return Hf.set(r.path,s),sM(s,o,{listPrs:()=>Vt(r.path),merge:a=>ts(r.path,a,{method:t}),sleep:nM,onMerged:n}).catch(()=>{}),{ok:!0,repo:r.path,total:s.total,queue:o.map(a=>a.number)}}async function oM(e,t){let n=Date.now()+(t.settleMaxMs??tM),r=null;for(;;){let o=null;try{if(o=await t.listPrs(),r=null,!o.some(a=>e.includes(a.number)&&(a.mergeable==="UNKNOWN"||a.mergeStateStatus==="UNKNOWN")))return o}catch(s){r=s}if(Date.now()>=n){if(o)return o;if(r)throw r;return[]}await t.sleep(eM)}}async function sM(e,t,n){try{let r=t;for(let o=0;o<t.length;o++){let s=t[o];if(e.current=s.number,o>0)try{r=await oM(t.slice(o).map(i=>i.number),n)}catch(i){for(let c of t.slice(o))e.failed.push({number:c.number,title:c.title,reason:`couldn't re-check PR state: ${zt(i)}`});break}let a=r.find(i=>i.number===s.number);if(!a){e.skipped.push({number:s.number,title:s.title,reason:"no longer open"});continue}if(!Vf(a)){e.skipped.push({number:a.number,title:a.title,reason:rM(a)});continue}try{await n.merge(a.number),e.merged.push({number:a.number,title:a.title});try{await n.onMerged?.(a)}catch{}}catch(i){e.failed.push({number:a.number,title:a.title,reason:zt(i)})}}}finally{e.current=null,e.running=!1,e.finishedAt=Date.now(),Jt()}}async function zf(e,{title:t,body:n="",base:r=null}={}){if(typeof t!="string"||!t.trim())throw new Error("title required");try{await Qo("git",["-C",e,"push","-u","origin","HEAD"],{timeout:12e4,maxBuffer:4*1024*1024})}catch(l){throw new Error(`push failed: ${zt(l)}`)}await GC(e);let o=n||"";if((await qt({cwd:e})).GH_TOKEN){let l=await Bu().catch(()=>null);l&&(o=`${o?`${o}
140
-
141
- `:""}Opened by bostrat on behalf of @${l}`)}let s=["pr","create","--title",t.trim(),"--body",o];r&&s.push("--base",r);let a;try{a=await vt(e,s)}catch(l){throw new Error(zt(l))}finally{Jt()}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 b0(e,t){let n=await bn(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");let o;try{let i;try{i=await vt(n.path,["pr","checks",String(r),"--json","name,state,link,bucket"])}catch(c){if(i=String(c?.stdout||""),!i.trim())throw new Error(zt(c))}o=JSON.parse(i||"[]").filter(c=>c.bucket==="fail")}catch(i){if(!Kf(i))throw i;let c=await vt(n.path,["pr","view",String(r),"--json","headRefOid"]),l=await d0(n.path,JSON.parse(c).headRefOid);if(l===null)throw new Error(zt(i));o=f0(l).map(l0).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=aM(i.link),l=null;c&&!s.has(c)&&(s.add(c),l=await vt(n.path,["run","view",c,"--log-failed"]).then(u=>iM(u)).catch(()=>null)),a.push({name:i.name,link:i.link||null,log:l})}return a}function aM(e){return String(e||"").match(/\/actions\/runs\/(\d+)/)?.[1]??null}function iM(e,{maxLines:t=400,maxBytes:n=64*1024}={}){let r=String(e||""),o=r.split(`
113
+ `});function j$(e){return{id:e.id,kind:"prompt",groupId:e.groupId,provider:e.provider,box:e.box,agent:e.provider,questionTotal:e.questions.length,answeredVia:"chat",questions:e.questions.map((t,n)=>({index:n,header:t.header||"",question:t.question,multiSelect:!!t.multiSelect,chosen:[]})),ts:e.ts}}function F$(e,t,n){let r=Iy(n),o=e.has(r)?r:null;if(!o&&n.number!=null)for(let[i,c]of e){if(Number(c.number)!==Number(n.number))continue;let l=!!(n.url&&c.url&&n.url===c.url),u=!c.repo&&!!n.repo||!!c.repo&&!n.repo;if(l||u&&(!c.url||!n.url||c.url===n.url)){o=i;break}}let s=n.repo||!o?r:o,a=o?e.get(o):e.get(s);if(o&&o!==s){e.delete(o);let i=t.get(o);if(t.delete(o),i?.length){let c=t.get(s)??[];t.set(s,c.concat(i))}}return e.set(s,{number:n.number,url:n.url??a?.url??null,title:n.title??a?.title??null,repo:n.repo??a?.repo??null,branch:n.branch??a?.branch??null}),s}function Zn(e){let t=[],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=new Map,f=(y,w)=>{u.set(y,w),t.push(w)},d=y=>{let w=u.get(y);w&&(w.retired=!0)},p=/^Agent "([\s\S]+)" finished$/,m=new Map;for(let y of e||[]){if(y.type!=="tool.called"||y.source!=="transcript")continue;let w=String(y.payload?.command||"");if(/\bbostrat-mock\s+(?:add|update)\b/.test(w))for(let v of w.matchAll(/[\w./~-]+\.(?:png|jpe?g|gif|webp|bmp|svg)\b/gi)){let $=v[0].split("/").pop().toLowerCase();m.has($)||m.set($,[]),m.get($).push(y.payload?.ts??y.ts)}}let h=3*6e4,g=20*6e4,x=(y,w)=>!!(y?.name&&m.get(String(y.name).toLowerCase()))?.some($=>$>=w-h&&$<=w+g);for(let y of e||[])if(y.type==="turn.retracted"){r.add(`${y.boxId}|${y.payload?.saidTs}`);let w=Oe(y.payload?.text);w&&(o.has(y.boxId)||o.set(y.boxId,[]),o.get(y.boxId).push(w))}else if(y.type==="turn.user"&&y.source==="orchestrator"){let w=Oe(y.payload?.text);w&&(s.has(y.boxId)||s.set(y.boxId,new Set),s.get(y.boxId).add(w))}else if(y.type==="job.started"&&y.payload?.id)a.add(y.payload.id),(y.payload.kind||"agent")==="agent"&&y.payload.name&&c.add(y.payload.name);else if(y.type==="turn.user"&&y.payload?.note?.kind==="task"){let w=y.payload.note,v={status:w.status||null,summary:w.summary||null,resultHead:w.resultHead??null,ts:de(y)};w.toolUseId&&i.set(w.toolUseId,v);let $=String(w.summary||"").match(p);$&&l.set($[1],v)}let k=new Map,E=new Map,I=null,M=new Map,N=new Map,O=new Map,T=new Map,j=new Map,Z=new Map,fe=new Map,ie=new Map,D=new Map,R=new Map,U=new Map,pe=new Map,Se=new Map,He=()=>{for(let y of Se.values())y.questions.length&&t.push(y);Se.clear()},le=null,q=6e4,J=new Map,ee=(y,w)=>{let v=o.get(y);if(!v?.length)return!1;let $=Oe(w),ve=s.get(y);return v.some(b=>{if(!$.startsWith(b))return!1;let P=Oe($.slice(b.length));return!!P&&!!ve?.has(P)})};for(let y of e||[]){let w=y.payload||{};switch(y.type){case"turn.user":{if(y.source==="hook"||!String(w.text||"").trim()&&!w.images?.length&&!w.attachments?.length)break;{let v=w.note||Nc(w.text);if(v){if(v.kind==="task"){if(v.toolUseId&&a.has(v.toolUseId))break;let $=String(v.summary||"").match(p);if(!v.toolUseId&&$&&c.has($[1]))break}if(v.kind==="command"&&xy(v.command))break;if(v.kind==="resume-summary"){t.push({id:y.id,kind:"resume-summary",title:v.title||"Context resumed from summary",bullets:v.bullets||[],sections:v.sections||[],rawChars:v.rawChars??null,ts:de(y),box:y.boxId,agent:y.provider});break}v.kind!=="suppress"&&t.push({id:y.id,kind:"event",type:vy(v),name:v.name??null,command:v.command??null,summary:v.summary??null,status:v.status??null,ts:de(y),box:y.boxId,agent:y.provider});break}}if(r.has(`${y.boxId}|${de(y)}`)||y.source==="transcript"&&ee(y.boxId,w.text))break;if(w.kind==="merge-notify"||w.kind==="ship-notify"){t.push({id:y.id,kind:"event",type:w.kind==="ship-notify"?"ship-notified":"merge-notified",text:w.text,ts:de(y),box:y.boxId,agent:y.provider});break}if(w.kind==="mock-picked"||w.kind==="ci-fix"||w.kind==="reconcile"||w.kind==="pr-go"||w.kind==="push-go"||w.kind==="spin-up-view"||w.kind==="prompt-answer"){w.kind==="prompt-answer"&&(le=null);break}for(let v of M.values())v.status="stale";M.clear();for(let v of O.values())v.status="stale";O.clear(),le&&le.box===y.boxId&&(t.push(j$(le)),le=null),t.push({id:y.id,kind:"message",role:"user",text:w.text,ts:de(y),box:y.boxId,agent:y.provider,boxRole:w.boxRole,...y.actor==="orchestrator"?{orchestration:w.kind||!0}:{},...w.sourceId?{sourceId:w.sourceId}:{},...w.attachments?.length?{attachments:w.attachments}:{},...w.images?.length?{images:w.images}:{}});break}case"peer.message":{let v=w.from||{};t.push({id:y.id,kind:"event",type:"peer-message",text:w.text,from:v.trackName||v.boxId||v.name||null,fromTrackId:v.trackId||null,ts:de(y),box:y.boxId,agent:y.provider});break}case"turn.agent":{if(w.model==="<synthetic>"&&/^No response requested\.$/.test(String(w.text||"").trim()))break;let v=Bg(w,{codexFailedText:Pr});if(v){t.push({id:y.id,kind:"event",type:"provider-error",cls:v.cls,status:v.status??void 0,text:v.text,provider:y.provider,legacy:!0,at:de(y),ts:de(y),box:y.boxId,agent:y.provider});break}He();let $=(w.images||[]).filter(Me=>!x(Me,de(y)));if(!String(w.text||"").trim()&&!$.length)break;if(y.provider==="cursor"){let Me=`${y.boxId}|${w.text}`;if(n.has(Me))break;n.add(Me)}(!le||le.box===y.boxId)&&(le=null);let ve=y.provider==="codex"?(w.tools||[]).filter(Me=>!xd.has(Me)&&!pa.has(Me)):w.tools||[],b=w.text,P=null;if(qd.has(y.provider)){let Me=Kd(String(w.text||""));Me&&(b=Me.text,P={questions:Me.questions})}t.push({id:y.id,kind:"message",role:"assistant",text:b,ts:de(y),box:y.boxId,agent:y.provider,boxRole:w.boxRole,...P?{ask:P}:{},...ve.length?{tools:ve}:{},...w.model?{model:w.model}:{},...w.sourceId?{sourceId:w.sourceId}:{},...$.length?{images:$}:{}}),P&&(le={id:y.id,groupId:Gd(y.provider,w.sourceId||y.id,P.questions),provider:y.provider,box:y.boxId,questions:P.questions,ts:de(y)});break}case"job.started":{if(!w.id)break;let v=de(y),$=i.get(w.id);if(!$&&(w.kind||"agent")==="agent"&&w.name){let We=l.get(w.name);We&&We.ts>=v&&($=We)}let ve={jobId:w.id,jobKind:w.kind||"agent",name:w.name||null,detail:w.detail||null,status:$?$.status==="killed"?"stopped":$.status&&$.status!=="completed"?"failed":"done":"running",startedTs:v,finishedTs:$?.ts??null,summary:$?.summary??null,resultHead:$?.resultHead??null},b=J.get(y.boxId),P=b?.jobs[b.jobs.length-1]?.startedTs;if(b&&P!=null&&v-P<=q)b.jobs.push(ve);else{let We={id:y.id,kind:"job-dock",dockId:w.id,ts:v,box:y.boxId,agent:y.provider,jobs:[ve]};J.set(y.boxId,We),t.push(We)}break}case"handoff.done":t.push(St(y,"lead-handoff"));break;case"subtask.delegated":t.push({...St(y,"subtask-delegated"),to:y.boxId,toAgent:y.provider});break;case"subtask.merged":t.push(St(y,"subtask-merged"));break;case"pr.state.changed":{if(!w.change)break;if(w.change==="opened"){for(let $ of M.values())$.status="stale";M.clear();for(let $ of O.values())$.status="stale";O.clear()}let v=St(y,`pr-${w.change}`);if(v.box=y.boxId??null,L$.has(w.change)&&w.number!=null){let $=F$(k,E,w);if(k.size>=2){for(let b of E.values())for(let P of b)P.grouped=!0;v.groupPrs=[...k.values()];let ve=[v];for(let b of k.keys())E.set(b,ve)}else{let ve=E.get($)??[];ve.push(v),E.set($,ve)}}else if(w.change==="merged"||w.change==="closed"||w.change==="lost"){let $=Iy(w),ve=I&&!I.complete||k.size>=2;if(k.has($))k.delete($),E.delete($);else if(w.number!=null)for(let b of[...k.keys()])b.endsWith(`#${w.number}`)&&(k.delete(b),E.delete(b));if(ve&&w.number!=null){(!I||I.complete)&&(I={id:y.id,kind:"event",type:"pr-group-settled",prs:[],remaining:[],complete:!1,at:de(y),ts:de(y),box:y.boxId,agent:y.provider},t.push(I)),I.prs.push({number:w.number,url:w.url??null,title:w.title??null,repo:w.repo??null,branch:w.branch??null,change:w.change,ts:de(y)}),I.remaining=[...k.values()],I.complete=k.size===0;break}}t.push(v);break}case"pr.offered":{if(!w.offerId)break;for(let $ of M.values())$.status="stale";M.clear();for(let $ of O.values())$.status="stale";O.clear();let v={id:y.id,kind:"pr-offer",offerId:w.offerId,excerpt:w.excerpt||null,branch:w.branch||null,base:w.base||null,offered:Array.isArray(w.offered)&&w.offered.length?w.offered:null,toPr:w.toPr&&typeof w.toPr=="object"?{number:w.toPr.number??null}:null,available:Array.isArray(w.available)?w.available:null,defaults:Array.isArray(w.defaults)?w.defaults:null,prState:w.prState||null,openPr:w.openPr&&typeof w.openPr=="object"?w.openPr:null,repos:Array.isArray(w.repos)&&w.repos.length?w.repos:null,status:"open",ts:de(y),box:y.boxId,agent:y.provider};M.set(w.offerId,v),N.set(w.offerId,v),t.push(v);break}case"pr.offer.answered":{let v=N.get(w.offerId);v&&(v.status=w.action||"dismiss",v.actions=Array.isArray(w.actions)?w.actions:null,v.notify=w.notify===!0,w.existingPr&&typeof w.existingPr=="object"&&(v.existingPr={number:w.existingPr.number??null}),M.delete(w.offerId));break}case"pr.exists.offered":{if(!w.offerId)break;for(let $ of O.values())$.status="stale";O.clear();let v={id:y.id,kind:"pr-exists-offer",offerId:w.offerId,srcOfferId:w.srcOfferId??null,branch:w.branch||null,base:w.base||null,pr:w.pr&&typeof w.pr=="object"?{number:w.pr.number??null,url:w.pr.url??null,title:w.pr.title??null}:null,actions:Array.isArray(w.actions)&&w.actions.length?w.actions:null,notify:w.notify===!0,status:"open",ts:de(y),box:y.boxId,agent:y.provider};O.set(w.offerId,v),T.set(w.offerId,v),t.push(v);break}case"pr.exists.answered":{let v=T.get(w.offerId);v&&(v.status=w.choice||"dismiss",O.delete(w.offerId));break}case"box.state.changed":{let v=w.change==="model"?"model-change":w.change;if(!v)break;let $=St(y,v);if(v==="model-change"&&($.to=w.model),v==="node-update"&&$.latest){let ve=t.findIndex(b=>b.kind==="event"&&b.type==="node-update"&&b.latest===$.latest);if(ve>=0){let b=t[ve];t[ve]={...$,ts:b.ts,at:b.at,firstAt:b.firstAt??b.ts,updatedAt:$.ts};break}}t.push($);break}case"track.transferred":case"track.recovered":t.push(St(y,"track-moved"));break;case"view.state.changed":{if(w.change==="deleted"){d(`view:${w.viewId}`);break}if(w.change!=="created"||w.restarted)break;f(`view:${w.viewId}`,{id:y.id,kind:"view-card",viewId:w.viewId,name:w.name,slug:w.slug,port:w.port,origin:w.origin,ts:de(y),box:y.boxId,agent:y.provider});break}case"view.spinup.failed":{t.push({id:y.id,kind:"view-spinup-failed",name:w.name||null,reason:w.reason||"no-view",ts:de(y),box:y.boxId,agent:y.provider});break}case"mock.state.changed":{if(w.change==="picked"){t.push({id:y.id,kind:"mock-picked",mockId:w.mockId,name:w.name,group:w.group??null,version:w.version??null,siblings:w.siblings??[],ts:de(y),box:y.boxId,agent:y.provider});break}if(w.change==="deleted"){d(`mock:${w.mockId}`);break}if(w.change!=="created")break;f(`mock:${w.mockId}`,{id:y.id,kind:"mock-card",mockId:w.mockId,name:w.name,group:w.group??null,ts:de(y),box:y.boxId,agent:y.provider});break}case"flow.state.changed":{if(w.change==="deleted"){d(`flow:${w.flowId}`);break}if(w.change!=="created")break;f(`flow:${w.flowId}`,{id:y.id,kind:"flow-card",flowId:w.flowId,name:w.name,stepCount:w.stepCount??null,mockIds:w.mockIds??[],ts:de(y),box:y.boxId,agent:y.provider});break}case"runbook.state.changed":{if(w.change==="deleted"){d(`runbook:${w.runbookId}`);break}if(w.change!=="created")break;f(`runbook:${w.runbookId}`,{id:y.id,kind:"runbook-card",runbookId:w.runbookId,name:w.name,ts:de(y),box:y.boxId,agent:y.provider});break}case"ticket.linked":{t.push({id:y.id,kind:"ticket-card",provider:w.provider||"linear",key:w.key,url:w.url,title:w.title??null,linkSource:w.linkSource??null,ts:de(y),box:y.boxId,agent:y.provider});break}case"box.fullscreen.detected":{if(!w.offerId)break;for(let $ of fe.values())$.box===(w.box||y.boxId)&&($.status="stale",fe.delete($.offerId));let v={id:y.id,kind:"fullscreen-offer",offerId:w.offerId,status:"open",ts:de(y),box:w.box||y.boxId,agent:w.agent||y.provider};fe.set(w.offerId,v),ie.set(w.offerId,v),t.push(v);break}case"box.fullscreen.answered":{let v=ie.get(w.offerId);v&&(v.status=w.action==="restarted"?"restarted":w.action==="cleared"?"cleared":"dismiss",fe.delete(w.offerId));break}case"ticket.move.offered":{if(!w.offerId)break;for(let $ of j.values())$.key===w.key&&($.status="stale",j.delete($.offerId));let v={id:y.id,kind:"ticket-offer",offerId:w.offerId,provider:w.provider||"linear",key:w.key,url:w.url??null,phase:w.phase??null,from:w.from??null,to:w.to?.name??null,prNumber:w.prNumber??null,status:"open",ts:de(y),box:y.boxId,agent:y.provider};j.set(w.offerId,v),Z.set(w.offerId,v),t.push(v);break}case"ticket.move.answered":{let v=Z.get(w.offerId);v&&(v.status=w.action==="moved"?"moved":"dismiss",j.delete(w.offerId));break}case"ticket.state.changed":{for(let v of j.values())v.key===w.key&&v.to===w.to&&(v.status="stale",j.delete(v.offerId));if(w.mode==="offer")break;t.push(St(y,"ticket-state"));break}case"ticket.commented":{t.push({id:y.id,kind:"ticket-comment",key:w.key,url:w.url??null,excerpt:w.excerpt??null,ts:de(y),box:y.boxId,agent:y.provider});break}case"ticket.flow.changed":t.push(St(y,"ticket-flow"));break;case"ticket.create.offered":{if(!w.proposalId)break;for(let $ of D.values())$.status="stale";D.clear();let v={id:y.id,kind:"ticket-create-offer",proposalId:w.proposalId,provider:w.provider||"linear",epic:w.epic??null,issues:Array.isArray(w.issues)?w.issues:[],team:w.team??null,needsTeam:!!w.needsTeam,linkCurrentTrack:!!w.linkCurrentTrack,status:"open",ts:de(y),box:y.boxId,agent:y.provider};D.set(w.proposalId,v),R.set(w.proposalId,v),t.push(v);break}case"ticket.create.answered":{let v=R.get(w.proposalId);v&&(v.status=w.action==="created"?"created":"dismiss",v.createdCount=w.createdCount??null,v.failedCount=w.failedCount??null,D.delete(w.proposalId));break}case"loop.create.offered":{if(!w.proposalId)break;for(let $ of U.values())$.status="stale";U.clear();let v={id:y.id,kind:"loop-create-offer",proposalId:w.proposalId,name:w.name??"",schedule:w.schedule??"",prompt:w.prompt??"",expectation:w.expectation??null,notify:w.notify??"off",assignment:w.assignment??{provider:"claude"},repo:w.repo??null,nodeId:w.nodeId??null,nodeName:w.nodeName??null,status:"open",ts:de(y),box:y.boxId,agent:y.provider};U.set(w.proposalId,v),pe.set(w.proposalId,v),t.push(v);break}case"loop.create.answered":{let v=pe.get(w.proposalId);v&&(v.status=w.action==="created"?"created":"dismiss",U.delete(w.proposalId));break}case"loop.created":{let v=w.proposalId?pe.get(w.proposalId):null;v&&(v.created={loopId:w.loopId??null,nextFireAt:Number.isFinite(Number(w.nextFireAt))?Number(w.nextFireAt):null});break}case"ticket.created":{let v={items:Array.isArray(w.items)?w.items:[],failed:Array.isArray(w.failed)?w.failed:[],team:w.team??null},$=w.proposalId?R.get(w.proposalId):null;if($){$.created=v;break}t.push({id:y.id,kind:"ticket-created",...v,ts:de(y),box:y.boxId,agent:y.provider});break}case"error":{if(!w.kind)break;t.push(St(y,w.kind));break}case"provider.error":t.push({...St(y,"provider-error"),provider:y.provider,box:y.boxId,agent:y.provider});break;case"usage.cap.hit":t.push(St(y,"usage-cap-hit"));break;case"usage.cap.warning":t.push(St(y,"usage-cap-warning"));break;case"provider.connected":{t.push({id:y.id,kind:"event",type:"provider-connected",provider:w.provider||y.provider,ts:de(y),at:de(y),box:y.boxId,agent:y.provider});break}case"prompt.answered":{if(le=null,w.control||!w.question)break;let v=w.groupId||w.promptId;if(!v)break;let $=Se.get(v);$||($={id:y.id,kind:"prompt",groupId:v,provider:y.provider,box:y.boxId,agent:y.provider,questionTotal:w.questionTotal??1,questions:[],ts:de(y)},Se.set(v,$));let ve=w.questionIndex??0,b={index:ve,header:w.header||"",question:w.question,multiSelect:!!w.multiSelect,chosen:Array.isArray(w.chosen)?w.chosen:[]},P=$.questions.findIndex(We=>We.index===ve&&Oe(We.question)===Oe(b.question));P>=0?$.questions[P]=b:$.questions.push(b),$.questions.sort((We,Ht)=>We.index-Ht.index),$.questionTotal=Math.max($.questionTotal,w.questionTotal??1),$.questions.length>=$.questionTotal&&(t.push($),Se.delete(v));break}default:break}}let Ze=u.size?t.filter(y=>!y.retired):t;return H$(Ze.sort((y,w)=>(y.ts??0)-(w.ts??0)))}function H$(e){let t=new Map,n=[];for(let r of e){if(r.kind!=="message"||!r.box){n.push(r);continue}let o=r.role==="assistant"&&!String(r.text||"").trim()&&r.images?.length,s=t.get(r.box);if(o&&s&&(r.ts??0)-s.lastTs<=U$){s.item.images.push(...r.images),s.lastTs=r.ts??s.lastTs;continue}if(o){let a={...r,images:[...r.images]};t.set(r.box,{item:a,lastTs:r.ts??0}),n.push(a)}else t.delete(r.box),n.push(r)}return n}function Jd(e,t=null){let n=[];for(let o of e||[]){if(o.type!=="tool.called"||o.source!=="transcript")continue;let s=o.payload||{};String(s.command||"").trim()&&n.push({id:s.id??null,tool:s.tool||null,command:s.command,description:s.description||"",summary:W$(s),ts:s.ts??o.ts,n:s.n,box:o.boxId,agent:o.provider,boxRole:s.boxRole})}if(!n.length)return[];let r=(t??Zn(e)).filter(o=>o.kind==="message");return Rg(n,r)}function W$(e){let t=String(e.summary||"").trim();return t&&t!==e.command&&t!==No(e.command)?t:Xn(e.command,e.description||"")}function St(e,t){let{ts:n,change:r,...o}=e.payload||{};return{id:e.id,kind:"event",type:t,...o,at:de(e),ts:de(e)}}function Ry(e){let t=[...e];for(let n=0;n<t.length;n++){let r=t[n];if(r?.kind!=="event"||r.type!=="archived")continue;let o=(r.ts??0)+q$,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||a?.kind==="event"&&K$.has(a.type))break;s++}s>n&&t.splice(s,0,...t.splice(n,1)),n=s}return t}function $y(e){let t=[...e];for(let n=0;n<t.length;n++){let r=t[n];if(r?.kind!=="event"||!V$.has(r.type)||!r.box)continue;let o=(r.ts??0)+G$,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||!(a?.kind==="message"&&a.role==="assistant"&&a.box===r.box||a?.kind==="command-batch"&&a.anchorBox===r.box))break;s++}s>n&&t.splice(s,0,...t.splice(n,1)),n=s}return t}function Oy(e){return(e||[]).filter(t=>z$.has(t?.kind)&&t.status==="open")}var de,L$,Iy,U$,q$,K$,G$,V$,z$,Xd=C(()=>{Po();Dr();xc();Rc();Wd();zd();de=e=>e.payload?.ts??e.ts;L$=new Set(["opened","ci-fixed","reconciled","pushed"]),Iy=e=>`${e.repo??""}#${e.number}`;U$=2*6e4;q$=12e4,K$=new Set(["archived","unarchived","opened"]);G$=2500,V$=new Set(["pr-opened","pr-merged","pr-auto-armed"]);z$=new Set(["pr-offer","pr-exists-offer","ticket-offer","ticket-create-offer","loop-create-offer","fullscreen-offer"])});function Q$(e){let t=null,n=null,r=null;for(let o of e??[]){let s=o?.ts??null;s&&(r=Math.max(r??0,s)),o?.type==="handoff.artifact"&&(t={ts:o.payload?.ts??s,truncated:!!o.payload?.truncated,...o.payload?.reconstructed?{reconstructed:!0}:{}}),o?.type==="code.pushed"&&(n={ts:o.payload?.ts??s,sha:o.payload?.sha??null,ref:o.payload?.ref??null,wip:!!o.payload?.wip})}return{lastArtifact:t,lastPush:n,lastEventAt:r}}function tO(e){for(let t=(e?.length??0)-1;t>=0;t--){let n=e[t];if(n?.type==="handoff.artifact"&&!n.payload?.reconstructed)return n}return null}function nO(e,t){let n=[],r=[],o=new Set,s=new Set;for(let a=(e?.length??0)-1;a>=0;a--){let i=e[a];if(i?.type!=="tool.called")continue;if(t!=null&&(i.ts??0)<=t)break;let c=i.payload||{};c.path&&!o.has(c.path)&&n.length<Y$&&(o.add(c.path),n.push(c.path)),c.head&&!s.has(c.head)&&r.length<Z$&&(s.add(c.head),r.push(c.head))}return{files:n,heads:r}}function Py(e,{trackName:t="this Track",now:n=null,mode:r="failover"}={}){let o=Q$(e),s=tO(e),a=s?.payload?.content??null,i=s?s.payload?.ts??s.ts??null:null,c=Zn(e??[]).filter(d=>d?.kind==="message"&&typeof d.text=="string"&&d.text.trim()).slice(-J$);if(!a&&!c.length)return null;let l=[];if(l.push(`# Reconstructed resume brief \u2014 ${t}`),l.push(""),l.push(Ny[r]??Ny.failover),l.push(""),o.lastPush?.sha){let d=My(n,o.lastPush.ts),p=d?` (~${d} min before the loss)`:"";l.push(`**Code state:** last pushed ref \`${o.lastPush.ref}\` @ \`${o.lastPush.sha.slice(0,12)}\`${p}`+(o.lastPush.wip?" \u2014 a bostrat WIP snapshot (full working tree incl. uncommitted edits at push time).":"."))}else r==="in-place"?l.push("**Code state:** no push recorded \u2014 the working tree in this workspace is the only copy; commit early."):l.push("**Code state:** no push was ever recorded for this Track \u2014 work since the branch's last known state stayed on the offline node.");if(l.push(""),a){let d=My(n,i);l.push(`## Last real checkpoint (written by the previous agent${d?`, ~${d} min before this reconstruction`:""})`),l.push(""),l.push(a.trim()),l.push("")}let u=nO(e??[],i);if((u.files.length||u.heads.length)&&(l.push(`## Work since ${a?"that checkpoint":"the start of the log"} (from the event log)`),l.push(""),u.files.length&&l.push(`Files touched (most recent first): ${u.files.map(d=>`\`${d}\``).join(", ")}`),u.heads.length&&(u.files.length&&l.push(""),l.push(`Commands run (most recent first): ${u.heads.map(d=>`\`${d}\``).join(" \xB7 ")}`)),l.push("")),c.length){l.push(`## Recent conversation (last ${c.length} message${c.length===1?"":"s"})`),l.push("");for(let d of c)l.push(`**${d.role==="user"?"operator":"agent"}:** ${eO(d.text,X$)}`),l.push("")}l.push("---"),l.push("Resume: continue the objective above from the verified repository state; ask the operator before redoing anything the log says was already done.");let f=l.join(`
114
+ `);return f.length<=Cy?f:`${f.slice(0,Cy)}
115
+
116
+ [\u2026 brief truncated]`}var J$,X$,Cy,Y$,Z$,eO,My,Ny,Dy=C(()=>{Xd();J$=12,X$=2e3,Cy=48e3,Y$=30,Z$=10;eO=(e,t)=>{let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1)}\u2026`},My=(e,t)=>e&&t?Math.max(1,Math.round((e-t)/6e4)):null;Ny={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 rO from"node:fs";import Qn from"node:fs/promises";import er from"node:path";function qy(e){let t=Or(String(e??"")),n=Buffer.byteLength(t,"utf8");return n<=By?{content:t,bytes:n,truncated:!1}:{content:`${Buffer.from(t,"utf8").subarray(0,By).toString("utf8").replace(/�+$/,"")}
117
+
118
+ [\u2026 truncated by bostrat at 32 KiB \u2014 full artifact in the workspace]`,bytes:n,truncated:!0}}function fO(e){let t=String(e||"").split(/\r?\n/).map(s=>s.trim()).filter(Boolean),n=[],r=[];for(let s of t)if(Ly.test(s)){if(r.length>=Xy)continue;let a=dO(s.replace(Ly,"").replace(/[.;,:]+$/,""),Yy,lO);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>jy&&(o=`${o.slice(0,jy-1).trimEnd()}\u2026`),{text:o,items:r.length>1?r:[]}}async function Zy(e,t,{timeoutMs:n=9e4}={}){let r=er.join(t,iO),o=er.join(r,cO);await Qn.mkdir(r,{recursive:!0});let s=await Pc(o),a=await se(e);if(!a)throw new Error(`session "${e}" not found`);return await Dc(e,a,uO(o)),await sb(o,s,n),fO(await Qn.readFile(o,"utf8"))}function Qy(e,t){let n=(t||"").trim();if(!n)return!1;if(e==="assistant")return n===Gy||n===Jy;let r=n.replace(/^\/[a-z0-9:_-]+\s+/i,"");return r.startsWith(Ky)||n===oO||r.startsWith(Vy)||r.startsWith(zy)}function eb(e){let t=[];for(let r of e?.events||[]){if(r.type!=="lead-handoff"||!r.from)continue;let o=r.at??Date.now(),s=r.handoffStartedAt??o-pO;t.push({box:r.from,from:s,to:o}),r.to&&r.to!==r.from&&t.push({box:r.to,from:s,to:o})}let n=e?.handoff;return n?.fromBox&&n.startedAt&&n.finishedAt&&t.push({box:n.fromBox,from:n.startedAt,to:n.finishedAt}),n?.toBox&&n.startedAt&&n.finishedAt&&t.push({box:n.toBox,from:n.startedAt,to:n.finishedAt}),t}function tb(e,t){let n=[];for(let r of e?.boxes||[]){let o=t?.(r.name);o?.startedAt&&n.push({box:r.name,from:o.startedAt,to:o.finishedAt||Date.now()+1e12})}return n}function nb(e,{windows:t=[]}={}){if(Qy(e.role,e.text))return!0;if(e.role!=="assistant"||!e.ts)return!1;for(let n of t)if(e.box===n.box&&e.ts>=n.from&&e.ts<=n.to)return!0;return!1}function Bc(e){return Yd.get(e)||null}async function rb(e){let t=Yd.get(e);if(t&&!t.finishedAt)throw new Error("a handoff is already running for this session");let n=await se(e);if(!n)throw new Error(`session "${e}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${e}"`);let r={name:e,step:"summarize",startedAt:Date.now(),finishedAt:null,error:null,file:er.join(n.cwd,Hy,Wy)};return Yd.set(e,r),wO(r,n.cwd).catch(o=>{r.error=o?.message||String(o),r.finishedAt=Date.now()}),r}async function wO(e,t){e.step="summarize",await ob(e.name,t),e.step="clear";let n=await se(e.name);await Dc(e.name,n,"/clear"),await ef(mO),e.step="resume",await Dc(e.name,n,aO),e.step="done",e.finishedAt=Date.now()}async function ob(e,t,{timeoutMs:n=hO}={}){let r=er.join(t,Hy),o=er.join(r,Wy);await Qn.mkdir(r,{recursive:!0});let s=await Pc(o),a=await se(e);await X({flow:"checkpoint",phase:"summarize-start",sessionName:e,cwd:t,file:o,beforeMtime:s}),await Dc(e,a,sO(o)),await sb(o,s,n),await X({flow:"checkpoint",phase:"summarize-done",sessionName:e,file:o,afterMtime:await Pc(o)});let i=await my(t,o,{exclude:u=>Qy(u.role,u.text)});await X({flow:"checkpoint",phase:"seed-enriched",sessionName:e,file:o,...i});let c=/workspaces[/\\]([0-9a-f]{8})$/.exec(t||"")?.[1];if(c){await _({id:c,cwd:t},{type:"memory.seed",actor:"orchestrator",payload:{...i,tokensEst:i.chars?Math.round(i.chars/4):0,ts:Date.now()}}).catch(()=>{});try{let u=await Qn.readFile(o,"utf8");await _({id:c,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...qy(u),ts:Date.now()}})}catch{}}await Yu(t);let l=await gO(r,o);return c&&await tg(c,l||o,{box:e,agent:a?.agent??null}),o}async function Zd(e,{timeoutMs:t}={}){let n=await se(e);if(!n)throw new Error(`session "${e}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${e}"`);return ob(e,n.cwd,t?{timeoutMs:t}:void 0)}async function Qd(e,t,{trackName:n="this Track"}={}){let r=await L({id:e,cwd:t}),o=Py(r,{trackName:n,now:Date.now(),mode:"in-place"});if(!o)return null;let s=er.join(t,Fy);return await Qn.mkdir(er.dirname(s),{recursive:!0}),await Qn.writeFile(s,o,"utf8"),await _({id:e,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...qy(o),reconstructed:!0,ts:Date.now()}}).catch(()=>{}),Fy}async function Pc(e){try{return(await Qn.stat(e)).mtimeMs}catch{return 0}}async function sb(e,t,n){let r=Date.now()+n;for(;;){if(await Pc(e)>t)return;if(Date.now()>r)throw new Error(`timed out waiting for the handoff file to be written (${e})`);await ef(2e3)}}async function gO(e,t){try{if(!rO.existsSync(t))return null;let n=new Date().toISOString().replace(/[:.]/g,"-"),r=er.join(e,`${n}.md`);return await Qn.copyFile(t,r),r}catch{return null}}function ef(e){return new Promise(t=>setTimeout(t,e))}function Uy(e){return e==="claude"?process.env.BOSTRAT_AGENT_CMD||"claude":e==="cursor"?process.env.BOSTRAT_CURSOR_CMD||"cursor-agent":e==="codex"?process.env.BOSTRAT_CODEX_CMD||"codex":""}async function Dc(e,t,n){if(t){let o=Uy(t.agent);await Yn({cwd:t.cwd,sessionId:t.sessionId,sessionName:e,agent:t.agent,agentCmd:o})}let r=await se(e);if(!r)throw new Error(`session "${e}" disappeared before the orchestration prompt could be sent`);await Ie(e,["Escape"],{kind:"drive-wipe"}),await ef(150),await $o(e,yc,{kind:"drive-wipe"}),await Le(e,n,{kind:"orchestration-drive",...zt(r.agent,n)}),await xa({sessionName:e,agent:r.agent,agentCmd:Uy(r.agent),text:n,flow:"orchestration-drive"})}var Hy,Wy,By,Ky,Gy,Vy,oO,sO,aO,zy,Jy,iO,cO,jy,Xy,Yy,lO,uO,Ly,dO,pO,mO,hO,Yd,Fy,tf=C(()=>{Ve();ga();Gt();ya();Dd();hy();Zs();ue();uc();Dy();Hy=".bostrat/handoff",Wy="latest.md",By=32*1024;Ky="Checkpoint: write a work-in-progress handoff",Gy="HANDOFF WRITTEN",Vy="Resume from .bostrat/handoff/latest.md",oO="/clear",sO=e=>`${Ky} to the EXACT absolute path ${e} (write it there specifically \u2014 NOT into any sub-project or other directory; create the directory if needed, overwrite the file) so a FRESH Claude context with none of this conversation can resume seamlessly. Use these sections: Objective; Done (with file paths); In progress (exact state); Next steps (ordered); Key files & commands; Open decisions/blockers; Resume instruction (one line). Be concrete and self-contained \u2014 assume the reader has none of this chat. When the file is written, reply only with ${Gy} and take no further action.`,aO=`${Vy}: read it, restate the Objective and the single next step in one line, then continue the work from 'Next steps'.`,zy="Beat: write a",Jy="BEAT WRITTEN",iO=".bostrat/arc",cO="beat.txt",jy=200,Xy=4,Yy=5,lO=36,uO=e=>`${zy} short summary of what this workstream accomplished, to the EXACT absolute path ${e} (write it there specifically \u2014 NOT into any sub-project or other directory; create the directory if needed, overwrite the file). Format the file as: FIRST LINE = one sentence of at most 18 words, plain past tense, saying the outcome \u2014 no heading, no bullet, no trailing list. THEN, only if this workstream covered several separable pieces of work, up to ${Xy} further lines, each starting with "- " and naming ONE piece in at most ${Yy} 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 ${Jy} and take no further action.`,Ly=/^(?:[-–—*•·]|\d+[.)])\s+/,dO=(e,t,n)=>{let r=e.split(/\s+/).filter(Boolean).slice(0,t).join(" ");return r.length>n?`${r.slice(0,n-1).trimEnd()}\u2026`:r};pO=6e5;mO=3500,hO=3e5,Yd=new Map;Fy=".bostrat/handoff/status-latest.md"});function ib(e,t,n){if(e==null)return t==="from"?-1/0:1/0;if(!yO.test(String(e)))throw new Error(`pricing.js: ${n} window ${t} must be YYYY-MM-DD, got ${JSON.stringify(e)}`);let r=Date.parse(`${e}T${t==="from"?"00:00:00.000":"23:59:59.999"}Z`);if(!Number.isFinite(r))throw new Error(`pricing.js: ${n} window ${t} is not a real date: ${e}`);return r}function bO(e){let t={};for(let[n,r]of Object.entries(e)){if(!Array.isArray(r)||r.length===0)throw new Error(`pricing.js: ${n} must be a non-empty array of rate windows`);t[n]=r.map(o=>({...o,fromMs:ib(o.from,"from",n),toMs:ib(o.to,"to",n)}))}return t}function xO(e){if(e==null)return Date.now();if(typeof e=="number")return Number.isFinite(e)?e:null;if(e instanceof Date){let n=e.getTime();return Number.isFinite(n)?n:null}let t=Date.parse(String(e));return Number.isFinite(t)?t:null}function SO(e){if(!e)return null;let t=String(e).trim();return nf[t]?t:ab[t]?ab[t]:Object.keys(nf).find(r=>t.startsWith(r))||null}function cb(e,t){let n=SO(e);if(!n)return null;let r=xO(t);return r===null?null:kO[n].find(o=>r>=o.fromMs&&r<=o.toMs)||null}function tr(e,t={},n){let r=cb(e,n);return r?((t.input||0)*r.input+(t.output||0)*r.output+(t.cacheWrite||0)*r.cacheWrite+(t.cacheRead||0)*r.cacheRead)/1e6:0}var nf,ab,yO,kO,lb,Aa=C(()=>{nf={"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)."}]},ab={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"},yO=/^\d{4}-\d{2}-\d{2}$/;kO=bO(nf);lb=(e,t)=>cb(e,t)!==null});function vO(e){return e?{input:e.input||0,output:e.output||0,cacheRead:e.cacheRead||0,cacheWrite:e.cacheWrite??e.cacheCreation??0}:null}function db(e,t){t&&(e.input+=t.input,e.output+=t.output,e.cacheRead+=t.cacheRead,e.cacheCreation+=t.cacheWrite)}function mn(e){let t=e.payload?.model||"unknown",n=vO(e.payload?.tokens),r=Number(e.payload?.usd)||0,o=e.source==="vendor",s=r,a=!1;if(n&&!o){let l=tr(t,n,e.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&&!lb(t,e.ts);return{usd:s,model:t,tokens:n,repriced:a,unpriced:c,asRecorded:r}}function nr(e,{boxLabels:t={}}={}){let n=(e||[]).filter(d=>d.type==="cost.recorded"),r={},o={},s={},a=0,i=0,c=0,l=0,u=new Set,f=ub();for(let d of n){let{usd:p,model:m,tokens:h,repriced:g,unpriced:x,asRecorded:k}=mn(d);i+=k;let E=d.provider||"unknown",I=d.boxId||"unattributed";if(g&&c++,x&&(l++,u.add(m)),a+=p,db(f,h),r[m]||={usd:0,tokens:ub(),events:0},r[m].usd+=p,r[m].events+=1,db(r[m].tokens,h),o[E]||={usd:0,events:0},o[E].usd+=p,o[E].events+=1,s[I]||={usd:0,events:0,provider:E,models:new Set,label:t[I]||I},s[I].usd+=p,s[I].events+=1,m!=="unknown"&&s[I].models.add(m),d.epoch!=null){let M=(s[I].epochs||={})[d.epoch]||={usd:0,events:0,provider:E,models:new Set};M.usd+=p,M.events+=1,M.provider=E,m!=="unknown"&&M.models.add(m)}}return{totalUsd:Fo(a),asRecordedUsd:Fo(i),totalTokens:f,turns:n.length,repricedTurns:c,unpricedTurns:l,unpricedModels:[...u],byModel:jc(r,d=>({...d,usd:Fo(d.usd)})),byProvider:jc(o,d=>({...d,usd:Fo(d.usd)})),byBox:jc(s,d=>({usd:Fo(d.usd),events:d.events,provider:d.provider,label:d.label,models:[...d.models],...d.epochs?{epochs:jc(d.epochs,p=>({usd:Fo(p.usd),events:p.events,provider:p.provider,models:[...p.models]}))}:{}}))}}var ub,Fo,jc,Lr=C(()=>{Aa();ub=()=>({input:0,output:0,cacheRead:0,cacheCreation:0});Fo=e=>Math.round(e*1e4)/1e4,jc=(e,t)=>Object.fromEntries(Object.entries(e).map(([n,r])=>[n,t(r)]))});function TO(e){if(!Number.isFinite(e)||e<=0)return null;let t=e/864e5;if(t>=1)return`${Math.round(t)}d`;let n=e/36e5;return n>=1?`${Math.round(n)}h`:`${Math.max(1,Math.round(e/6e4))}m`}function fb(e,t=[]){let n=[],r=e?.events||[],o=new Map,s=0;for(let u of t){if(u.type!=="pr.state.changed")continue;let f=u.payload||{};!f.repo||f.number==null||(f.change==="merged"?o.set(`${f.repo}#${f.number}`,f):f.change==="opened"&&s++)}if(o.size){let u=[...o.keys()].map(f=>{let[d,p]=f.split("#");return`${d.split("/").pop()}#${p}`});n.push(`Merged ${u.slice(0,4).join(", ")}${u.length>4?` +${u.length-4}`:""}`)}else s&&n.push(rf(s,"PR")+" opened");let a=Object.keys(e?.subtasks||{}).length||r.filter(u=>u.type==="subtask-delegated").length;a&&n.push(rf(a,"subtask"));let i=r.filter(u=>u.type==="lead-handoff"&&u.fromAgent&&u.toAgent);if(i.length){let u=i.slice(0,3).map(f=>`${f.fromAgent}\u2192${f.toAgent}`).join(", ");n.push(`${rf(i.length,"handoff")} ${u}${i.length>3?"\u2026":""}`)}let c=nr(t);c.totalUsd>=.01&&n.push(`$${c.totalUsd.toFixed(2)}`);let l=Number.isFinite(e?.archivedAt)&&Number.isFinite(e?.createdAt)?TO(e.archivedAt-e.createdAt):null;return n.length&&l&&n.push(l),n.length?n.join(" \xB7 "):null}var rf,pb=C(()=>{Lr();rf=(e,t)=>`${e} ${t}${e===1?"":"s"}`});import{execFile as EO}from"node:child_process";import{promisify as AO}from"node:util";import{randomUUID as _O}from"node:crypto";async function of(e,t){let n=Date.now()+t;for(;;){if(await fn(e))return!0;if(Date.now()>n)return!1;await _a(RO)}}async function OO(e,t){let n=hb[t]||hb.default;n.escape&&(await Ie(e,["Escape"],{kind:"swap-exit"}),await _a(150)),n.wipe&&await $o(e,yc,{kind:"swap-exit"}),await bc(e,n.text,{perCharDelayMs:90,kind:"swap-exit"});let r=zt(t).submitDelayMs||0;await _a(Math.max(r,250)),await Ie(e,["Enter"],{kind:"swap-exit"})}async function wb(e,t){try{let{stdout:n}=await Fr(F,H("show-environment","-t",e,t));return!String(n||"").trimStart().startsWith("-")}catch{return!1}}async function gb(e){await Fr(F,H("respawn-pane","-k","-t",e))}async function sf(e,t={}){if(!_e(e))throw new Error("invalid session name");let n=String(t.agentCmd||"").trim();if(!n)throw new Error("agentCmd is required");let r=await se(e);if(!r)throw new Error(`session "${e}" not found`);if(!r.cwd)throw new Error(`can't resolve cwd for "${e}"`);let o=r.agent||"agent",s=t.agent||Vn(n),a=Number(t.exitTimeoutMs)||IO;await X({flow:"swap",phase:"start",sessionName:e,from:o,to:s,cwd:r.cwd});let i=!1;if(!await fn(e)&&(await OO(e,o),!await of(e,a)&&(i=!0,await X({flow:"swap",phase:"respawn-forced",sessionName:e,from:o}),await gb(e),!await of(e,mb))))throw new Error(`pane shell did not come back after respawn-pane in "${e}"`);let c=s==="claude"&&Cr(n),l=c?Ki():null,u=await wb(e,"ANTHROPIC_API_KEY"),f=!1;try{l?(await Fr(F,H("set-environment","-t",e,"ANTHROPIC_API_KEY",l)),f=!0):u&&(await Fr(F,H("set-environment","-u","-t",e,"ANTHROPIC_API_KEY")),f=!0)}catch(g){throw l?fc(g,l):g}if(f&&!i&&(await gb(e),!await of(e,mb)))throw new Error(`pane shell did not come back after env respawn in "${e}"`);let d=!!t.resumeSessionId,p=t.resumeSessionId||_O(),m=d?n:id(n,p,e),h=d?t.pinned===!0:/(^|\s)--session-id(\s|=)/.test(m);return c&&await Fn(r.cwd),s==="codex"&&await go(r.cwd),s==="cursor"&&await yo(r.cwd),await Mr(e),await Fr(F,H("set-option","-t",e,"@bostrat-sid",p)),await Fr(F,H("set-option","-t",e,"@bostrat-agent",s)),await _a($O),c&&aa().length&&(await wb(e,sa)||await Fr(F,H("set-environment","-t",e,sa,"1")).catch(()=>{}),await Le(e,`export ${sa}=1`,{kind:"swap-env"}),await _a(150)),await Le(e,m,{kind:"swap-launch"}),await X({flow:"swap",phase:"done",sessionName:e,from:o,to:s,sid:p,forced:i,envRespawned:f}),{name:e,cwd:r.cwd,sessionId:p,agent:s,pinned:h,forced:i,envRespawned:f,launchCmd:m}}var Fr,_a,IO,mb,RO,$O,hb,yb=C(()=>{Ve();Ks();Vi();zi();ya();Gt();Fr=AO(EO),_a=e=>new Promise(t=>setTimeout(t,e)),IO=Number(process.env.BOSTRAT_SWAP_EXIT_TIMEOUT_MS)||15e3,mb=Number(process.env.BOSTRAT_SWAP_SHELL_TIMEOUT_MS)||8e3,RO=250,$O=400,hb={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 bb(e,{maxBytes:t=2097152,limit:n=100}={}){let r;try{r=await it(e,t)}catch{return[]}let o=new Map,s=new Set;for(let i of r.split(`
119
+ `)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.isSidechain)continue;let u=l.message?.content;if(!Array.isArray(u))continue;let f=l.timestamp?Date.parse(l.timestamp):null;for(let d of u)if(!(!d||typeof d!="object"))if(d.type==="tool_use"&&d.id){if(d.name==="Agent"){let p=d.input||{};o.set(d.id,{id:d.id,kind:"agent",name:String(p.description||"").trim()||null,detail:String(p.subagent_type||"").trim()||null,ts:f,proven:!1})}else if(d.name==="Bash"&&d.input?.run_in_background===!0){let p=String(d.input.command||"").trim();o.set(d.id,{id:d.id,kind:"command",name:String(d.input.description||"").trim()||(p?No(p):null),detail:p?No(p):null,ts:f,proven:!0})}}else d.type==="tool_result"&&d.tool_use_id&&CO.test(MO(d.content))&&s.add(d.tool_use_id)}let a=[];for(let i of o.values()){if(!i.proven&&!s.has(i.id))continue;let{proven:c,...l}=i;a.push(l)}return a.slice(-n)}var CO,MO,kb=C(()=>{Nt();Po();CO=/^Async (?:agent|task) launched/i,MO=e=>{if(typeof e=="string")return e.trim();if(!Array.isArray(e))return"";let t=e.find(n=>n&&n.type==="text"&&typeof n.text=="string");return t?t.text.trim():""}});function rr(e,t){if(!e)return null;let n=String(e);if(t){let o=t.endsWith("/")?t:`${t}/`;if(n===t)return".";if(n.startsWith(o))return n.slice(o.length)||"."}let r=n.split("/").filter(Boolean);return n.startsWith("/")&&r.length>2?r.slice(-2).join("/"):n}function NO(e){let t=typeof e=="string"?e:String(e?.patch??e?.input??""),n=[];for(let r of t.matchAll(/^\*{3} (?:Update|Add|Delete) File: (.+)$/gm))n.push(r[1].trim());return n}function xb(e,t,n){switch(e){case"Shell":{let r=String(t?.command||"").trim();return r?{command:r,description:String(t?.description||"").trim()}:null}case"Read":{let r=t?.path;if(!r)return null;let o=Number(t?.offset)||null,s=o&&Number(t?.limit)?o+Number(t.limit)-1:null;return{command:Pt(`read ${rr(r,n)}${o?` (lines ${o}\u2013${s??"end"})`:""}`,140),description:o?`Read lines ${o}\u2013${s??"end"} of ${Uo(r)}`:`Read ${Uo(r)}`}}case"Grep":{let r=t?.pattern;if(!r)return null;let o=t?.path?rr(t.path,n):null,s=t?.glob?` --glob ${af(t.glob)}`:"",a=Pt(String(r),40);return{command:Pt(`grep ${af(r)}${o&&o!=="."?` ${o}`:""}${s}`,140),description:o&&o!=="."?`Search for \u201C${a}\u201D in ${o}`:`Search for \u201C${a}\u201D`}}case"Glob":{let r=t?.glob_pattern;if(!r)return null;let o=t?.target_directory?rr(t.target_directory,n):null;return{command:Pt(`glob ${af(r)}${o&&o!=="."?` ${o}`:""}`,140),description:`Find files matching \u201C${Pt(String(r),40)}\u201D`}}case"StrReplace":return t?.path?{command:Pt(`edit ${rr(t.path,n)}`,140),description:`Edit ${Uo(t.path)}`}:null;case"Write":return t?.path?{command:Pt(`write ${rr(t.path,n)}`,140),description:`Write ${Uo(t.path)}`}:null;case"Delete":return t?.path?{command:Pt(`delete ${rr(t.path,n)}`,140),description:`Delete ${Uo(t.path)}`}:null;case"ReadLints":{let o=(Array.isArray(t?.paths)?t.paths:[]).map(s=>rr(s,n)).filter(Boolean);return{command:Pt(o.length?`lints ${o.join(" ")}`:"lints",140),description:"Check lints"}}case"ApplyPatch":{let r=NO(t);if(!r.length)return null;let o=r.length>1?` (+${r.length-1} more)`:"";return{command:Pt(`apply_patch ${rr(r[0],n)}${o}`,140),description:r.length>1?`Patch ${r.length} files`:`Patch ${Uo(r[0])}`}}case"Await":{let r=t?.shell_id??t?.task_id;return{command:Pt(`await ${r??"background output"}`,140),description:"Wait for a background command"}}default:return null}}var Lc,Pt,Uo,af,Sb=C(()=>{Lc=new Set(["Shell","Read","Grep","Glob","StrReplace","Write","ReadLints","Delete","ApplyPatch","Await"]),Pt=(e,t=88)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,Uo=e=>String(e).replace(/\/+$/,"").split("/").pop()||String(e);af=e=>`"${String(e).replace(/"/g,'\\"')}"`});import Ia from"node:fs";import PO from"node:fs/promises";import Ur from"node:path";import DO from"node:os";import BO from"node:crypto";import jO from"node:zlib";function Eb(e){let t=BO.createHash("md5").update(String(e)).digest("hex");return Ur.join(LO,t)}function Ab(e){try{let t=JSON.parse(Ia.readFileSync(Ur.join(e,"meta.json"),"utf8"));return{createdAtMs:Number(t.createdAtMs)||null,updatedAtMs:Number(t.updatedAtMs)||Number(t.createdAtMs)||null,hasConversation:t.hasConversation===!0}}catch{return null}}function FO(e){let t=Eb(e),n;try{n=Ia.readdirSync(t,{withFileTypes:!0}).filter(o=>o.isDirectory())}catch{return null}let r=null;for(let o of n){let s=Ur.join(t,o.name),a=Ur.join(s,"store.db");if(!Ia.existsSync(a))continue;let i=Ab(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 Fc(e,t){if(!e)return null;if(t){let n=Ur.join(Eb(e),t),r=Ur.join(n,"store.db");if(Ia.existsSync(r))return{id:t,dir:n,store:r,...Ab(n)||{createdAtMs:null,updatedAtMs:null}}}return FO(e)}function vb(e,t){let n=e.prepare("SELECT data FROM blobs WHERE id = ?").get(t);return n?Buffer.from(n.data):null}function UO(e){if(!e)return null;let t=e;if(t.length>1&&t[0]===31&&t[1]===139)try{t=jO.gunzipSync(t)}catch{}try{return JSON.parse(t.toString("utf8"))}catch{return null}}function HO(e){let t=[],n=0,r=e.length,o=()=>{let s=0,a=0;for(;n<r;){let i=e[n++];if(s+=(i&127)*2**a,!(i&128))break;a+=7}return s};for(;n<r;){let s=o(),a=s>>>3,i=s&7;if(i===2){let c=o(),l=e.subarray(n,n+c);n+=c,a===1&&c===32&&t.push(l.toString("hex"))}else if(i===0)o();else if(i===5)n+=4;else if(i===1)n+=8;else break}return t}function WO(e,t){if(!Array.isArray(e))return[];let n=[];for(let r of e){if(!r||r.type!=="tool-call"||!Lc.has(r.toolName))continue;let o=xb(r.toolName,r.args,t);!o||!o.command||n.push({id:r.toolCallId||null,tool:r.toolName,command:o.command,description:o.description||""})}return n}async function cf(e,t){if(!Tb)return Ho;let{DatabaseSync:n}=Tb,r;try{r=new n(e,{readOnly:!0})}catch{return Ho}try{let o=r.prepare("SELECT value FROM meta WHERE key = '0'").get()||r.prepare("SELECT value FROM meta LIMIT 1").get();if(!o)return Ho;let s;try{s=JSON.parse(Buffer.from(String(o.value),"hex").toString("utf8"))}catch{return Ho}let a=s.lastUsedModel||null,i=s.latestRootBlobId?vb(r,s.latestRootBlobId):null;if(!i)return{...Ho,model:a};let c=[],l=[],u=[],f=null,d=[];for(let p of HO(i)){let m=UO(vb(r,p));if(!m)continue;let h=m.providerOptions?.cursor;if(h?.requestId&&d.push(h.requestId),h?.modelProviderMessageId&&d.push(h.modelProviderMessageId),m.role!=="assistant")continue;if(Array.isArray(m.content))for(let k of m.content){let E=k?.providerOptions?.cursor?.modelName;E&&(f=E)}l.push(...WO(m.content,t).map((k,E)=>({...k,id:k.id||`${p}:${E}`}))),u.push(...KO(m.content));let g=qO(m.content);if(!g)continue;let x=[...new Set(u)];u=[],c.push({id:p,text:g,tools:x.length?x:void 0,commands:l,model:f}),l=[]}return{turns:c,trailingCommands:l,model:a,requestIds:d}}catch{return Ho}finally{try{r.close()}catch{}}}function _b(e,t){let n=e.updatedAtMs;if(!n)try{n=Math.round(Ia.statSync(e.store).mtimeMs)}catch{n=Date.now()}let r=e.createdAtMs;(!r||r>n)&&(r=n-t*1e3);let o=Math.max(0,n-r);return{end:n,tsAt:s=>Math.round(r+o*(s+1)/t)}}async function Ib(e,t,{limit:n=80}={}){let r=Fc(e,t);if(!r)return[];let{turns:o,model:s}=await cf(r.store,e);if(!o.length)return[];let a=o.slice(-n),{tsAt:i}=_b(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 Rb(e,t){let n=Fc(e,t);if(!n)return null;let{turns:r,requestIds:o,model:s}=await cf(n.store,e);return{chatId:n.id,requestIds:o,models:[...new Set(r.map(a=>a.model).filter(Boolean))],configuredModel:s,updatedAtMs:n.updatedAtMs||null}}async function $b(e,t,{limit:n=80}={}){let r=Fc(e,t);if(!r)return[];let{turns:o,trailingCommands:s}=await cf(r.store,e);if(!o.length&&!s.length)return[];let a=o.slice(-n),{end:i,tsAt:c}=_b(r,a.length||1),l=[];a.forEach((u,f)=>{for(let d of u.commands)l.push({...d,summary:Xn(d.command,d.description),ts:c(f)})});for(let u of s)l.push({...u,summary:Xn(u.command,u.description),ts:i+1});return l}async function Ob(e,t){let n=Fc(e,t);if(!n)return null;if(n.updatedAtMs)return n.updatedAtMs;try{return Math.round((await PO.stat(n.store)).mtimeMs)}catch{return null}}var LO,qO,KO,Tb,Ho,lf=C(()=>{Po();Sb();LO=process.env.BOSTRAT_CURSOR_CHATS||Ur.join(DO.homedir(),".cursor","chats");qO=e=>typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&t.type==="text"&&typeof t.text=="string").map(t=>t.text).join(`
120
+ `).trim():"",KO=e=>Array.isArray(e)?e.filter(t=>t&&t.type==="tool-call"&&t.toolName).map(t=>t.toolName):[],Tb=process.getBuiltinModule?.("node:sqlite"),Ho={turns:[],trailingCommands:[],model:null,requestIds:[]}});import GO from"node:fs/promises";function pf(e){return Cb.set(e.agent,e),e}function Ra(e){return Cb.get(e)||VO}async function hf(e,t={}){return(await Ra(e.agent).readMessages(e,t)).map(mf(e))}async function Mb(e,t={}){return(await Ra(e.agent).readCommands(e,t)).map(mf(e))}async function Nb(e,t={}){return(await Ra(e.agent).readJobs(e,t)).map(mf(e))}var Wo,uf,df,ff,VO,Cb,mf,Pb=C(()=>{Nt();Sc();Po();kb();lf();Dr();Wo=class{constructor(t,n=new Set){this.agent=t,this.cliTools=n}async readMessages(){return[]}async readCommands(){return[]}async readJobs(){return[]}async updatedAt(){return null}},uf=class extends Wo{transcript(t){return!t?.cwd||!t?.sessionId?null:Mt(t.cwd,t.sessionId)}async readMessages(t,n){let r=this.transcript(t);return r?vd(r,n):[]}async readCommands(t,n){let r=this.transcript(t);return r?Ig(r,n):[]}async readJobs(t,n){let r=this.transcript(t);return r?bb(r,n):[]}async updatedAt(t){let n=this.transcript(t);if(!n)return null;try{return Math.round((await GO.stat(n)).mtimeMs)}catch{return null}}},df=class extends Wo{async readMessages(t,n){return Ib(t.cwd,t.sessionId,n)}async readCommands(t,n){return $b(t.cwd,t.sessionId,n)}async updatedAt(t){return Ob(t.cwd,t.sessionId)}},ff=class extends Wo{sessionId(t){return t?.pinned?t.sessionId:null}async readMessages(t,n){return Cg(t.cwd,this.sessionId(t),n)}async readCommands(t,n){return Mg(t.cwd,this.sessionId(t),n)}async updatedAt(t){return Ng(t.cwd,this.sessionId(t))}},VO=new Wo("unknown"),Cb=new Map;pf(new uf("claude",yd));pf(new df("cursor",Lc));pf(new ff("codex",pa));mf=e=>t=>({...t,box:e.name,agent:e.agent,boxRole:e.role})});function qr(e){let t=e.search(bf);return(t>=0?e.slice(0,t):e).trim()}function zO(e){if(!e)return"";let t=e.replace(/[│┌└├─┘┤┬┴┼─✂].*$/,"").trim();return!t||/hidden|\d+\s+lines?/i.test(t)?"":t}function JO(e){let t=String(e).trim();return!!(!t||Wr.test(e)||bf.test(t)||/hidden|\d+\s+lines?/i.test(t)||/notespress|press n to add/i.test(t)||/^\s*notes?\s*$/i.test(t))}function XO(e,t=""){let n=[],r=/([☐☒])\s+([^☐☒←→✔]+)/g,o;for(;(o=r.exec(e))!==null;)n.push({label:o[2].trim(),answered:o[1]==="\u2612",current:!1});if(!n.length)return null;let s=YO(n,t);return n.forEach((a,i)=>{a.current=i===s}),{tabs:n,questionIndex:s,questionTotal:n.length,currentTabLabel:n[s].label}}function YO(e,t){let n=String(t).toLowerCase(),r=e.findIndex(c=>!c.answered),o=r>=0?r:e.length-1;if(!n)return o;let s=e.map(c=>{let l=c.label.toLowerCase(),u=l.split(/\s+/).filter(d=>d.length>3&&n.includes(d)).length;if(u)return u;let f=l.slice(0,8).trim();return f.length>=4&&n.includes(f)?1:0}),a=Math.max(...s);if(a===0||s[o]===a)return o;let i=s.flatMap((c,l)=>c===a?[l]:[]);return i.length===1?i[0]:o}function Bb(e){return e.replace(/[←→✔☐☒●▶]/g," ").replace(/\bSubmit\b/g," ").replace(/\s+/g," ").trim()}function ZO(e,t=""){let n=String(e);if(!Lb.test(n))return null;let r=n.replace(/\r/g,"").split(`
121
+ `),o=-1;for(let u=r.length-1;u>=0;u--)if(/^\s*Switch model\?\s*$/.test(r[u])){o=u;break}if(o<0)return null;let s=[],a=[];for(let u=o+1;u<r.length;u++){let f=r[u].match(Hr);if(f)s.push({cursor:!!f[1],label:f[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let d=r[u].trim();d&&!Wr.test(r[u])&&a.push(d)}}if(s.length<2)return null;let i=s.map(u=>({label:qr(u.label),description:""})),c=Math.max(0,s.findIndex(u=>u.cursor)),l=["Switch model?",...a].join(" ");return{provider:"claude",box:t,multiSelect:!1,cursorIndex:c,promptId:`claude:model-confirm:${i.map(u=>u.label).join("|")}`.slice(0,240),questions:[{question:l,header:"Model",multiSelect:!1,options:i}]}}function eC(e,t=""){let n=String(e).replace(/\r/g,"").split(`
122
+ `),r=n.length-1;for(;r>=0&&n[r].trim()==="";)r--;if(r<0||!Fb.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(Hr);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&&!(QO.test(n[c])||Wr.test(n[c]));c--){let l=n[c].trim();l&&a.unshift(l)}let i=s.map(c=>({label:qr(c.label),description:""}));return{provider:"claude",box:t,multiSelect:!1,cursorIndex:Math.max(0,s.findIndex(c=>c.cursor)),promptId:`claude:confirm-gate:${i.map(c=>c.label).join("|")}`.slice(0,240),questions:[{question:a.join(" ")||"Claude Code is asking you to confirm",header:"Confirm",multiSelect:!1,options:i}]}}function tC(e,t=""){let n=String(e);if(!/ready to submit your answers/i.test(n))return null;let r=n.replace(/\r/g,"").split(`
123
+ `),o=[];for(let c=0;c<r.length;c++){let l=r[c].match(Hr);l&&o.push({cursor:!!l[1],label:l[4].trim()})}let s=o.filter(c=>/^(submit answers|cancel)$/i.test(c.label));if(s.length<2)return null;let a=s.map(c=>({label:c.label,description:""})),i=Math.max(0,s.findIndex(c=>c.cursor));return{provider:"claude",box:t,multiSelect:!1,cursorIndex:i,review:!0,promptId:"claude:review:submit-answers",questions:[{question:"Ready to submit your answers?",header:"Review",multiSelect:!1,options:a}]}}function rC(e,t=""){let n=String(e);if(!wf.test(n))return null;let r=n.replace(/\r/g,"").split(`
124
+ `),o=-1;for(let u=r.length-1;u>=0;u--)if(nC.test(r[u])){o=u;break}if(o<0)return null;let s=[],a=[r[o].trim()];for(let u=o+1;u<r.length;u++){let f=r[u].match(Hr);if(f)s.push({cursor:!!f[1],label:f[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let d=r[u].trim();d&&!Wr.test(r[u])&&a.push(d)}}if(s.length<2||!s.some(u=>wf.test(u.label)))return null;let i=s.map(u=>({label:qr(u.label),description:""})),c=Math.max(0,s.findIndex(u=>u.cursor)),l=a.join(" ");return{provider:"claude",box:t,multiSelect:!1,cursorIndex:c,promptId:`claude:resume-confirm:${i.map(u=>u.label).join("|")}`.slice(0,240),questions:[{question:l,header:"Resume",multiSelect:!1,options:i}]}}function kf(e){let t=[];for(let r=0;r<e.length;r++){let o=e[r].match(Hr);o&&t.push({line:r,cursor:!!o[1],n:Number(o[2]),label:o[4].trim()})}let n=t.sort((r,o)=>r.n-o.n);return n.length<2||n.some((r,o)=>r.n!==o+1)?null:n}function oC(e,t=""){let n=String(e);if(!Ub.test(n)||!Hb.test(n)||Kr.test(n))return null;let r=n.replace(/\r/g,"").split(`
125
+ `),o=kf(r);return o?{provider:"claude",box:t,multiSelect:!1,cursorIndex:Math.max(0,o.findIndex(s=>s.cursor)),setup:"theme",promptId:`claude:setup:theme:${o.map(s=>s.label).join("|")}`.slice(0,200),questions:[{question:"Claude Code asks: choose the text style that looks best with your terminal. You can change it later with /theme.",header:"Theme",multiSelect:!1,options:o.map(s=>({label:qr(s.label),description:""}))}]}:null}function sC(e,t=""){let n=String(e);if(!Wb.test(n)||Kr.test(n))return null;let r=n.replace(/\r/g,"").split(`
126
+ `),o=kf(r);if(!o)return null;let s=o.map(a=>{let[i,...c]=a.label.split("\xB7");return{label:qr(i),description:c.join("\xB7").trim()}});return{provider:"claude",box:t,multiSelect:!1,cursorIndex:Math.max(0,o.findIndex(a=>a.cursor)),setup:"login-method",promptId:`claude:setup:login-method:${s.map(a=>a.label).join("|")}`.slice(0,200),questions:[{question:"How do you want to sign in to Claude? A Claude subscription (Pro/Max/Team) uses your existing plan; a Console account bills API usage. Your login stays on this box \u2014 bostrat never sees it.",header:"Log in",multiSelect:!1,options:s}]}}function iC(e,t){let n=e[t].trim();for(let r=t+1;r<e.length;r++){let o=e[r].trim();if(!o||!aC.test(o)||xf.test(e[r]))break;n+=o}return n}function cC(e,t=""){let n=String(e);if(!xf.test(n)||Kr.test(n))return null;let r=n.replace(/\r/g,"").split(`
127
+ `),o="";for(let s=0;s<r.length;s++)if(/^\s*https:\/\//.test(r[s])){o=iC(r,s);break}return o?{provider:"claude",box:t,multiSelect:!1,cursorIndex:0,answerMode:"text",setup:"oauth",url:o,inputLabel:"Paste your sign-in code",promptId:"claude:setup:oauth",questions:[{question:"Open the sign-in link, approve access, then paste the code you're shown back here. The code goes straight to the Claude CLI on your box \u2014 bostrat relays the keystrokes and never stores it.",header:"Log in",multiSelect:!1,options:[]}]}:null}function uC(e,t=""){let n=String(e);if(!gf.test(n)||!lC.test(n)||Kr.test(n))return null;let s=([...n.replace(/\r/g,"").split(`
128
+ `)].reverse().find(a=>gf.test(a))||"OAuth error").trim();return{provider:"claude",box:t,multiSelect:!1,cursorIndex:0,setup:"oauth-error",promptId:`claude:setup:oauth-error:${s}`.slice(0,200),questions:[{question:`${s} \u2014 retry to get a fresh sign-in link.`,header:"Log in",multiSelect:!1,options:[{label:"Retry sign-in",description:"Mints a new sign-in link and code"}]}]}}function dC(e,t=""){let n=String(e);if(!qb.test(n)||Kr.test(n))return null;let r=n.replace(/\r/g,"").split(`
129
+ `),o=kf(r);return o?{provider:"claude",box:t,multiSelect:!1,cursorIndex:Math.max(0,o.findIndex(s=>s.cursor)),setup:"trust",promptId:`claude:setup:trust:${o.map(s=>s.label).join("|")}`.slice(0,200),questions:[{question:"Claude Code asks whether it can read, edit, and run files in this workspace. This box's workspace is bostrat-managed scratch space, so trusting it is safe.",header:"Folder trust",multiSelect:!1,options:o.map(s=>({label:qr(s.label),description:""}))}]}:null}function fC(e,t=""){let n=String(e);if(Kr.test(n))return null;let r=n.replace(/\r/g,"").split(`
130
+ `),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(Kb);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(Wr.test(r[l])||bf.test(u))break;a.unshift(u)}let i=s[1].trim();i&&a.push(i);let c=a.join(" ")||"Claude Code is waiting for you to continue.";return{provider:"claude",box:t,multiSelect:!1,cursorIndex:0,setup:"continue",promptId:`claude:setup:continue:${c}`.slice(0,200),questions:[{question:c,header:"Continue",multiSelect:!1,options:[{label:"Continue",description:""}]}]}}function pC(e){let t=-1;for(let r=e.length-1;r>=0;r--)if(yf.test(e[r])){t=r;break}if(t<0)return null;let n=-1;for(let r=t-1;r>=0;r--)if(/[☐☒]/.test(e[r])){n=r;break}return n<0?null:{headerLine:n,chatLine:t,optStart:n+1,optEnd:t}}function mC(e,t=""){let n=String(e);if(!jb.test(n)||!yf.test(n))return null;let r=n.replace(/\r/g,"").split(`
131
+ `),o=pC(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 j=r[T].match(Hr);j&&(u<0&&(u=T),l.push({line:T,cursor:!!j[1],checked:j[3]!=null&&j[3]!==" ",hasCheckbox:j[3]!=null,label:j[4].trim(),desc:""}))}if(!l.length)return null;for(let T of l)for(let j=T.line+1;j<Math.min(r.length,T.line+4)&&!(Hr.test(r[j])||Wr.test(r[j]));j++){let Z=r[j].trim();if(!(!Z||JO(r[j])||Db.test(Z))){T.desc=zO(Z);break}}let f=l.filter(T=>!Db.test(T.label));if(!f.length)return null;let d=f.some(T=>T.hasCheckbox),p=Math.max(0,f.findIndex(T=>T.cursor)),m=s>=0?s+1:0,h=[];for(let T=m;T<u;T++){let j=r[T].trim();j&&!Wr.test(r[T])&&!/[☐☒]/.test(r[T])&&h.push(j)}let g=h.join(" ")||(s>=0?Bb(r[s]):"")||"The agent is asking a question",x=s>=0?XO(r[s],g):null,k=x?.currentTabLabel||(s>=0?Bb(r[s]):""),E=f.map(T=>({label:qr(T.label),description:T.desc})),I=E.map(T=>T.label).join("|"),N=`claude:${x?`q${x.questionIndex+1}/${x.questionTotal}`:"q1/1"}:${k}:${g}:${I}`.slice(0,240),O=x?`claude:ask:${x.tabs.map(T=>T.label).join("|")}`.slice(0,240):N;return{provider:"claude",box:t,multiSelect:d,cursorIndex:p,promptId:N,groupId:O,...x?{questionIndex:x.questionIndex,questionTotal:x.questionTotal,currentTabLabel:x.currentTabLabel,tabs:x.tabs}:{},questions:[{question:g,header:k,multiSelect:d,options:E}]}}function Gr(e,t){let n=String(t||"");return n?e==="claude"?jb.test(n)&&yf.test(n)||Lb.test(n)||wf.test(n)||Fb.test(n.trimEnd().split(`
132
+ `).pop()||"")?!0:Kr.test(n)?!1:Ub.test(n)&&Hb.test(n)||Wb.test(n)||xf.test(n)||gf.test(n)||qb.test(n)||Kb.test(n.trimEnd().split(`
133
+ `).pop()||""):e==="codex"&&/Sign in with ChatGPT|one-time code|Paste or type your API key|link to authenticate|Successfully logged in\.[\s\S]*Press Enter to continue\./i.test(n)?!0:e==="cursor"||e==="codex"?/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i.test(n):!1:!1}function or(e,t){return!e||!t?null:e.agent==="claude"?tC(t,e.name)||mC(t,e.name)||ZO(t,e.name)||rC(t,e.name)||uC(t,e.name)||cC(t,e.name)||sC(t,e.name)||oC(t,e.name)||dC(t,e.name)||fC(t,e.name)||eC(t,e.name):e.agent==="cursor"||e.agent==="codex"?Jg(e.agent,t,e.name):null}async function Sf(e){if(!e)return null;let t=await pn(e.name).catch(()=>"");return or(e,t)}function Gb(e,t){let n=Array.isArray(t?.[0])?t[0].filter(a=>Number.isInteger(a)&&a>=0):[],r=Number.isInteger(e?.cursorIndex)?e.cursorIndex:0,o=(a,i)=>{let c=i-a;return Array.from({length:Math.abs(c)},()=>c>0?"Down":"Up")},s=[];if(e?.multiSelect){let a=r;for(let i of[...n].sort((c,l)=>c-l))s.push(...o(a,i),"Enter"),a=i;s.push("Tab","Enter")}else{let a=n.length?n[0]:0;s.push(...o(r,a),"Enter")}return s}function Vb(e,t){let n=Number.isInteger(e?.questionIndex)?e.questionIndex:0,o=(Number.isInteger(t)?t:n)-n;if(!o)return[];let s=o>0?"Tab":"BTab";return Array.from({length:Math.abs(o)},()=>s)}var jb,yf,Hr,Db,Wr,bf,Lb,Fb,QO,wf,nC,Kr,Ub,Hb,Wb,xf,aC,gf,lC,qb,Kb,vf=C(()=>{Ve();Tc();jb=/to navigate\b.*\bEsc to cancel|Enter to select\b/,yf=/Chat about this/i,Hr=/^\s*(❯)?\s*(\d+)\.\s+(?:\[([ xX✔])\]\s+)?(.+?)\s*$/,Db=/^(type something|chat about this|submit)\b/i,Wr=/^[─—-]{6,}\s*$/,bf=/[\u2500-\u257F\u2550-\u256F┌┐└┘├┤│┬┴┼─✂]/;Lb=/^\s*Switch model\?\s*$/m;Fb=/^\s*Enter to confirm\s*·\s*Esc to cancel\s*$/,QO=/^\s*[─—▔-]{6,}\s*$/;wf=/Resume from summary/i,nC=/^\s*This session is\b/;Kr=/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/;Ub=/Choose the text style that looks best with your terminal/,Hb=/Let's get started\./;Wb=/Select login method:/;xf=/Paste code here if prompted/,aC=/^[A-Za-z0-9%&=+._~#?/:\-]+$/;gf=/OAuth error:/,lC=/Press Enter to retry\./;qb=/Quick safety check: Is this a project you created or one you trust/;Kb=/^(.{0,60}?)Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/});function Uc(e,t,n){if(!e||!t)return null;for(let r of hC)if(r.provider===e.agent)try{if(r.match(t,n))return r}catch{}return null}function gC(e){let t=Tf.get(e);return t||(t={sentAt:[],last:0,emitted:new Set},Tf.set(e,t)),t}function Xb(e,t,n=Date.now()){let r=gC(e);if(r.sentAt=r.sentAt.filter(s=>n-s<Jb),r.sentAt.length>=zb)return{action:"give-up"};if(n-r.last<wC)return{action:"wait"};r.last=n,r.sentAt.push(n);let o=!r.emitted.has(t);return o&&r.emitted.add(t),{action:"send",first:o}}function Yb(e,t=Date.now()){let n=Tf.get(e);return n?n.sentAt.filter(r=>t-r<Jb).length>=zb:!1}var hC,wC,zb,Jb,Tf,Ef=C(()=>{hC=[{provider:"claude",id:"fullscreen-upsell",match(e,t){let n=e?.questions?.[0],r=(n?.options||[]).map(s=>String(s.label||"").trim());if(r.length!==2||!/^Yes, try it$/.test(r[0])||!/^Not now$/.test(r[1]))return!1;let o=`${n?.question||""}
134
+ ${String(t||"")}`;return/Try the new fullscreen renderer|Flicker-free output/i.test(o)},keys:["Escape"]}];wC=5e3,zb=5,Jb=3600*1e3,Tf=new Map});function qo(e){return typeof e=="string"?e.trim():""}var Zb=C(()=>{});import{execFile as yC}from"node:child_process";import{promisify as bC}from"node:util";async function $e(e,t,{input:n}={}){let r=_f("git",["-C",e,...t],{maxBuffer:Qb});return n!==void 0&&r.child.stdin&&(r.child.stdin.on("error",()=>{}),r.child.stdin.end(n)),r}async function Ko(e){if(!e)return!1;try{let{stdout:t}=await $e(e,["rev-parse","--is-inside-work-tree"]);return t.trim()==="true"}catch{return!1}}async function ek(e){let{stdout:t}=await $e(e,["rev-parse","--show-toplevel"]);return t.trim()}async function kC(e){try{return await $e(e,["rev-parse","--verify","HEAD"]),!0}catch{return!1}}async function Go(e,t="bostrat: subtask snapshot"){let{stdout:n}=await $e(e,["rev-parse","--absolute-git-dir"]),r=`${n.trim()}/bostrat-snapshot-index`,o={...process.env,GIT_INDEX_FILE:r},s=(a,i)=>_f("git",["-C",e,...a],{maxBuffer:Qb,env:o,...i});try{let a=await kC(e);a&&await s(["read-tree","HEAD"]),await s(["add","-A"]);let{stdout:i}=await s(["write-tree"]),c=i.trim(),l=a?["commit-tree",c,"-p","HEAD","-m",t]:["commit-tree",c,"-m",t],{stdout:u}=await s(l);return u.trim()}finally{try{await _f("rm",["-f",r])}catch{}}}async function If(e,t){let{stdout:n}=await $e(e,["status","--porcelain"]);return n.trim()?(await $e(e,["add","-A"]),await $e(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","-m",t]),!0):!1}async function $a(e,{ignorePlumbing:t=!1}={}){let{stdout:n}=await $e(e,["status","--porcelain"]),r=n.split(`
135
+ `).filter(Boolean);return t&&(r=r.filter(o=>{let s=o.slice(3);return!(s===".bostrat"||s===".bostrat/"||s.startsWith(".bostrat/")||o.startsWith("??")&&(s==="AGENTS.md"||s==="CLAUDE.md"))})),r.length>0}async function Oa(e,t){if(!t)return 0;try{let{stdout:n}=await $e(e,["rev-list","--count",`${t}..HEAD`]);return Number(n.trim())||0}catch{return 0}}async function Vo(e,t,n,r){return await $e(e,["worktree","add","--no-track","-b",n,t,r]),t}async function tk(e,t){try{return await $e(e,["rev-parse","--verify","--quiet",`refs/heads/${t}`]),!0}catch{return!1}}async function Hc(e,t,n){return await $e(e,["worktree","add",t,n]),t}async function zo(e){if(process.env.BOSTRAT_TRACK_BASE_REF)return process.env.BOSTRAT_TRACK_BASE_REF;try{let{stdout:t}=await $e(e,["symbolic-ref","--short","refs/remotes/origin/HEAD"]);if(t.trim())return t.trim()}catch{}for(let[t,n]of[["refs/remotes/origin/main","origin/main"],["refs/remotes/origin/master","origin/master"],["refs/heads/main","main"],["refs/heads/master","master"]])try{return await $e(e,["rev-parse","--verify","--quiet",t]),n}catch{}return"HEAD"}async function Rf(e){await $e(e,["init","-q"]),await $e(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","--allow-empty","-qm","bostrat: track workspace"])}async function pt(e,t){try{await $e(e,["worktree","remove","--force",t])}catch{try{await $e(e,["worktree","prune"])}catch{}}}function xC(e){let t=/(\d+) files? changed/.exec(e),n=/(\d+) insertions?\(\+\)/.exec(e),r=/(\d+) deletions?\(-\)/.exec(e);return{files:t?Number(t[1]):0,insertions:n?Number(n[1]):0,deletions:r?Number(r[1]):0}}function $f(e,t){return!t||!t.length?e:[...e,"--",".",...t.map(n=>`:(exclude)${n}`)]}async function Of(e,t,n,r){let{stdout:o}=await $e(e,$f(["diff","--shortstat",t,n],r));return xC(o)}async function Cf(e,t,n,r){let{stdout:o}=await $e(e,$f(["diff","--name-only",t,n],r));return o.split(`
136
+ `).map(s=>s.trim()).filter(Boolean)}async function Mf(e,t,n,r){let{stdout:o}=await $e(e,$f(["diff","--binary",t,n],r));if(!o.trim())return{applied:!0,empty:!0,conflicts:[]};if((await Af(e,o,["--whitespace=nowarn"])).ok)return{applied:!0,empty:!1,conflicts:[]};let s=await Af(e,o,["--3way","--whitespace=nowarn"]),a=await SC(e);return a.length>0?{applied:!1,empty:!1,conflicts:a}:s.ok?{applied:!0,empty:!1,conflicts:[]}:(await Af(e,o,["--reject","--whitespace=nowarn"]),{applied:!1,empty:!1,conflicts:[`patch did not apply cleanly: ${s.err}`]})}async function Af(e,t,n){try{return await $e(e,["apply",...n,"-"],{input:t}),{ok:!0}}catch(r){return{ok:!1,err:r?.stderr?.trim()||r?.message||String(r)}}}async function SC(e){try{let{stdout:t}=await $e(e,["diff","--name-only","--diff-filter=U"]);return t.split(`
137
+ `).map(n=>n.trim()).filter(Boolean)}catch{return[]}}var _f,Qb,Wc=C(()=>{_f=bC(yC),Qb=64*1024*1024});import Nf from"node:fs/promises";import rk from"node:path";import vC from"node:os";function ik(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(t.getDate()-(t.getDay()+6)%7),t.getTime()}function ck(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(1),t.getTime()}function lk(e){let t=new Date(ik(e));return t.setDate(t.getDate()+7),t.getTime()}function uk(e){let t=new Date(ck(e));return t.setMonth(t.getMonth()+1),t.getTime()}function Kc(e=Date.now()){for(let[t,n]of Object.entries(Jo)){let r=n.startOf(e);if(r!==hn[t]){hn[t]=r;for(let o of Vr.values())o[t]=0;for(let o of Xo)o.includes(`:${t}:`)&&!o.endsWith(`:${r}`)&&Xo.delete(o)}}}function dk(e,t){let n=Dt?.caps?.[e]?.[Jo[t].capKey];return Number.isFinite(n)&&n>0?n:null}function zr(e,t=Date.now()){if(!e||!Df||!Dt?.caps)return null;Kc(t);let n=Vr.get(e);for(let r of Object.keys(Jo)){let o=dk(e,r);if(o==null)continue;let s=n?.[r]||0;if(s>=o)return{provider:e,window:r,limitUsd:o,spentUsd:qc(s),resetsAt:Jo[r].nextStart(t)}}return null}function fk(e,t){let n=`hit:${e}:${t.provider}:${t.window}:${hn[t.window]}`;return Xo.has(n)?!1:(Xo.add(n),!0)}function nk(e,t,n,r=Date.now()){if(!e||!t)return;Kc(r);let o=TC(e);for(let[s,a]of Object.entries(Jo))n>=hn[s]&&n<a.nextStart(r)&&(o[s]+=t)}async function EC(e,t,n=Date.now()){if(!Dt?.caps||!Pf)return;let r=Vr.get(e);if(r)for(let[o,s]of Object.entries(Jo)){let a=dk(e,o);if(a==null)continue;let i=r[o]||0;if(i<a*ak||i>=a)continue;let c=`warn:${e}:${o}:${hn[o]}`;if(!Xo.has(c)){Xo.add(c);try{let l=await Pf(t);if(!l)continue;await _(l,{type:"usage.cap.warning",actor:"system",provider:e,payload:{provider:e,window:o,limitUsd:a,spentUsd:qc(i),pct:Math.round(i/a*100),resetsAt:s.nextStart(n)}})}catch{}}}}function pk(e){let t={};for(let[n,r]of Object.entries(e||{})){if(typeof n!="string"||!/^[a-z][a-z0-9-]{0,31}$/.test(n))throw new Error(`bad provider key "${n}"`);let o={};for(let s of["weeklyUsd","monthlyUsd"]){let a=r?.[s];if(a==null||a==="")continue;let i=Number(a);if(!Number.isFinite(i)||i<=0)throw new Error(`${n}.${s} must be a positive number or null`);o[s]=i}Object.keys(o).length&&(t[n]=o)}return t}async function Gc(e,{source:t="local",updatedAt:n=Date.now()}={}){Dt={caps:pk(e),updatedAt:n,source:t};try{await Nf.mkdir(ok,{recursive:!0}),await Nf.writeFile(sk(),JSON.stringify(Dt,null,2))}catch{}return Ca()}function Ca(e=Date.now()){Kc(e);let t=new Set([...Vr.keys(),...Object.keys(Dt?.caps||{})]),n={};for(let r of t){let o=Vr.get(r);n[r]={weeklyUsd:qc(o?.weekly||0),monthlyUsd:qc(o?.monthly||0)}}return{caps:Dt?.caps||{},configured:!!Dt,seeded:Df,updatedAt:Dt?.updatedAt??null,spent:n,windows:{weekly:{start:hn.weekly,resetsAt:lk(e)},monthly:{start:hn.monthly,resetsAt:uk(e)}},warnPct:ak}}async function mk({listTracks:e,getTrack:t}={}){Pf=t||null,Kc();try{let o=JSON.parse(await Nf.readFile(sk(),"utf8"));Dt={caps:pk(o?.caps),updatedAt:o?.updatedAt??null,source:o?.source??"file"}}catch{Dt=null}let n=Date.now();st.on("event",o=>{if(o?.type!=="cost.recorded")return;let{usd:s}=mn(o);nk(o.provider||"unknown",s,o.ts??Date.now()),EC(o.provider||"unknown",o.trackId).catch(()=>{})});let r=Math.min(hn.weekly,hn.monthly);for(let o of await e?.()||[]){let s;try{s=await L(o)}catch{continue}for(let a of s){if(a.type!=="cost.recorded")continue;let i=a.ts??0;i<r||i>=n||nk(a.provider||"unknown",mn(a).usd,i,n)}}return Df=!0,Ca()}var ok,sk,ak,Jo,Dt,Df,hn,Vr,Xo,Pf,TC,qc,Vc=C(()=>{ue();Lr();ok=process.env.BOSTRAT_STATE_DIR||rk.join(process.env.HOME||vC.tmpdir(),".bostrat"),sk=()=>rk.join(ok,"usage-caps.json"),ak=.8;Jo={weekly:{startOf:ik,nextStart:lk,capKey:"weeklyUsd"},monthly:{startOf:ck,nextStart:uk,capKey:"monthlyUsd"}},Dt=null,Df=!1,hn={weekly:0,monthly:0},Vr=new Map,Xo=new Set,Pf=null,TC=e=>{let t=Vr.get(e);return t||(t={weekly:0,monthly:0},Vr.set(e,t)),t};qc=e=>Math.round(e*1e4)/1e4});import AC from"node:fs/promises";import _C from"node:os";import hk from"node:path";function Sk(e){return e==="codex"?OC:e==="cursor"?xk:bk}function wk(e){let t=String(e||"").split(`
138
+ `),n=t.findIndex(o=>/Select Model and Effort/i.test(o));if(n<0)return null;let r=[];for(let o=n+1;o<t.length;o++){let s=t[o].match(/^\s*(›\s*)?(\d+)\.\s+(\S+?)(?:\s+\((current|default)\))?(?:\s{2,}|\s*$)/);if(s)r.push({n:Number(s[2]),id:s[3],current:s[4]==="current",active:!!s[1]});else if(r.length&&/Press enter|esc to go back/i.test(t[o]))break}return r.length?r:null}function gk(e){let t=String(e||"").split(`
139
+ `),n=t.findIndex(o=>/Select Reasoning Level/i.test(o));if(n<0)return null;let r=[];for(let o=n+1;o<t.length;o++){let s=t[o].match(/^\s*(›\s*)?(\d+)\.\s+([A-Za-z ]+?)(?:\s+\((default|current)\))?(?:\s{2,}|\s*$)/);if(s)r.push({n:Number(s[2]),label:s[3].trim(),isDefault:!!s[4],active:!!s[1]});else if(r.length&&/Press enter|esc to go back/i.test(t[o]))break}return r.length?r:null}function CC(e){let t=String(e||"").split(`
140
+ `);for(let n=t.length-1;n>=0;n--){let r=t[n].match(/Model changed to\s+(\S+)(?:\s+(\S+))?\s*$/i);if(r)return{model:r[1],effort:r[2]||null}}return null}function yk(e){let t=String(e||"").split(`
141
+ `),n=t.findIndex(s=>/Available models|Models matching/i.test(s));if(n<0)return null;let r=/Models matching/i.test(t[n]),o=[];for(let s=n+1;s<t.length;s++){let a=t[s];if(/^\s*Filter:/i.test(a)||!a.trim())continue;if(/to filter|Enter to select|^\s*\d+-\d+ of \d+/i.test(a))break;let i=a.match(/^\s*(→\s+)?(.+?)\s*$/);if(!i)continue;let c=i[2].replace(/\s*\(Tab to modify\)\s*$/i,""),l=null,u=c.split(/\s{2,}/);u.length>1&&(c=u[0],l=u.slice(1).join(" ").trim()||null),c&&o.push({label:c.trim(),params:l,active:!!i[1]})}return o.length?{filtered:r,rows:o}:null}function vk(e,t){if(typeof t!="string"||!t.trim())throw new Error("model (string) required");let n=t.trim();if(e==="codex"){let[r,o]=n.split(/[\s:]+/);if(o&&!kk.has(o))throw new Error(`unknown codex effort "${o}" (low | medium | high | xhigh)`);return{model:r,effort:o||null}}if(e==="cursor"){let r=xk.find(o=>o.alias===n);return{model:n,filter:r?r.label:n}}if(!$C.has(n))throw new Error(`unknown model "${n}"`);return{model:n}}async function Ma(e,t,{timeoutMs:n=IC}={}){let r=Date.now()+n;for(;;){let o=await Te(e,{lines:80}).catch(()=>""),s=t(o);if(s)return s;if(Date.now()>r)return null;await zc(RC)}}async function MC(e,t){return await Le(e,`/model ${t.model}`,zt("claude")),{verified:!1,note:"confirmed when the next turn's transcript model flips"}}async function NC(e,t){await gc(e),await Le(e,"/model",{enter:!1}),await zc(250),await Ie(e,["Enter"],{kind:"model-switch"});let n=await Ma(e,wk);if(!n)throw new Error("codex model picker didn't open");let r=n.find(i=>i.id===t.model);if(!r)throw await Ie(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`unknown model "${t.model}" \u2014 codex offers: ${n.map(i=>i.id).join(", ")}`);let o=i=>{let c=CC(i);return!c||c.model!==t.model||t.effort&&c.effort&&c.effort.toLowerCase()!==t.effort.toLowerCase()?null:c};await Le(e,String(r.n),{enter:!1,kind:"model-switch"});let s=await Ma(e,i=>gk(i)||!wk(i)&&o(i)&&{done:o(i)});if(!s)throw await Ie(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error("codex reasoning-level picker didn't open");if(!s.done){let i=t.effort?kk.get(t.effort):null,c=i?s.find(l=>l.label.toLowerCase()===i.toLowerCase()):s.find(l=>l.isDefault)||s[0];if(!c)throw await Ie(e,["Escape","Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`codex doesn't offer effort "${t.effort}" for ${t.model}`);await Le(e,String(c.n),{enter:!1,kind:"model-switch"})}let a=s.done||await Ma(e,i=>!gk(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 PC(){let e=hk.join(process.env.CURSOR_CONFIG_DIR||hk.join(_C.homedir(),".cursor"),"cli-config.json");try{return JSON.parse(await AC.readFile(e,"utf8"))?.model||null}catch{return null}}async function DC(e,t){await gc(e),await bc(e,`/model ${t.filter}`,{kind:"model-switch"});let n=await Ma(e,yk),r=c=>String(c||"").toLowerCase(),o=c=>r(c.label).startsWith(r(t.filter)),s=n?.rows.find(c=>c.active)||null;if(n&&!(s&&o(s)))for(let c=0;c<12;c++){let l=await Ma(e,yk,{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 Ie(e,["Down"],{kind:"model-switch"}),await zc(250)}if(!n||!s||!o(s)){await Ie(e,["Escape"],{kind:"model-switch"}).catch(()=>{});let c=Array(`/model ${t.filter}`.length).fill("BSpace");throw await Ie(e,c,{settleMs:15,kind:"model-switch"}).catch(()=>{}),new Error(n?`cursor picker has no model matching "${t.filter}"`:"cursor model picker didn't open")}await Ie(e,["Enter"],{kind:"model-switch"}),await zc(800);let a=await PC();return{verified:!!a&&(a.modelId===t.model||a.displayModelId===t.model||r(a.displayName).startsWith(r(t.filter))),model:a?.modelId||null,note:"cursor applies this as the global default for new sessions too"}}async function Tk(e,t,n){return e==="codex"?NC(t,n):e==="cursor"?DC(t,n):MC(t,n)}var zc,IC,RC,bk,$C,OC,kk,xk,Ek=C(()=>{Ve();ya();zc=e=>new Promise(t=>setTimeout(t,e)),IC=Number(process.env.BOSTRAT_MODEL_PICKER_TIMEOUT_MS)||8e3,RC=300,bk=[{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"}],$C=new Set([...bk.map(e=>e.alias),"best","opus[1m]","sonnet[1m]","claude-opus-5","claude-opus-4-8","claude-sonnet-5","claude-sonnet-4-6","claude-haiku-4-5","claude-fable-5"]),OC=[{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"}],kk=new Map([["low","Low"],["medium","Medium"],["high","High"],["xhigh","Extra high"]]),xk=[{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 Xc(e){let t=e||{},n=BC(t);return n&&(n.payload={ts:t.at,...n.payload}),n}function BC(e){switch(e.type){case"said":return{type:"turn.user",actor:"user",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{text:e.text,boxRole:e.boxRole,...e.kind?{kind:e.kind}:{},...e.attachments?.length?{attachments:e.attachments}:{}}};case"unsaid":return{type:"turn.retracted",actor:"user",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{saidTs:e.saidTs,text:e.text,boxRole:e.boxRole}};case"orchestration-prompt":return{type:"turn.user",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{text:e.prompt,kind:e.kind,boxRole:e.boxRole}};case"lead-handoff":return{type:"handoff.done",actor:"orchestrator",source:"orchestrator",boxId:e.to,provider:ct(e.toAgent),payload:{from:e.from,fromAgent:e.fromAgent,to:e.to,toAgent:e.toAgent,reason:e.reason,handoffStartedAt:e.handoffStartedAt,fromSessionId:e.fromSessionId,toSessionId:e.toSessionId,epoch:e.epoch,singleBox:e.singleBox,forced:e.forced,recovered:e.recovered,checkpoint:e.checkpoint}};case"lead-handoff-failed":return{type:"handoff.failed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:ct(e.toAgent),payload:{box:e.box,fromAgent:e.fromAgent,toAgent:e.toAgent,reason:e.reason,error:e.error,rolledBack:e.rolledBack,handoffStartedAt:e.handoffStartedAt}};case"subtask-delegated":return{type:"subtask.delegated",actor:"orchestrator",source:"orchestrator",boxId:e.to,provider:ct(e.toAgent),payload:{task:e.task,subtaskId:e.subtaskId,reason:e.reason}};case"subtask-merged":return{type:"subtask.merged",actor:"orchestrator",source:"orchestrator",boxId:e.box||e.from,provider:ct(e.agent),payload:{...sr(e)}};case"subtask-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box||e.to,provider:ct(e.agent||e.toAgent),payload:{kind:"subtask-failed",...sr(e)}};case"subtask-resumed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{change:"subtask-resumed",...sr(e)}};case"model-change":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:e.box,payload:{change:"model",model:e.to,from:e.from??null,verified:e.verified??null}};case"codex-update":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:"codex",payload:{change:"cli-update",from:e.from??null,to:e.to??null,status:e.status,...e.error?{error:e.error}:{}}};case"node-update":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",payload:{change:"node-update",...sr(e)}};case"opened":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:e.box,payload:{change:"opened",...sr(e)}};case"archived":case"unarchived":case"track-deleted":case"renamed":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:e.type,...sr(e)}};case"rehydrated":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{change:"rehydrated"}};case"transferred-in":return{type:e.mode==="recover"?"track.recovered":"track.transferred",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{...sr(e)}};case"transferred-out":return null;case"retagged":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:"retagged",...sr(e)}};case"rehydrate-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:ct(e.agent),payload:{kind:"rehydrate-failed",reason:e.reason}};default:return null}}function Ik(e,t){let n=Xc(t);if(!n)return;let r=t?.type==="track-deleted"?{id:e.id}:e;jf(()=>_(r,n))}async function Rk(e){if(!(!e?.id||Ak.has(e.id))){Ak.add(e.id);try{let t=await L(e),n=new Set(t.filter(r=>r.source==="orchestrator").map(r=>`${r.type}|${r.payload?.ts??"?"}`));for(let r of e.events||[]){let o=Xc(r);!o||n.has(`${o.type}|${o.payload?.ts??"?"}`)||await _(e,o)}}catch{}}}function sr(e){let{type:t,at:n,...r}=e;return r}function $k(e,t,n){!n?.promptId||Bf.get(e.id)===n.promptId||(Bf.set(e.id,n.promptId),jf(()=>_(e,{type:"prompt.raised",actor:"agent",source:"pane",boxId:t?.name,provider:ct(n.provider||t?.agent),payload:{promptId:n.promptId,question:n.question||n.title||null,options:(n.options||[]).map(r=>r?.label??r).slice(0,12)}})))}function Lf(e,t,n,r={}){Bf.delete(e.id),jf(()=>_(e,{type:"prompt.answered",actor:"user",source:"orchestrator",boxId:t?.name,provider:ct(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}var ct,Jc,jf,_k,Ak,Bf,Ff=C(()=>{ue();ct=e=>e||null;Jc=Promise.resolve(),jf=e=>(Jc=Jc.then(e).catch(()=>{}),Jc),_k=()=>Jc;Ak=new Set;Bf=new Map});function HC(e){return String(e).split(/(?<=[.?!])\s+|\n+/).map(t=>t.trim()).filter(Boolean)}function Dk(e){let t=String(e||"").trim();if(!t)return null;let n=t.slice(-600);for(let r of HC(n).reverse()){if(!jC.test(r))continue;let o=r.endsWith("?")&&r.length<=UC&&FC.test(r);if(LC.test(r)||o)return r.length>200?r.slice(0,197)+"\u2026":r}return null}function jk(e){let t=String(e||""),n=[];WC.test(t)&&n.push("commit"),Bk.test(t)&&n.push("rebase"),qC.test(t)&&n.push("push");let r=GC.test(t);!r&&KC.test(t)&&n.push("pr");let o=null;if(r){let s=t.match(/(?:pr|pull\s+request)\s*\(?\s*#(\d+)\)?/i)||t.match(/#(\d+)/);o={number:s?Number(s[1]):null}}return{offered:n.length?n:null,toPr:o}}function Lk(e){return Bk.test(String(e||""))}function Zo(e,{branch:t=null,base:n=null,toPr:r=null,repos:o=null,offeredRebase:s=!1}={}){Array.isArray(e)||(e=e==="push"?["commit","push"]:["commit","push","pr"]);let a=new Set(e),i=Array.isArray(o)&&o.length>0,c=i?o.map(p=>`${p.name}/`).join(", "):null,l=t?` on this branch (${t})`:"",u=[];if(a.has("commit")&&u.push(i?`commit the work in each changed checkout (${c})${l} with a clear commit message per repo`:`commit the work${l} with a clear commit message`),a.has("rebase")){let p=a.has("commit")?"the branch":`this branch${t?` (${t})`:""}`;u.push(i?`rebase ${p} in each changed checkout (${c}) onto its own base branch (fetch origin first), resolving any conflicts so both sides' intent is preserved`:`rebase ${p} onto ${n?`the latest ${n}`:"its base branch"} (fetch origin first), resolving any conflicts so both sides' intent is preserved`)}if(a.has("push")||a.has("pr")){let p=r&&!a.has("pr")?` (the open PR${r.number?` #${r.number}`:""} picks it up)`:"",m=a.has("rebase")?" with `--force-with-lease` (the rebase rewrote history)":"";i?u.push(a.has("commit")||a.has("rebase")?`push each one to its remote${m}${p}`:`push this branch${t?` (${t})`:""} from each changed checkout (${c}) to its remote${p}`):u.push(a.has("commit")||a.has("rebase")?`push it to the remote${m}${p}`:`push this branch${l} to the remote${p}`)}a.has("pr")&&u.push(i?"open a pull request in each changed repo with a concise title and a description of what changed and why (run `gh pr create` inside each checkout)":`open a pull request${n?` against ${n}`:""} with a concise title and a description of what changed and why (use \`gh pr create\`)`);let f=[];a.has("commit")||f.push("don't create any new commits \u2014 ship what's already committed"),s&&!a.has("rebase")&&f.push("don't rebase \u2014 leave the branch's history as it is"),!a.has("push")&&!a.has("pr")&&f.push("don't push"),a.has("pr")||f.push("don't open a pull request");let d=`Yes \u2014 go ahead: ${u.join(", then ")}.`;return f.length&&(d+=` ${f.join(", and ").replace(/^./,p=>p.toUpperCase())}.`),a.has("pr")&&(d+=i?" If a repo's PR for this branch is already open, just push that repo's update instead.":" If a PR for this branch is already open, just push the update instead."),d}function Fk(e,{branch:t=null,base:n=null,prNumber:r=null,offeredRebase:o=!1}={}){let s=new Set(Array.isArray(e)?e:["commit","push","pr"]),a=t?` on this branch (${t})`:"",i=[];s.has("commit")&&i.push(`commit the work${a} with a clear commit message`),s.has("rebase")&&i.push(`rebase ${s.has("commit")?"the branch":`this branch${t?` (${t})`:""}`} onto ${n?`the latest ${n}`:"its base branch"} (fetch origin first), resolving any conflicts so both sides' intent is preserved`),i.push("move the work to a fresh branch (branch off the current HEAD with a clear new name)"),i.push("push the new branch to the remote"),i.push(`open a pull request${n?` against ${n}`:""} from the new branch with a concise title and a description of what changed and why (use \`gh pr create\`)`);let c=[];s.has("commit")||c.push("don't create any new commits \u2014 ship what's already committed"),o&&!s.has("rebase")&&c.push("don't rebase \u2014 leave the branch's history as it is");let l=`Yes \u2014 go ahead, as a NEW pull request: ${i.join(", then ")}.`;return c.length&&(l+=` ${c.join(", and ").replace(/^./,u=>u.toUpperCase())}.`),l+=` Leave the existing open PR${r?` #${r}`:""}${t?` and its remote branch (${t})`:" and its remote branch"} exactly as they are \u2014 don't push ${t||"the old branch"} itself.`,l}function Uk(e,t=Date.now()){let n=[],r=null;for(let o of e||[]){let s=o.payload||{},a=s.ts??o.ts;if(o.type==="pr.offer.answered"&&s.action==="pr"){r={box:o.boxId,from:a,lastActivity:a};continue}if(o.type==="pr.exists.answered"&&s.choice==="new"){r={box:o.boxId,from:a,lastActivity:a};continue}!r||a==null||a<r.from||(o.type==="pr.offer.answered"||o.type==="pr.exists.answered"?r=null:o.type==="pr.state.changed"&&s.change==="opened"?(n.push({box:r.box,from:r.from,to:a,settled:!0}),r=null):o.type==="turn.user"&&o.source!=="hook"&&!s.kind&&String(s.text||"").trim()?r=null:o.boxId===r.box&&/^(?:turn|tool)\./.test(o.type)&&(r.lastActivity=Math.max(r.lastActivity,a)))}return r&&t-r.lastActivity<=VC&&n.push({box:r.box,from:r.from,to:t+1e12}),n}function Hk(e,t){let n=new Set;for(let r of t||[]){if(!r.settled)continue;let o=null;for(let s of e||[])s.kind!=="message"||s.role!=="assistant"||s.box!==r.box||s.ts==null||s.ts<r.from||s.ts>r.to+zC||(!o||s.ts>=o.ts)&&(o=s);o&&n.add(o)}return n}function Wk(e){let t=(Array.isArray(e)?e:[]).filter(r=>Ok[r]).map(r=>Ok[r]);return`The ship you were given the go-ahead for${t.length?` (${t.join(", then ")})`:""} should now be complete. This is an automated ship notification the operator armed on the offer: carry straight on with this Track's follow-up work (dependent tasks, cleanup, next steps) \u2014 don't wait for review or merge. If a ship step failed or is unfinished, finish the ship first. If nothing needs doing, say so briefly.`}var Ck,Mk,Nk,Pk,jC,LC,FC,UC,Yo,WC,Bk,qC,KC,GC,VC,zC,Ok,Qo=C(()=>{Ck=/(?<!\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,Mk=/(?<!\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,Nk=/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,Pk=/(?<!\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,jC=new RegExp(`\\b(?:${Ck}|${Mk}|${Nk}|${Pk})\\b`,"i"),LC=/\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,FC=/^(?:commit|push|open|create|raise|rebase|ready|ok(?:ay)?\s+to|good\s+to)\b/i,UC=90;Yo=["commit","rebase","push","pr"],WC=new RegExp(`\\b(?:${Ck})\\b`,"i"),Bk=new RegExp(`\\b(?:${Pk})\\b`,"i"),qC=new RegExp(`\\b(?:${Mk})\\b`,"i"),KC=new RegExp(`\\b(?:${Nk})\\b`,"i"),GC=/\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;VC=3e4;zC=2500;Ok={commit:"commit",rebase:"rebase",push:"push",pr:"open a PR"}});import JC from"node:crypto";import Yc from"node:fs/promises";import qk from"node:path";import XC from"node:os";async function Ce(){return ar||(Uf??=Yc.readFile(Wf,"utf8").then(e=>({links:JSON.parse(e)?.links??{},existed:!0})).catch(()=>({links:{},existed:!1})).then(async({links:e,existed:t})=>{if(ar=e,!t&&Ae()){let{records:n,source:r}=await Fe("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;ar[Q(i.repo,i.number)]=i}Object.keys(ar).length&&await qf().catch(()=>{})}}return ar}).finally(()=>Uf=null),Uf)}async function qf(){let e=JSON.stringify({links:ar},null,2),t=`${Wf}.${process.pid}.tmp`;await Yc.mkdir(Kk,{recursive:!0}),await Yc.writeFile(t,e),await Yc.rename(t,Wf)}async function Ue(e){Hf=Hf.then(qf,qf),await Hf.catch(()=>{});let t=ar?.[e];t&&tt("prlinks",{id:Gk(e),updatedAt:Date.now(),...t},{trackId:t.trackId??null}).catch(()=>{})}async function mt({repo:e,number:t,trackId:n,url:r=null,headRef:o=null,title:s=null,source:a="matched"}){if(!e||!Number.isInteger(Number(t))||!n)return{link:null,created:!1};let i=await Ce(),c=Q(e,t);return i[c]?{link:i[c],created:!1}:(i[c]={repo:e,number:Number(t),trackId:n,url:r,headRef:o,title:s,source:a,announced:YC.has(a),firstSeen:Date.now()},await Ue(Q(e,t)),{link:i[c],created:!0})}async function wn(e,t){if(!e||t==null)return null;let n=(await Ce())[Q(e,t)];return!n||n.announced?null:(n.announced=!0,await Ue(Q(e,t)),n)}async function qe(e,t){return!e||t==null?null:(await Ce())[Q(e,t)]??null}async function ir(e,t,n){if(!e||t==null)return null;let r=(await Ce())[Q(e,t)];return r?(r.state=n,r.resolvedAt=Date.now(),delete r.armedAt,delete r.autoMerge,delete r.archiveOnMerge,delete r.notifyOnMerge,delete r.notifyPending,await Ue(Q(e,t)),r):null}async function Vk(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await Ce())[Q(e,t)];return o?(o.ciFix={delegatedAt:Date.now(),headSha:n,trackId:r},await Ue(Q(e,t)),o):null}async function zk(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await Ce())[Q(e,t)];return o?(o.reconcile={delegatedAt:Date.now(),headSha:n,trackId:r},await Ue(Q(e,t)),o):null}async function Zc(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await Ce())[Q(e,t)];return!r||!r.ciFix?null:(r.ciFixAwait={since:Date.now(),trackId:r.ciFix.trackId??null,headSha:n},delete r.ciFix,await Ue(Q(e,t)),r)}async function Qc(e,t){if(!e||t==null)return null;let n=(await Ce())[Q(e,t)];return!n||!n.ciFixAwait?null:(delete n.ciFixAwait,await Ue(Q(e,t)),n)}async function el(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await Ce())[Q(e,t)];return!r||!r.reconcile?null:(r.reconcileAwait={since:Date.now(),trackId:r.reconcile.trackId??null,headSha:n},delete r.reconcile,await Ue(Q(e,t)),r)}async function tl(e,t){if(!e||t==null)return null;let n=(await Ce())[Q(e,t)];return!n||!n.reconcileAwait?null:(delete n.reconcileAwait,await Ue(Q(e,t)),n)}async function Jk(e,t,{at:n=Date.now()}={}){if(!e||t==null)return null;let r=(await Ce())[Q(e,t)];return r?(r.baseFoldAt=n,await Ue(Q(e,t)),r):null}async function Xk(e,t){if(!e||t==null)return null;let n=(await Ce())[Q(e,t)];return!n||!n.baseFoldAt?null:(delete n.baseFoldAt,await Ue(Q(e,t)),n)}async function Yk(e,t,n){if(!e||t==null||!n)return null;let r=(await Ce())[Q(e,t)];return r?(r.lastHeadSha=n,await Ue(Q(e,t)),r):null}async function Zk(e,t,n){if(!e||t==null||!n)return{prev:null,link:null};let r=(await Ce())[Q(e,t)];if(!r)return{prev:null,link:null};let o=r.verdict??null;return o&&o.blocked===(n.blocked??null)&&(o.sha??null)===(n.sha??null)||(r.verdict={blocked:n.blocked??null,sha:n.sha??null,at:n.at??Date.now()},await Ue(Q(e,t))),{prev:o,link:r}}async function Na(e,t,{merge:n=null}={}){if(!e||t==null)return null;let r=(await Ce())[Q(e,t)];return r?(r.armedAt=Date.now(),n&&(r.autoMerge={method:n.method||"merge",armedAt:r.armedAt}),await Ue(Q(e,t)),r):null}async function Jr(e,t,n=!0){if(!e||t==null)return null;let r=(await Ce())[Q(e,t)];return r?(n?r.archiveOnMerge=!0:delete r.archiveOnMerge,await Ue(Q(e,t)),r):null}async function Pa(e,t,n=!0){if(!e||t==null)return null;let r=(await Ce())[Q(e,t)];return r?(n?r.notifyOnMerge=!0:delete r.notifyOnMerge,await Ue(Q(e,t)),r):null}async function Qk(e,t,n){if(!e||t==null)return null;let r=(await Ce())[Q(e,t)];if(!r)return null;r.notifyOnMerge=!0;let o=new Map((r.notifyPending||[]).map(s=>[`${s.repo}#${s.number}`,s]));for(let s of n||[])s&&s.number!=null&&o.set(`${s.repo}#${s.number}`,s);return r.notifyPending=[...o.values()],await Ue(Q(e,t)),r}async function Da(e,t){if(!e||t==null)return null;let n=(await Ce())[Q(e,t)];return!n||!n.armedAt&&!n.autoMerge?null:(delete n.armedAt,delete n.autoMerge,delete n.archiveOnMerge,delete n.notifyOnMerge,delete n.notifyPending,await Ue(Q(e,t)),n)}async function ex(){return Object.values(await Ce()).filter(e=>!ZC.has(e.state))}async function Xr(){return Object.values(await Ce()).sort((e,t)=>t.firstSeen-e.firstSeen)}async function tx(){if(!Ae())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await Fe("prlinks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Ce(),r=0;for(let[o,s]of Object.entries(n))await tt("prlinks",{id:Gk(o),updatedAt:Date.now(),...s},{trackId:s.trackId??null}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}var Kk,Wf,Q,Gk,ar,Uf,Hf,YC,ZC,gn=C(()=>{Gn();Kk=process.env.BOSTRAT_STATE_DIR||qk.join(process.env.HOME||XC.tmpdir(),".bostrat"),Wf=qk.join(Kk,"pr-links.json"),Q=(e,t)=>`${e}#${Number(t)}`,Gk=e=>{let t=e.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^[^A-Za-z0-9]+/,"").slice(0,55),n=JC.createHash("sha256").update(e).digest("hex").slice(0,8);return`${t||"pr"}-${n}`},ar=null,Uf=null,Hf=Promise.resolve();YC=new Set(["api","observed","reconciled"]);ZC=new Set(["merged","closed","lost"])});import QC from"node:fs";import Kf from"node:fs/promises";import sx from"node:path";import eM from"node:os";function cx(e,t=!1){if(!t&&e-rx<tM)return;rx=e;let n=JSON.stringify({windowStart:es,byCaller:Object.fromEntries(yn),lastHour:cr});ox=ox.then(()=>Kf.mkdir(ax,{recursive:!0})).then(()=>Kf.writeFile(`${nl}.tmp`,n)).then(()=>Kf.rename(`${nl}.tmp`,nl)).catch(()=>{})}function lx(e){e-es<ix||(cr={start:es,total:rl(yn),byCaller:Object.fromEntries(yn)},cr.total&&console.log(`[github] ${cr.total} calls last hour`,cr.byCaller),es=e,yn=new Map,cx(e,!0))}function bn(e="other",t=Date.now()){lx(t),yn.set(e,(yn.get(e)||0)+1),cx(t)}function ux(e=Date.now()){return lx(e),{windowStart:es,total:rl(yn),byCaller:Object.fromEntries(yn),lastHour:cr,backoffUntil:Yr>e?Yr:null}}function lr(e){return nM.test(String(e?.message||e||""))}function ur(e,t=Date.now()){return Yr<=t&&console.warn(`[github] rate limited \u2014 backing off ${nx/6e4} min:`,String(e?.message||e||"").slice(0,200)),Yr=Math.max(Yr,t+nx),Yr}function ol(e=Date.now()){return Math.max(0,Yr-e)}var ax,nl,ix,nx,tM,es,yn,cr,Yr,rx,rl,ox,nM,Ba=C(()=>{ax=process.env.BOSTRAT_STATE_DIR||sx.join(process.env.HOME||eM.tmpdir(),".bostrat"),nl=sx.join(ax,"github-metrics.json"),ix=60*6e4,nx=5*6e4,tM=6e4,es=Date.now(),yn=new Map,cr=null,Yr=0,rx=0,rl=e=>[...e.values()].reduce((t,n)=>t+n,0);try{let e=JSON.parse(QC.readFileSync(nl,"utf8"));e?.windowStart&&(Date.now()-e.windowStart<ix?(es=e.windowStart,yn=new Map(Object.entries(e.byCaller||{})),cr=e.lastHour||null):rl(new Map(Object.entries(e.byCaller||{})))&&(cr={start:e.windowStart,total:rl(new Map(Object.entries(e.byCaller||{}))),byCaller:e.byCaller||{}}))}catch{}ox=Promise.resolve();nM=/rate limit|too quickly|abuse detection|HTTP 429/i});import dx from"node:fs/promises";import fx from"node:path";import rM from"node:os";function al({change:e,repo:t=null,number:n=null,githubAt:r=null,observedAt:o=Date.now(),lane:s=null,intervalMs:a=null,source:i=null}){let c=r?o-r:null,l={change:e,repo:t,number:n,githubAt:r,observedAt:o,latencyMs:c,lane:s,intervalMs:a,source:i};sl.push(l),sl.length>sM&&sl.shift();let u=Gf.get(e)||{count:0,measured:0,totalMs:0,maxMs:0};return u.count+=1,c!=null&&(u.measured+=1,u.totalMs+=c,u.maxMs=Math.max(u.maxMs,c)),Gf.set(e,u),aM(l),l}async function aM(e){try{await dx.mkdir(px,{recursive:!0}),await dx.appendFile(oM,JSON.stringify(e)+`
142
+ `)}catch{}}function mx(){let e={};for(let[t,n]of Gf)e[t]={count:n.count,measured:n.measured,avgMs:n.measured?Math.round(n.totalMs/n.measured):null,maxMs:n.measured?n.maxMs:null};return{byChange:e,recent:sl.slice(-20)}}var px,oM,sM,sl,Gf,il=C(()=>{px=process.env.BOSTRAT_STATE_DIR||fx.join(process.env.HOME||rM.tmpdir(),".bostrat"),oM=fx.join(px,"github-latency.ndjson"),sM=100,sl=[],Gf=new Map});import{execFile as iM}from"node:child_process";import{promisify as cM}from"node:util";async function lM(e){let t=/workspaces[/\\]([0-9a-f]{8})(?:[/\\]|$)/.exec(e||"")?.[1];if(t)try{let[{stdout:n},{stdout:r}]=await Promise.all([ns("git",["-C",e,"rev-parse","HEAD"]),ns("git",["-C",e,"rev-parse","--abbrev-ref","HEAD"])]);await _({id:t,cwd:e},{type:"code.pushed",actor:"orchestrator",payload:{ref:r.trim(),sha:n.trim(),wip:!1,ts:Date.now()}})}catch{}}async function vt(e,t,n={}){let{caller:r="prs",...o}=n,s=await qt({cwd:e});bn(r);try{let{stdout:a}=await ns("gh",t,{cwd:e,...uM,...o,env:{...process.env,...s,...o.env||{}}});return String(a||"")}catch(a){throw lr(a)&&ur(a),a}}async function Jf(){if(cl&&Date.now()-cl.at<6e4)return cl.data;let e;try{bn("auth");let t=await ns("gh",["auth","status"],{timeout:1e4});e={installed:!0,authenticated:!0,login:`${t.stdout||""}${t.stderr||""}`.match(/account\s+(\S+)/)?.[1]??null}}catch(t){e=t?.code==="ENOENT"||t?.code===127?{installed:!1,authenticated:!1,login:null}:{installed:!0,authenticated:!1,login:null}}if(e.installed&&!e.authenticated)try{let t=await zs();t.configured&&(e={installed:!0,authenticated:!0,login:t.username,via:"broker"})}catch{}return cl={at:Date.now(),data:e},e}async function dM(e){try{let{stdout:t}=await ns("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});return/github\.com/.test(t)}catch{return!1}}function wx(e){let t=e.name||e.context||"check",n=e.detailsUrl||e.targetUrl||null,r=e.completedAt||e.createdAt||null,o;return e.__typename==="StatusContext"?o=e.state==="SUCCESS"?"pass":e.state==="PENDING"||e.state==="EXPECTED"?"pending":"fail":e.status&&e.status!=="COMPLETED"?o="pending":["SUCCESS","NEUTRAL","SKIPPED"].includes(e.conclusion)?o="pass":o="fail",{name:t,state:o,url:n,completedAt:r}}function Vf(e){let t=(e||[]).map(wx),n=t.filter(s=>s.state==="pending").length,r=t.map(s=>Date.parse(s.completedAt||"")).filter(s=>s>0),o=t.length&&!n&&r.length?Math.max(...r):null;return{total:t.length,passed:t.filter(s=>s.state==="pass").length,failed:t.filter(s=>s.state==="fail").length,pending:n,failing:t.filter(s=>s.state==="fail").map(({name:s,url:a})=>({name:s,url:a})),settledAt:o}}function Yf(e){return/Resource not accessible by personal access token/.test(String(e?.stderr||e?.message||""))}async function yx(e,t){if(!t)return null;let n=await me(e);if(!n)return null;try{let r=await vt(e,["api",`repos/${n}/actions/runs?head_sha=${encodeURIComponent(t)}&per_page=100`,"--jq",".workflow_runs"]),o=new Map;for(let s of JSON.parse(r||"[]"))o.has(s.name)||o.set(s.name,s);return[...o.values()]}catch{return null}}function bx(e){return(e||[]).map(t=>({name:t.name,detailsUrl:t.html_url||null,status:String(t.status||"").toUpperCase(),conclusion:t.conclusion?String(t.conclusion).toUpperCase():null,completedAt:t.status==="completed"&&t.updated_at||null}))}async function kx(e,t){let n=await yx(e,t);return n===null?{...Vf([]),unavailable:!0}:Vf(bx(n))}function ll(e,t=Vf(e.statusCheckRollup)){return{number:e.number,title:e.title,url:e.url,author:e.author?.login??null,headRefName:e.headRefName,headSha:e.headRefOid??null,baseRefName:e.baseRefName,isDraft:!!e.isDraft,reviewDecision:e.reviewDecision||null,mergeable:e.mergeable||"UNKNOWN",mergeStateStatus:e.mergeStateStatus||"UNKNOWN",additions:e.additions??0,deletions:e.deletions??0,createdAt:e.createdAt,updatedAt:e.updatedAt,checks:t,green:t.failed===0&&t.pending===0&&e.mergeStateStatus==="CLEAN",autoMergeArmed:!!e.autoMergeRequest,mergeabilityPending:!1}}function pM(e,t,n){let r=new Set;for(let o of t){let s=`${e}#${o.number}`;if(o.mergeable!=="UNKNOWN"&&o.mergeStateStatus!=="UNKNOWN"){ts.delete(s);continue}r.add(s),ts.has(s)||ts.set(s,n),o.mergeabilityPending=n-ts.get(s)<fM}for(let o of ts.keys())o.startsWith(`${e}#`)&&!r.has(o)&&ts.delete(o);return t}async function rs(e,t){let n=await kn(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{let o=await vt(n.path,["pr","view",String(r),"--json",Xf]);return ll(JSON.parse(o))}catch(o){if(!Yf(o))throw o;let s=await vt(n.path,["pr","view",String(r),"--json",gx]),a=JSON.parse(s);return ll(a,await kx(n.path,a.headRefOid))}}async function Jt(e,{caller:t="prs"}={}){try{let n=await vt(e,["pr","list","--json",Xf,"--limit","50"],{caller:t});return JSON.parse(n||"[]").map(r=>ll(r)).sort(hx)}catch(n){if(!Yf(n))throw n;let r=await vt(e,["pr","list","--json",gx,"--limit","50"],{caller:t});return(await Promise.all(JSON.parse(r||"[]").map(async o=>ll(o,await kx(e,o.headRefOid))))).sort(hx)}}function Yt(){ja.clear()}async function wM(e,t){if(!e)return t;for(let n of t){let r=await qe(e,n.number).catch(()=>null);if(!r)continue;r.trackId&&(n.trackId=r.trackId),r.autoMerge&&(n.autoMergeArmed=!0),r.archiveOnMerge&&(n.archiveOnMerge=!0),r.notifyOnMerge&&(n.notifyOnMerge=!0);let o=s=>n.headSha&&s.headSha&&n.headSha!==s.headSha;r.ciFix&&(o(r.ciFix)?await Zc(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.ciFix={delegatedAt:r.ciFix.delegatedAt,trackId:r.ciFix.trackId??null}),r.reconcile&&(o(r.reconcile)?await el(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.reconcile={delegatedAt:r.reconcile.delegatedAt,trackId:r.reconcile.trackId??null})}return t}async function xx(){let e=await Jf();if(!e.authenticated)return{auth:e,repos:[]};let t=[];for(let a of await un())await dM(a.path)&&t.push(a);let n=Date.now(),r=ol(n)>0,o=await Promise.all(t.map(async a=>{let i=ja.get(a.path),c=i?.pending?hM:mM;if(i&&(r||n-i.at<c))return i.entry;try{let l=await me(a.path).catch(()=>null),u=pM(a.path,await Jt(a.path,{caller:"tab"}),n);if(await wM(l,u),i?.entry?.prs)for(let p of u)i.entry.prs.find(h=>h.number===p.number)?.checks?.pending>0&&p.checks.total>0&&p.checks.pending===0&&al({change:p.checks.failed>0?"checks-failed":"checks-green",repo:l||a.name,number:p.number,githubAt:p.checks.settledAt,source:"tab"});let f={name:a.name,path:a.path,prs:u},d=u.some(p=>p.mergeabilityPending||p.checks.pending>0||p.autoMergeArmed);return ja.set(a.path,{at:Date.now(),entry:f,pending:d}),f}catch(l){return i?i.entry:{name:a.name,path:a.path,prs:[],error:Xt(l)}}})),s=new Set(t.map(a=>a.path));for(let a of ja.keys())s.has(a)||ja.delete(a);return{auth:e,repos:o}}async function kn(e){let t=(await un()).find(n=>n.path===e);if(!t)throw new Error(`unknown repo: ${e}`);return t}async function Zr(e){return bo(e)}async function os(e,t,{method:n="squash"}={}){let r=await kn(e);if(!La.has(n))throw new Error(`invalid merge method: ${n}`);let o=Number(t);if(!Number.isInteger(o)||o<=0)throw new Error("invalid PR number");let s=["pr","merge",String(o),`--${n}`];if(n!=="rebase"&&(await qt({cwd:r.path})).GH_TOKEN){let a=await Uu().catch(()=>null);a&&s.push("--body",`Merged by bostrat on behalf of @${a}`)}try{await vt(r.path,s)}catch(a){throw new Error(Xt(a))}finally{Yt()}return{ok:!0,number:o}}async function Fa(e,t){let n=await kn(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await vt(n.path,["api","-X","PUT",`repos/{owner}/{repo}/pulls/${r}/update-branch`])}catch(s){throw new Error(Xt(s))}finally{Yt()}let o=await me(n.path).catch(()=>null);return o&&await Jk(o,r).catch(()=>{}),{ok:!0,number:r}}async function Zf(e,t){let n=await kn(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await vt(n.path,["pr","merge",String(r),"--disable-auto"])}catch(o){throw new Error(Xt(o))}finally{Yt()}return{ok:!0,number:r}}function Qf(e){return e.green&&!e.isDraft}function kM(e){return e.isDraft?"draft":e.mergeable==="CONFLICTING"?`conflicts with ${e.baseRefName}`:e.checks.failed>0?"checks failing":e.checks.pending>0?"checks running":e.mergeable==="UNKNOWN"||e.mergeStateStatus==="UNKNOWN"?"mergeability unresolved":e.mergeStateStatus==="BEHIND"?`behind ${e.baseRefName}`:e.mergeStateStatus==="BLOCKED"?"blocked by branch protection":`not clean (${e.mergeStateStatus})`}function Sx(e,{update:t=!0}={}){return e.isDraft?{action:"skip",reason:"draft"}:Qf(e)?{action:"merge"}:t&&e.mergeStateStatus==="BEHIND"&&e.mergeable!=="CONFLICTING"&&e.checks.failed===0?{action:"update-arm"}:{action:"arm"}}function vx(e){return[...e.filter(t=>t.plan.action!=="merge"),...e.filter(t=>t.plan.action==="merge")]}function Tx(){let e={};for(let[t,n]of zf)e[t]={...n};return e}async function Ex(e,{method:t="merge",onMerged:n=null}={}){let r=await kn(e);if(!La.has(t))throw new Error(`invalid merge method: ${t}`);if(zf.get(r.path)?.running)throw new Error("a merge-all is already running for this repo");let o=(await Jt(r.path)).filter(Qf).sort((a,i)=>Date.parse(a.createdAt)-Date.parse(i.createdAt));if(!o.length)throw new Error("no PRs ready to merge");let s={running:!0,startedAt:Date.now(),finishedAt:null,method:t,total:o.length,current:o[0].number,queue:o.map(a=>({number:a.number,title:a.title})),merged:[],skipped:[],failed:[]};return zf.set(r.path,s),SM(s,o,{listPrs:()=>Jt(r.path),merge:a=>os(r.path,a,{method:t}),sleep:bM,onMerged:n}).catch(()=>{}),{ok:!0,repo:r.path,total:s.total,queue:o.map(a=>a.number)}}async function xM(e,t){let n=Date.now()+(t.settleMaxMs??yM),r=null;for(;;){let o=null;try{if(o=await t.listPrs(),r=null,!o.some(a=>e.includes(a.number)&&(a.mergeable==="UNKNOWN"||a.mergeStateStatus==="UNKNOWN")))return o}catch(s){r=s}if(Date.now()>=n){if(o)return o;if(r)throw r;return[]}await t.sleep(gM)}}async function SM(e,t,n){try{let r=t;for(let o=0;o<t.length;o++){let s=t[o];if(e.current=s.number,o>0)try{r=await xM(t.slice(o).map(i=>i.number),n)}catch(i){for(let c of t.slice(o))e.failed.push({number:c.number,title:c.title,reason:`couldn't re-check PR state: ${Xt(i)}`});break}let a=r.find(i=>i.number===s.number);if(!a){e.skipped.push({number:s.number,title:s.title,reason:"no longer open"});continue}if(!Qf(a)){e.skipped.push({number:a.number,title:a.title,reason:kM(a)});continue}try{await n.merge(a.number),e.merged.push({number:a.number,title:a.title});try{await n.onMerged?.(a)}catch{}}catch(i){e.failed.push({number:a.number,title:a.title,reason:Xt(i)})}}}finally{e.current=null,e.running=!1,e.finishedAt=Date.now(),Yt()}}async function ep(e,{title:t,body:n="",base:r=null}={}){if(typeof t!="string"||!t.trim())throw new Error("title required");try{await ns("git",["-C",e,"push","-u","origin","HEAD"],{timeout:12e4,maxBuffer:4*1024*1024})}catch(l){throw new Error(`push failed: ${Xt(l)}`)}await lM(e);let o=n||"";if((await qt({cwd:e})).GH_TOKEN){let l=await Uu().catch(()=>null);l&&(o=`${o?`${o}
143
+
144
+ `:""}Opened by bostrat on behalf of @${l}`)}let s=["pr","create","--title",t.trim(),"--body",o];r&&s.push("--base",r);let a;try{a=await vt(e,s)}catch(l){throw new Error(Xt(l))}finally{Yt()}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 Ax(e,t){let n=await kn(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");let o;try{let i;try{i=await vt(n.path,["pr","checks",String(r),"--json","name,state,link,bucket"])}catch(c){if(i=String(c?.stdout||""),!i.trim())throw new Error(Xt(c))}o=JSON.parse(i||"[]").filter(c=>c.bucket==="fail")}catch(i){if(!Yf(i))throw i;let c=await vt(n.path,["pr","view",String(r),"--json","headRefOid"]),l=await yx(n.path,JSON.parse(c).headRefOid);if(l===null)throw new Error(Xt(i));o=bx(l).map(wx).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=vM(i.link),l=null;c&&!s.has(c)&&(s.add(c),l=await vt(n.path,["run","view",c,"--log-failed"]).then(u=>TM(u)).catch(()=>null)),a.push({name:i.name,link:i.link||null,log:l})}return a}function vM(e){return String(e||"").match(/\/actions\/runs\/(\d+)/)?.[1]??null}function TM(e,{maxLines:t=400,maxBytes:n=64*1024}={}){let r=String(e||""),o=r.split(`
142
145
  `);return o.length>t&&(r=`\u2026 (${o.length-t} earlier lines truncated)
143
146
  `+o.slice(-t).join(`
144
147
  `)),Buffer.byteLength(r)>n&&(r=`\u2026 (truncated)
145
- `+r.slice(-n)),r}function zt(e){return String(e?.stderr||e?.message||e||"").trim().split(`
146
- `).find(n=>n.trim())||"gh failed"}var Qo,VC,ol,qf,u0,JC,Zo,c0,XC,ZC,Ma,Na,eM,tM,nM,Hf,ns=O(()=>{Un();Qe();wn();Ca();rl();ue();Qo=KC(qC),VC={timeout:3e4,maxBuffer:8*1024*1024};ol=null;qf="number,title,url,headRefName,headRefOid,baseRefName,isDraft,author,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup,autoMergeRequest,additions,deletions,createdAt,updatedAt",u0=qf.replace("statusCheckRollup,","");JC=9e4,Zo=new Map;c0=(e,t)=>e.number-t.number;XC=3e4,ZC=1500,Ma=new Map;Na=new Set(["squash","merge","rebase"]);eM=2500,tM=9e4,nM=e=>new Promise(t=>setTimeout(t,e));Hf=new Map});import{execFile as cM}from"node:child_process";import{promisify as lM}from"node:util";async function dM(e,t){try{let{stdout:n}=await uM("git",["-C",e,"rev-list","--count",t]);return Number(n.trim())||0}catch{return null}}async function fM(e,t,n,{rebase:r=!1,listPrs:o=Vt}={}){let s=await Ea(e.dir,{ignorePlumbing:!0}).catch(()=>!1),a=await Aa(e.dir,n).catch(()=>0),i=t?await dM(e.dir,`refs/remotes/origin/${t}..HEAD`):null,c=i==null?a>0:i>0,l=null,u="unknown";try{l=(await o(e.dir,{caller:"ship-state"})||[]).find(h=>h.headRefName===t)||null,u=l?"open":"none"}catch{}let f=s||a>0,d=[];s&&d.push("commit"),r&&d.push("rebase"),(s||c)&&d.push("push"),f&&(u!=="open"||s||c)&&d.push("pr");let p=d.filter(m=>!(m==="pr"&&u==="open"));return{name:e.name??null,slug:e.repo??null,dirty:s,unpushed:c,aheadBase:a,prState:u,openPr:l?{number:l.number,url:l.url??null,title:l.title??null}:null,available:al.filter(m=>d.includes(m)),defaults:al.filter(m=>p.includes(m))}}async function k0(e,{branch:t,rebase:n=!1,listPrs:r=Vt}={}){let o=e?.workspace,s=o?.kind==="multi"?(o.repos||[]).filter(d=>d?.dir):o?.base&&(o.dir||e?.cwd)?[{name:o.base?.split("/").pop()??null,dir:o.dir||e.cwd,repo:o.repo??null,baseRef:o.baseRef}]:[];if(!s.length||!await Ho(s[0].dir).catch(()=>!1))return null;let a=[];for(let d of s)a.push(await fM(d,t,d.baseRef||o.baseRef,{rebase:n,listPrs:r}));let i=a.filter(d=>d.dirty||d.aheadBase>0||d.openPr),c=i.length?i:a,l=al.filter(d=>c.some(p=>p.available.includes(d))),u=al.filter(d=>c.some(p=>p.defaults.includes(d))),f=c.filter(d=>d.openPr);return{available:l,defaults:u,prState:f.length?"open":c.every(d=>d.prState==="none")?"none":"unknown",openPr:c.length===1?c[0].openPr:null,repos:c.map(d=>({name:d.name,slug:d.slug,dirty:d.dirty,unpushed:d.unpushed,prState:d.prState,openPr:d.openPr}))}}var uM,al,x0=O(()=>{Lc();ns();uM=lM(cM),al=["commit","rebase","push","pr"]});function il(e,t,n){let{state:r,reason:o}=Ed(t,n);if(r!=="unknown"){if(e){let a=Date.now();for(let[i,c]of Da)a-c.at>=S0()&&Da.delete(i);Da.set(e,{busy:r==="busy",at:a})}return r==="busy"}if(o!=="narrow"||!e)return!1;let s=Da.get(e);return s?Date.now()-s.at>=S0()?(Da.delete(e),!1):s.busy:!1}async function Jf(e,t){let n={working:!1,prompted:!1};if(!e)return n;let r=await Ae(e,{lines:Le}).catch(()=>"");if(!il(e,t,r))return zg(t,r)?{working:!0,prompted:!1}:n;if(Vr(t,r)){let o=await fn(e).catch(()=>r),s=or({name:e,agent:t},o);if(s)return!Bc({name:e,agent:t},s,o)||qb(e)?{working:!1,prompted:!0}:{working:!1,prompted:!1}}return{working:!0,prompted:!1}}async function eo(e,t){return(await Jf(e,t)).working}var S0,Da,Ba=O(()=>{tt();Tc();gf();bf();S0=()=>Number(process.env.BOSTRAT_NARROW_CARRY_MS)||9e4,Da=new Map});import{execFile as pM}from"node:child_process";import{promisify as mM}from"node:util";async function rs(e){if(!e)return null;let t=v0.get(e);if(t&&Date.now()-t.at<wM)return t.branch;let n=null;try{let{stdout:r}=await hM("git",["-C",e,"symbolic-ref","--short","-q","HEAD"],{timeout:5e3});n=r.trim()||null}catch{n=null}return v0.set(e,{at:Date.now(),branch:n}),n}function T0(e){return String(e||"").match(gM)?.[1]??null}function yM(e,t){let n=T0(e);return!!n&&!!t&&n===t}function E0(e,t){let n=T0(e);return!!n&&n!==t}function bM(e){let t=e?.workspace;return t?.kind==="multi"?(t.repos??[]).map(n=>n?.dir).filter(Boolean):[t?.dir||e?.cwd].filter(Boolean)}async function os(e){let t=[],n=r=>{r&&!t.includes(r)&&t.push(r)};n(e?.workspace?.branch??null);for(let r of bM(e))n(await rs(r));return t}async function cl(e,t,n=()=>!0){if(!t)return null;let r=(e??[]).filter(a=>a&&n(a)),o=r.find(a=>a.workspace?.branch===t);if(o)return o;let s=r.find(a=>yM(t,a.id));if(s)return s;for(let a of r)if(!(a.archivedAt||a.transferredTo)&&(await os(a)).includes(t))return a;return null}var hM,wM,v0,gM,ss=O(()=>{hM=mM(pM),wM=5e3,v0=new Map;gM=/^track\/.+-([0-9a-f]{8})$/});import{execFile as kM}from"node:child_process";import{promisify as xM}from"node:util";async function Yf(e,t,{midTurn:n=eo,pollMs:r=SM,capMs:o=vM}={}){let s=Date.now()+o;for(;await n(e,t).catch(()=>!1);){if(Date.now()>=s)return!1;await new Promise(a=>setTimeout(a,r))}return!0}function O0(e){let t=String(e||""),n=0;for(let r=0;r<64;r++){A0.lastIndex=n;let o=A0.exec(t);if(!o)break;n=o.index+o[0].length;let s=o[1]==="-",a=o[2]??o[3]??o[4],i=t.indexOf(`
147
- `,o.index);if(i<0)break;let l=new RegExp("^"+(s?"\\t*":"")+$M(a)+"[ \\t]*$","m").exec(t.slice(i+1));if(!l)continue;let u=i+1+l.index+l[0].length;t=t.slice(0,i)+t.slice(u)}return t}function Xf(e,t){return e.slice(t).replace(/^[\s;&|)]+/,"").replace(/"[^"]*"|'[^']*'/g,'""').split(/[;&|\n]/)[0]}function M0(e){let t=O0(e),n=t.match(_M);if(!n)return null;let r=Xf(t,n.index);return RM.test(r)?null:{repo:r.match(C0)?.[1]??null,head:r.match(OM)?.[1]??null}}function N0(e){let t=O0(e),n=t.match(IM);if(!n)return null;let r=Xf(t,n.index),o=Xf(t,n.index+n[0].length),s=null,a=o.trim().split(/\s+/).filter(Boolean);for(let i=0;i<a.length;i++){let c=a[i];if(c.startsWith("-")){MM.has(c)&&i++;continue}s=c.replace(/^["']+|["']+$/g,"")||null;break}return{repo:r.match(C0)?.[1]??null,selector:s,auto:/\s--auto\b/.test(r)}}async function PM(e,t,{exclude:n=()=>!1}={}){let r=async i=>{yn("observer");let{stdout:c}=await _0("gh",["pr","list","--repo",e,"--author","@me","--state","all","--limit","10","--json",NM],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...i}}).catch(l=>{throw lr(l)&&ur(l),l});return JSON.parse(c||"[]")},o=i=>(i||[]).filter(c=>Date.parse(c.createdAt)>=t-TM&&!n(c)),s=await qt({slug:e}),a=o(await r(s));return!a.length&&s.GH_TOKEN&&(a=o(await r({}).catch(()=>[]))),a.sort((i,c)=>Date.parse(c.createdAt)-Date.parse(i.createdAt))}async function DM(e,t){if(t)return[t];let n=[];for(let r of P0(e)){let o=await me(r).catch(()=>null);o&&!n.includes(o)&&n.push(o)}for(let r of await cn().catch(()=>[])){let o=await me(r.path).catch(()=>null);o&&!n.includes(o)&&n.push(o)}return n}function P0(e){let t=e.workspace;return t?.kind==="multi"?(t.repos??[]).map(n=>n?.base).filter(Boolean):[t?.base||e.cwd].filter(Boolean)}async function BM(e,t,n){let r=await os(e).catch(()=>[e.workspace?.branch].filter(Boolean)),o=t?.head??null,s=c=>r.includes(c)||o&&c===o,a=c=>o!=null&&!s(c.headRefName)||CM(c.headRefName,e.id),i=[];for(let c of await DM(e,t?.repo??null)){let l;try{l=await PM(c,n,{exclude:a})}catch{continue}for(let u of l){let f=await qe(c,u.number);if(s(u.headRefName)){if(f&&f.trackId===e.id&&f.announced)return{settled:!0};if(f&&f.trackId!==e.id)continue;return{slug:c,pr:u}}f&&(f.trackId!==e.id||f.announced)||i.push({slug:c,pr:u})}}return i.length?(i.sort((c,l)=>Date.parse(l.pr.createdAt)-Date.parse(c.pr.createdAt)),i[0]):null}function D0(e,t,{delays:n=I0,turnEnd:r}={}){let o=M0(t.command);if(!o)return null;let s=!!N0(t.command),a=`${e.id}|${t.id??t.ts??t.command}`;if(dr.has(a))return null;dr.add(a);let i=t.ts??Date.now(),c=(async()=>{try{for(let l of n){await new Promise(h=>setTimeout(h,l));let u=await BM(e,o,i).catch(()=>null);if(u?.settled)return null;if(!u)continue;let{slug:f,pr:d}=u,{link:p,created:m}=await mt({repo:f,number:d.number,trackId:e.id,url:d.url,headRef:d.headRefName,title:d.title,source:"observed"});return!m&&!(p?.trackId===e.id&&await hn(f,d.number))?null:(await Yf(t.box,t.agent,r),await _({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Date.now(),change:"opened",number:d.number,url:d.url,title:d.title,branch:d.headRefName,repo:f,...s?{selfMerge:!0}:{}}}),d)}return null}finally{dr.delete(a)}})();return c.catch(()=>dr.delete(a)),c}function B0(e,t,{delays:n=I0,turnEnd:r,openedWait:o}={}){let s=N0(t.command);if(!s)return null;let a=`merge|${e.id}|${t.id??t.ts??t.command}`;if(dr.has(a))return null;dr.add(a);let i=(async()=>{try{let c=s.repo,l=s.selector,u=l?.match(/github\.com\/([\w.-]+\/[\w.-]+)\/pull\/(\d+)/);u&&([,c,l]=u);let f=[];if(c)f=[c];else{let m=P0(e);if(m.length>1&&/^\d+$/.test(String(s.selector??"")))return null;for(let h of m){let g=await me(h).catch(()=>null);g&&!f.includes(g)&&f.push(g)}}if(l||=(await os(e).catch(()=>[])).filter(m=>m!==e.workspace?.branch)[0]||e.workspace?.branch,!f.length||!l)return null;c=f[0];let d=async(m,h)=>{let g=await qe(c,m.number);return g&&g.trackId!==e.id?null:(g||await mt({repo:c,number:m.number,trackId:e.id,url:m.url,headRef:m.headRefName,title:m.title,source:"merge-observed"}),await Ra(c,m.number),h&&((await L(e).catch(()=>[])).some(E=>E.type==="pr.state.changed"&&(E.payload?.change==="auto-armed"||E.payload?.change==="merged")&&E.payload?.number===m.number)||(await Yf(t.box,t.agent,r),await _({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Date.now(),change:"auto-armed",number:m.number,url:m.url,title:m.title,branch:m.headRefName,repo:c}}))),m)},p=null;for(let m of n){await new Promise(N=>setTimeout(N,m));let h=[];for(let N of f)try{yn("observer");let{stdout:C}=await _0("gh",["pr","view",String(l),"--repo",N,"--json",jM],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...await qt({slug:N})}}),T=JSON.parse(C||"null");T?.number&&h.push({slug:N,pr:T})}catch(C){lr(C)&&ur(C)}let g=h.find(N=>N.pr.state==="MERGED")??(h.length===1?h[0]:null);if(!g)continue;c=g.slug;let x=g.pr;if(!x?.number)continue;if(x.state==="CLOSED")return null;if(x.state!=="MERGED"){if(p=x,s.auto)return d(x,!0);continue}let k=await qe(c,x.number);if(k&&k.trackId!==e.id)return null;k||await mt({repo:c,number:x.number,trackId:e.id,url:x.url,headRef:x.headRefName,title:x.title,source:"merge-observed"}),await Yf(t.box,t.agent,r);let E=await L(e).catch(()=>[]);if(E.some(N=>N.type==="pr.state.changed"&&N.payload?.change==="merged"&&N.payload?.number===x.number))return null;let I=N=>N.some(C=>C.type==="pr.state.changed"&&C.payload?.change==="opened"&&C.payload?.number===x.number),M=0;if(!I(E)){if(M0(t.command)&&await hn(c,x.number)){let N=Date.now();M=N+1,await _({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:N,change:"opened",number:x.number,url:x.url,title:x.title,branch:x.headRefName,repo:c,selfMerge:!0}})}else if((await qe(c,x.number))?.announced){let N=o?.capMs??EM,C=o?.pollMs??AM,T=Date.now()+N;for(;Date.now()<T&&(await new Promise(j=>setTimeout(j,C)),!I(await L(e).catch(()=>[]))););}}return await _({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Math.max(Date.now(),M),change:"merged",number:x.number,url:x.url,title:x.title,branch:x.headRefName,repo:c}}),await xn(c,x.number).catch(()=>{}),await kn(c,x.number).catch(()=>{}),await ir(c,x.number,"merged"),x}return p?d(p,!1):null}finally{dr.delete(a)}})();return i.catch(()=>dr.delete(a)),i}var _0,I0,SM,vM,TM,EM,AM,R0,$0,_M,IM,RM,A0,$M,C0,OM,CM,MM,NM,dr,jM,j0=O(()=>{ue();Un();Qe();Ca();wn();fr();Ba();ss();_0=xM(kM),I0=[4e3,15e3,45e3],SM=2500,vM=5*6e4;TM=15e3,EM=9e4,AM=2e3,R0=/(?:^|[;&|\n({`]\s*|\)\s*)(?:(?:then|do|else|elif|if|while|until|time)\s+)?/.source,$0=/gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+/.source,_M=new RegExp(`${R0}${$0}create\\b`),IM=new RegExp(`${R0}${$0}merge\\b`),RM=/\s--web\b/,A0=/<<(-?)\s*(?:'([^'\n]+)'|"([^"\n]+)"|\\?([A-Za-z_][\w-]*))/g,$M=e=>e.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");C0=/(?:--repo|-R)[\s=]+([\w.-]+\/[\w.-]+)/,OM=/(?:--head|-H)[\s=]+([^\s"'`;&|]+)/,CM=E0;MM=new Set(["--subject","-t","--body","-b","--body-file","-F","--match-head-commit","--author-email","-A","--repo","-R"]);NM="number,url,title,headRefName,createdAt";dr=new Set;jM="number,url,title,headRefName,state"});import LM from"node:fs/promises";import Qf from"node:path";import FM from"node:os";function Zf(e,t){let n=new RegExp(`\\b${t}="([^"]*)"`).exec(e);return n?n[1]:null}function ll(e){let t=UM.exec(String(e||""));if(!t)return null;let[,n,r]=t,o=Zf(n,"from"),s=o?o.replace(/^uds:/,""):null,a=L0(s);return{socket:s,pid:a,name:Zf(n,"from-name"),mode:Zf(n,"from-mode"),text:r.trim()}}function L0(e){let t=/(\d+)\.sock$/.exec(String(e||""));return t?Number(t[1]):null}function HM(){return process.env.CLAUDE_CONFIG_DIR?Qf.join(process.env.CLAUDE_CONFIG_DIR,"sessions"):Qf.join(FM.homedir(),".claude","sessions")}async function WM(e){let t=L0(e);if(!t)return null;try{let n=await LM.readFile(Qf.join(HM(),`${t}.json`),"utf8"),r=JSON.parse(n);return{pid:t,sessionId:r.sessionId??null,cwd:r.cwd??null,name:r.name??null,tmux:r.tmux??null}}catch{return null}}async function F0(e,t){let n=await WM(e?.socket),r=n?.cwd??null,o=null;if((n?.sessionId||r)&&typeof t=="function")try{o=await t(n?.sessionId??null,r)??null}catch{o=null}return{socket:e?.socket??null,pid:n?.pid??e?.pid??null,sessionId:n?.sessionId??null,cwd:r,tmux:n?.tmux??null,name:n?.name??e?.name??null,mode:e?.mode??null,trackId:o?.track?.id??null,trackName:o?.track?.name??null,boxId:o?.box?.name??null}}var UM,ep=O(()=>{UM=/<cross-session-message\b([^>]*)>([\s\S]*?)<\/cross-session-message>/});function tp(e=process.env){return!!(ke(e)&&e.BOSTRAT_PLANE_TOKEN)}async function np({loopId:e,outcome:t,note:n=null,env:r=process.env}={}){if(!tp(r))return{ok:!1,source:"unconfigured"};let o=new AbortController,s=setTimeout(()=>o.abort(),U0);try{let a=await H0(`${ke(r)}/v1/loops/${encodeURIComponent(e)}/report`,{method:"POST",headers:{authorization:`Bearer ${r.BOSTRAT_PLANE_TOKEN||""}`,"content-type":"application/json"},body:JSON.stringify({outcome:t,...n?{note:n}:{}}),signal:o.signal}),i=await a.json().catch(()=>({}));return a.ok?{ok:!0,source:"plane",status:a.status,run:i?.run||null}:{ok:!1,source:"plane",status:a.status,error:i?.error||`plane ${a.status}`}}catch(a){return{ok:!1,source:"unreachable",error:a?.message||String(a)}}finally{clearTimeout(s)}}async function W0(e,{provider:t=null,cls:n="other",status:r=null,text:o=""}={},{env:s=process.env,now:a=Date.now}={}){if(!e?.id||!String(e.name||"").startsWith("\u21BB"))return{ok:!1,source:"not-a-loop-track"};if(!tp(s))return{ok:!1,source:"unconfigured"};let i=ul.get(e.id)||0;if(a()-i<qM)return{ok:!1,source:"debounced"};ul.set(e.id,a());let c=await dl({env:s}),l=c.loops.find(d=>d.trackId===e.id);if(!l)return ul.delete(e.id),{ok:!1,source:c.source==="plane"?"no-loop":c.source};let u=`${t||"provider"} ${r?r+" ":""}${n}: ${String(o||"").replace(/\s+/g," ").trim()}`.slice(0,500),f=await np({loopId:l.id,outcome:"errored",note:u,env:s});return f.ok||ul.delete(e.id),{...f,loop:{id:l.id,name:l.name}}}async function dl({env:e=process.env}={}){if(!tp(e))return{loops:[],source:"unconfigured"};let t=new AbortController,n=setTimeout(()=>t.abort(),U0);try{let r=await H0(`${ke(e)}/v1/loops`,{headers:{authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`},signal:t.signal});if(!r.ok)throw new Error(`plane ${r.status}`);let o=await r.json();return{loops:Array.isArray(o?.loops)?o.loops:[],source:"plane"}}catch(r){return{loops:[],source:"unreachable",error:r?.message||String(r)}}finally{clearTimeout(n)}}var U0,H0,qM,ul,rp=O(()=>{Qe();U0=1e4,H0=(...e)=>fetch(...e);qM=10*6e4,ul=new Map});import{randomUUID as KM}from"node:crypto";function ja(e){return e.sourceId?`${e.role}|id:${e.sourceId}`:`${e.role}|${e.ts??"?"}|${String(e.text||"").slice(0,40)}`}function q0(e){return e.id?`cmd|${e.box}|id:${e.id}`:`cmd|${e.box}|${e.ts??"?"}|${String(e.command||"").slice(0,40)}`}function K0(e){return`job|${e.box}|id:${e.id}`}async function sp(e){return op.has(e.id)?op.get(e.id):(fl.has(e.id)||fl.set(e.id,L(e).then(t=>{let n={keys:new Set,cmdN:0};for(let r of t)if((r.type==="turn.user"||r.type==="turn.agent"||r.type==="provider.error")&&r.payload?.text!=null){let o=r.type==="turn.user"?"user":"assistant";r.payload.sourceId&&n.keys.add(ja({role:o,sourceId:r.payload.sourceId})),n.keys.add(ja({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(ja({role:"user",sourceId:r.payload.sourceId})),n.keys.add(ja({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(q0({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(K0({id:r.payload.id,box:r.boxId}));return op.set(e.id,n),n}).finally(()=>fl.delete(e.id))),fl.get(e.id))}async function G0(e,t){let n=new Set;try{let r=(await sp(e)).keys;for(let o of t||[]){if(!o||o.ts==null||!String(o.text||"").trim()&&!o.images?.length)continue;let s=ja(o);if(r.has(s))continue;r.add(s);let a=o.role==="user"?ll(o.text):null;if(a){await _(e,{type:"peer.message",actor:"peer",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{text:a.text,ts:o.ts,keyText:String(o.text||"").slice(0,40),from:await F0(a,La),boxRole:o.boxRole,sourceId:o.sourceId||void 0}});continue}let i=$g(o);if(i){await _(e,{type:"provider.error",actor:"system",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{cls:i.cls,code:i.code||void 0,status:i.status||void 0,requestId:i.requestId||void 0,text:o.text,ts:o.ts,model:o.model||null,boxRole:o.boxRole,sourceId:o.sourceId||void 0}}),W0(e,{provider:o.agent||null,cls:i.cls,status:i.status,text:o.text}).catch(()=>{});continue}if(o.role!=="user"&&o.box&&n.add(o.box),await _(e,{type:o.role==="user"?"turn.user":"turn.agent",actor:o.role==="user"?"user":"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{text:o.text,ts:o.ts,model:o.model||null,tools:o.tools||void 0,boxRole:o.boxRole,sourceId:o.sourceId||void 0,note:o.note||void 0,images:o.images?.length?o.images:void 0}}),o.role==="assistant"&&o.box===e.leadBox&&e.workspace?.branch){let c=Rk(o.text);if(c){let l=Ck(c),u;if(e.workspace?.kind==="multi"){let m=await as(e).catch(()=>[]);u=m.length?m.map(h=>({name:h.name,slug:h.repo??null})):void 0}let f=(e.workspace?.kind==="multi"?null:await rs(e.cwd).catch(()=>null))||e.workspace.branch,d=await k0(e,{branch:f,rebase:l}).catch(()=>null),p=d?null:Ok(c);if(d&&d.available.length===0)continue;await _(e,{type:"pr.offered",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{offerId:KM(),ts:o.ts,excerpt:c,branch:f,base:e.workspace.baseRef?.replace(/^origin\//,"")||null,boxRole:o.boxRole,available:d?.available,defaults:d?.defaults,prState:d?.prState,openPr:d?.openPr||void 0,repos:d?.repos||u,offered:d?.defaults||p?.offered||void 0,toPr:p?.toPr||void 0}})}}}}catch{}return{agentTurnBoxes:n}}async function V0(e,t){try{let n=await sp(e),r=[...t||[]].filter(o=>o&&String(o.command||"").trim()).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=q0(o);n.keys.has(s)||(n.keys.add(s),n.cmdN+=1,await _(e,{type:"tool.called",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{id:o.id??null,tool:o.tool||null,command:o.command,description:o.description||"",summary:o.summary||o.command,ts:o.ts??null,boxRole:o.boxRole,n:n.cmdN}}),D0(e,o),B0(e,o))}}catch{}}async function z0(e,t){try{let n=await sp(e),r=[...t||[]].filter(o=>o&&o.id).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=K0(o);n.keys.has(s)||(n.keys.add(s),await _(e,{type:"job.started",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{id:o.id,kind:o.kind||"agent",name:o.name||null,detail:o.detail||null,ts:o.ts??null,boxRole:o.boxRole}}))}}catch{}}var op,fl,J0=O(()=>{ue();Yo();x0();j0();ss();ep();fr();gc();rp();op=new Map,fl=new Map});function GM(e){let t=[],n=null;for(let r of String(e||"").split(`
148
- `)){let o=r.trim();if(!o||o[0]!=="{")continue;let s;try{s=JSON.parse(o)}catch{continue}let a=s.payload||{};if(s.type==="turn_context"&&a.model&&(n=a.model),s.type==="event_msg"&&a.type==="token_count"&&a.info?.last_token_usage){let i=a.info.last_token_usage;t.push({ts:s.timestamp?Date.parse(s.timestamp):null,model:n,last:{input:i.input_tokens||0,cachedInput:i.cached_input_tokens||0,output:i.output_tokens||0,reasoningOutput:i.reasoning_output_tokens||0},occupancy:i.total_tokens??null,contextWindow:a.info.model_context_window??null})}}return t}async function VM(e,t){let n=`${e.id}:${t.name}`;if(!ap.has(n)){let r=await L(e),o=new Set;for(let s of r)s.type==="cost.recorded"&&s.boxId===t.name&&s.payload?.codexTs!=null&&o.add(s.payload.codexTs);ap.set(n,o)}return ap.get(n)}async function Y0(e,t){try{if(t?.agent!=="codex"||!t.cwd)return;let n=await Pr(t.cwd,t.pinned?t.sessionId:null);if(!n)return;let r=await VM(e,t),o=GM(await it(n.file,262144)),s=o[o.length-1];for(let a of o){if(a.ts==null||r.has(a.ts))continue;r.add(a.ts);let i={input:Math.max(0,a.last.input-a.last.cachedInput),output:a.last.output,cacheRead:a.last.cachedInput,cacheWrite:0},c=a.model||t.model||"gpt-5.5";await _(e,{type:"cost.recorded",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{usd:tr(c,i),model:c,tokens:i,reasoningOutput:a.last.reasoningOutput||void 0,codexTs:a.ts,ts:a.ts}}),a===s&&a.contextWindow&&await _(e,{type:"context.usage",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{occupancy:a.occupancy,window:a.contextWindow,pct:a.occupancy!=null?a.occupancy/a.contextWindow:null,model:a.model||null,ts:a.ts}})}}catch{}}var ap,X0=O(()=>{ue();Br();Nt();xa();ap=new Map});import pl from"node:fs";import cp from"node:path";import zM from"node:os";async function XM({sinceMs:e,cookie:t,fetchImpl:n=fetch}){let r=[];for(let o=1;o<=20;o++){let s=await n(YM,{method:"POST",headers:{"content-type":"application/json",origin:"https://cursor.com",cookie:`WorkosCursorSessionToken=${t}`},body:JSON.stringify({teamId:0,startDate:String(e),endDate:String(Date.now()),page:o,pageSize:Z0})});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<Z0)break}return r}function ZM(e){if(!e)return null;let t=Number(e.timestamp)||null,n=e.tokenUsage||null,r=n?{input:n.inputTokens||0,output:n.outputTokens||0,cacheRead:n.cacheReadTokens||0,cacheWrite:n.cacheWriteTokens||0}:null,o=e.conversationId||null;return{id:[o||"?",t??"?",r?`${r.input}.${r.output}.${r.cacheRead}.${r.cacheWrite}`:"?"].join(":"),conversationId:o,ts:t,model:e.model||e.modelIntent||null,kind:e.kindLabel||e.kind||null,isHeadless:e.isHeadless===!0,tokens:r,vendorCents:n?.totalCents??null,chargedCents:e.chargedCents??null}}function ex(){try{return JSON.parse(pl.readFileSync(ml(),"utf8"))}catch{return{sinceMs:0,seen:[]}}}function eN(e){try{pl.mkdirSync(cp.dirname(ml()),{recursive:!0});let t=ml()+".tmp";pl.writeFileSync(t,JSON.stringify(e)),pl.renameSync(t,ml())}catch{}}async function nN({fetchImpl:e,now:t=Date.now()}={}){if(pr.rows&&t-pr.at<QM)return pr.rows;let n=process.env.BOSTRAT_CURSOR_USAGE_COOKIE;if(!n)return null;let r=ex(),o=Math.max(r.sinceMs-6e4,t-24*36e5);try{let s=await XM({sinceMs:o,cookie:n,fetchImpl:e});pr={at:t,rows:s.map(ZM).filter(Boolean),error:null}}catch(s){pr={at:t,rows:null,error:String(s?.message||s)}}return pr.rows}async function rN(e,t){let n=`${e.id}:${t.name}`;if(!ip.has(n)){let r=await L(e),o=new Set;for(let s of r)s.type==="cost.recorded"&&s.boxId===t.name&&s.payload?.cursorEventId&&o.add(s.payload.cursorEventId);ip.set(n,o)}return ip.get(n)}async function tx(e,t,{fetchImpl:n}={}){try{if(t?.agent!=="cursor"||!t.cwd||!Q0())return;let r=await nN({fetchImpl:n});if(!r||!r.length)return;let o=await Sb(t.cwd,t.pinned?t.sessionId:null);if(!o?.chatId)return;let s=await rN(e,t),a=ex(),i=new Set(a.seen||[]),c=a.sinceMs||0;for(let l of r){if(!l.conversationId||l.conversationId!==o.chatId||s.has(l.id)||i.has(`${e.id}:${t.name}:${l.id}`))continue;s.add(l.id),i.add(`${e.id}:${t.name}:${l.id}`),l.ts&&l.ts>c&&(c=l.ts);let u=l.model||o.models[o.models.length-1]||"cursor-unknown",f=l.tokens||null,d=l.vendorCents!=null?l.vendorCents/100:0;!d&&f&&(d=tr(u,f)),!d&&l.chargedCents!=null&&(d=l.chargedCents/100),await _(e,{type:"cost.recorded",actor:"agent",source:"vendor",boxId:t.name,provider:"cursor",payload:{usd:d,model:u,...f?{tokens:f}:{},...l.vendorCents!=null?{vendorCents:l.vendorCents}:{},...l.chargedCents!=null?{chargedCents:l.chargedCents}:{},...l.kind?{kind:l.kind}:{},conversationId:l.conversationId,cursorEventId:l.id,ts:l.ts??void 0}})}eN({sinceMs:c,seen:[...i].slice(-tN)})}catch{}}var JM,Q0,YM,Z0,QM,pr,ml,tN,lp,ip,up=O(()=>{ue();nf();xa();JM=process.env.BOSTRAT_STATE_DIR||cp.join(process.env.HOME||zM.tmpdir(),".bostrat"),Q0=(e=process.env)=>!!e.BOSTRAT_CURSOR_USAGE_COOKIE,YM="https://cursor.com/api/dashboard/get-filtered-usage-events",Z0=100;QM=5*6e4,pr={at:0,rows:null,error:null},ml=()=>cp.join(JM,"cursor-usage.json");tN=5e3;lp=()=>({enabled:Q0(),lastPollAt:pr.at||null,error:pr.error}),ip=new Map});import Ha from"node:fs/promises";import lt from"node:path";import oN from"node:os";import sN from"node:net";import{randomUUID as aN}from"node:crypto";import{execFile as iN}from"node:child_process";import{promisify as cN}from"node:util";function hN(e){for(let t of gp(e))if(!ix.test(t))return t;return null}function cx(e){let t=gp(e),n=t.indexOf("--");return n===-1?t:t.slice(0,n)}function wN(e,t){let n=cx(t);for(let r=0;r<n.length;r++){let o=/^--prefix=(.+)$/.exec(n[r]);if(o)return lt.resolve(e,o[1]);if(n[r]==="--prefix"&&n[r+1])return lt.resolve(e,n[r+1])}return e}function yN(e){let t=!1,n=!1;for(let r of gp(e)){if(!t){if(ix.test(r))continue;t=!0;continue}if(r.startsWith("-")){let o=r.indexOf("="),s=o===-1?null:r.slice(o+1);if(s&&dp(s))return`serves the filesystem root ("${s}")`;n=o===-1;continue}if(n){if(n=!1,dp(r))return`serves the filesystem root ("${r}")`;continue}if(dp(r))return`serves the filesystem root ("${r}")`;if(gN(r))return`serves a path that escapes the workspace ("${r}")`}return null}async function kN(e,t){if(lt.resolve(e)===lt.resolve(t))return!0;let[n,r]=await Promise.all([hl(e),hl(t)]);return n===r}async function xN(e){let n=(await Ha.readdir(e,{withFileTypes:!0}).catch(()=>[])).filter(o=>o.isDirectory()&&!o.name.startsWith(".")&&o.name!=="node_modules");return(await Promise.all(n.map(async o=>await lx(lt.join(e,o.name,mp))?`./${o.name}`:null))).filter(Boolean)}async function SN(e,t){let[n,r]=await Promise.all([hl(e),hl(t)]),o=lt.relative(n,r);if(o&&(o.startsWith("..")||lt.isAbsolute(o)))throw Fa(`serve directory escapes the Track workspace: ${t}`)}async function vN(e,t){let n=yN(t);if(n)throw Fa(`refusing this view: the command ${n} \u2014 serve a build dir, not the filesystem root`);if(!await bN(e))throw Fa(`serve directory does not exist: ${e}`);let r=hN(t);if(!r)return;if(!r.includes("/")&&!await og(r,{loginShell:!0,failOpen:!0}))throw Fa(`\`${r}\` is not on the box's PATH \u2014 install it in the box first`);if(fN.test(t)||pN.has(r)||!dN.has(r)||!cx(t).includes("run")||mN.test(t))return;let o=wN(e,t);if(await lx(lt.join(o,mp)))return;let s=await xN(o),a=s.length?` \u2014 found one in ${s.join(", ")}; run bostrat-view from there`:"";throw Fa(`no ${mp} in ${o}${a}`)}async function Tn(){return Yt||(fp||=(async()=>{try{Yt=JSON.parse(await Ha.readFile(ax,"utf8"))}catch{Yt={views:[],adoptWatermarks:{}}}finally{fp=null}return Yt.views||=[],Yt.adoptWatermarks||={},Yt})(),fp)}async function Zt(){await at(ax,Yt)}function vn(e,t,n={}){return _({id:e.trackId,cwd:e.cwd},{type:"view.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,payload:{ts:Date.now(),change:t,viewId:e.id,name:e.name,slug:e.slug,port:e.port,cmd:e.cmd||null,...n}}).catch(()=>{})}function bp(e){return Ua.get(e)||null}function dx(e,{name:t,box:n}={}){let r=Ua.get(e);if(r&&!r.finishedAt)throw new Error("a view is already being spun up for this Track");let o={trackId:e,name:t||"preview",box:n||null,step:"spinning-up",startedAt:Date.now(),finishedAt:null,viewId:null,error:null};return Ua.set(e,o),o}function hp(e,t){let n=Ua.get(e);n&&!n.finishedAt&&!n.viewId&&(n.viewId=t,n.step="booting")}function wl(e,{error:t=null}={}){let n=Ua.get(e);return!n||n.finishedAt?null:(n.finishedAt=Date.now(),t&&(n.error=t),n)}function fx(e){let t=[];for(let n of e?.events||[])n.type!=="view-spinup"||!n.box||!n.startedAt||!n.endedAt||t.push({box:n.box,from:n.startedAt,to:n.endedAt});return t}function wp(e){return String(e||"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40).replace(/-+$/g,"")||"view"}function TN(e,t){let n=wp(t),r=new Set(e.views.map(o=>o.slug));if(!r.has(n)&&!ox.has(n))return n;for(let o=2;;o++){let s=`${n}-${o}`;if(!r.has(s)&&!ox.has(s))return s}}function Wa(e,{timeoutMs:t=1200}={}){return new Promise(n=>{let r=sN.connect({port:e,host:"127.0.0.1"}),o=s=>{r.destroy(),n(s)};r.setTimeout(t,()=>o(!1)),r.once("connect",()=>o(!0)),r.once("error",()=>o(!1))})}async function kp(e){if(process.platform!=="darwin"){await Xt("fuser",["-k",`${e}/tcp`]).catch(()=>{});return}let t="";try{({stdout:t}=await Xt("lsof",["-t","-sTCP:LISTEN","-i",`tcp:${e}`]))}catch{return}for(let n of t.split(/\s+/).filter(Boolean)){let r=Number(n);if(!(!r||r===process.pid))try{process.kill(r,"SIGKILL")}catch{}}}function px(e=process.env){return new Set([Number(e.PORT)||3362,Number(e.BOSTRAT_TLS_PORT)||3443])}async function EN(e,t){let n=new Set(e.views.map(o=>o.port)),r=px();if(t){let o=Number(t);if(!Number.isInteger(o)||o<1024||o>65535)throw new Error("invalid port");if(r.has(o))throw new Error(`port ${o} is the node's own API port`);if(n.has(o))throw new Error(`port ${o} is already owned by a view`);return o}for(let o=nx;o<=rx;o++)if(!(n.has(o)||r.has(o))&&!await Wa(o,{timeoutMs:250}))return o;throw new Error(`no free view port in ${nx}-${rx}`)}async function AN(e){try{let{stdout:t}=await Xt(F,H("list-sessions","-F","#{session_name}"));return t.split(`
149
- `).some(n=>n.trim()===is(e))}catch{return!1}}async function qa(e){try{await Xt(F,H("kill-session","-t",is(e)))}catch{}}async function xp(e){if(!await ra())throw new Error("host tmux server not running and auto-start failed \u2014 cannot spawn a view server");let t=is(e.slug),n=e.serveCwd??e.cwd,r=lt.dirname(process.execPath);await Xt(F,H("new-session","-d","-s",t,"-c",n)),await Xt(F,H("send-keys","-t",t,"-l",`export PORT=${e.port} PATH="${r}:$PATH"`)),await Xt(F,H("send-keys","-t",t,"Enter")),await Xt(F,H("send-keys","-t",t,"-l",e.cmd)),await Xt(F,H("send-keys","-t",t,"Enter"))}async function sx(e,t=12){try{let{stdout:n}=await Xt(F,H("capture-pane","-t",is(e),"-p"));return String(n||"").trimEnd().split(`
148
+ `+r.slice(-n)),r}function Xt(e){return String(e?.stderr||e?.message||e||"").trim().split(`
149
+ `).find(n=>n.trim())||"gh failed"}var ns,uM,cl,Xf,gx,fM,ts,hx,mM,hM,ja,La,gM,yM,bM,zf,ss=C(()=>{Hn();et();gn();Ba();il();ue();ns=cM(iM),uM={timeout:3e4,maxBuffer:8*1024*1024};cl=null;Xf="number,title,url,headRefName,headRefOid,baseRefName,isDraft,author,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup,autoMergeRequest,additions,deletions,createdAt,updatedAt",gx=Xf.replace("statusCheckRollup,","");fM=9e4,ts=new Map;hx=(e,t)=>e.number-t.number;mM=3e4,hM=1500,ja=new Map;La=new Set(["squash","merge","rebase"]);gM=2500,yM=9e4,bM=e=>new Promise(t=>setTimeout(t,e));zf=new Map});import{execFile as EM}from"node:child_process";import{promisify as AM}from"node:util";async function IM(e,t){try{let{stdout:n}=await _M("git",["-C",e,"rev-list","--count",t]);return Number(n.trim())||0}catch{return null}}async function RM(e,t,n,{rebase:r=!1,listPrs:o=Jt}={}){let s=await $a(e.dir,{ignorePlumbing:!0}).catch(()=>!1),a=await Oa(e.dir,n).catch(()=>0),i=t?await IM(e.dir,`refs/remotes/origin/${t}..HEAD`):null,c=i==null?a>0:i>0,l=null,u="unknown";try{l=(await o(e.dir,{caller:"ship-state"})||[]).find(h=>h.headRefName===t)||null,u=l?"open":"none"}catch{}let f=s||a>0,d=[];s&&d.push("commit"),r&&d.push("rebase"),(s||c)&&d.push("push"),f&&(u!=="open"||s||c)&&d.push("pr");let p=d.filter(m=>!(m==="pr"&&u==="open"));return{name:e.name??null,slug:e.repo??null,dirty:s,unpushed:c,aheadBase:a,prState:u,openPr:l?{number:l.number,url:l.url??null,title:l.title??null}:null,available:ul.filter(m=>d.includes(m)),defaults:ul.filter(m=>p.includes(m))}}async function _x(e,{branch:t,rebase:n=!1,listPrs:r=Jt}={}){let o=e?.workspace,s=o?.kind==="multi"?(o.repos||[]).filter(d=>d?.dir):o?.base&&(o.dir||e?.cwd)?[{name:o.base?.split("/").pop()??null,dir:o.dir||e.cwd,repo:o.repo??null,baseRef:o.baseRef}]:[];if(!s.length||!await Ko(s[0].dir).catch(()=>!1))return null;let a=[];for(let d of s)a.push(await RM(d,t,d.baseRef||o.baseRef,{rebase:n,listPrs:r}));let i=a.filter(d=>d.dirty||d.aheadBase>0||d.openPr),c=i.length?i:a,l=ul.filter(d=>c.some(p=>p.available.includes(d))),u=ul.filter(d=>c.some(p=>p.defaults.includes(d))),f=c.filter(d=>d.openPr);return{available:l,defaults:u,prState:f.length?"open":c.every(d=>d.prState==="none")?"none":"unknown",openPr:c.length===1?c[0].openPr:null,repos:c.map(d=>({name:d.name,slug:d.slug,dirty:d.dirty,unpushed:d.unpushed,prState:d.prState,openPr:d.openPr}))}}var _M,ul,Ix=C(()=>{Wc();ss();_M=AM(EM),ul=["commit","rebase","push","pr"]});function dl(e,t,n){let{state:r,reason:o}=Rd(t,n);if(r!=="unknown"){if(e){let a=Date.now();for(let[i,c]of Ua)a-c.at>=Rx()&&Ua.delete(i);Ua.set(e,{busy:r==="busy",at:a})}return r==="busy"}if(o!=="narrow"||!e)return!1;let s=Ua.get(e);return s?Date.now()-s.at>=Rx()?(Ua.delete(e),!1):s.busy:!1}async function tp(e,t){let n={working:!1,prompted:!1};if(!e)return n;let r=await Te(e,{lines:je}).catch(()=>"");if(!dl(e,t,r))return ty(t,r)?{working:!0,prompted:!1}:n;if(Gr(t,r)){let o=await pn(e).catch(()=>r),s=or({name:e,agent:t},o);if(s)return!Uc({name:e,agent:t},s,o)||Yb(e)?{working:!1,prompted:!0}:{working:!1,prompted:!1}}return{working:!0,prompted:!1}}async function Qr(e,t){return(await tp(e,t)).working}var Rx,Ua,Ha=C(()=>{Ve();ga();vf();Ef();Rx=()=>Number(process.env.BOSTRAT_NARROW_CARRY_MS)||9e4,Ua=new Map});import{execFile as $M}from"node:child_process";import{promisify as OM}from"node:util";async function as(e){if(!e)return null;let t=$x.get(e);if(t&&Date.now()-t.at<MM)return t.branch;let n=null;try{let{stdout:r}=await CM("git",["-C",e,"symbolic-ref","--short","-q","HEAD"],{timeout:5e3});n=r.trim()||null}catch{n=null}return $x.set(e,{at:Date.now(),branch:n}),n}function Ox(e){return String(e||"").match(NM)?.[1]??null}function PM(e,t){let n=Ox(e);return!!n&&!!t&&n===t}function Cx(e,t){let n=Ox(e);return!!n&&n!==t}function DM(e){let t=e?.workspace;return t?.kind==="multi"?(t.repos??[]).map(n=>n?.dir).filter(Boolean):[t?.dir||e?.cwd].filter(Boolean)}async function is(e){let t=[],n=r=>{r&&!t.includes(r)&&t.push(r)};n(e?.workspace?.branch??null);for(let r of DM(e))n(await as(r));return t}async function fl(e,t,n=()=>!0){if(!t)return null;let r=(e??[]).filter(a=>a&&n(a)),o=r.find(a=>a.workspace?.branch===t);if(o)return o;let s=r.find(a=>PM(t,a.id));if(s)return s;for(let a of r)if(!(a.archivedAt||a.transferredTo)&&(await is(a)).includes(t))return a;return null}var CM,MM,$x,NM,cs=C(()=>{CM=OM($M),MM=5e3,$x=new Map;NM=/^track\/.+-([0-9a-f]{8})$/});import{execFile as BM}from"node:child_process";import{promisify as jM}from"node:util";async function np(e,t,{midTurn:n=Qr,pollMs:r=LM,capMs:o=FM}={}){let s=Date.now()+o;for(;await n(e,t).catch(()=>!1);){if(Date.now()>=s)return!1;await new Promise(a=>setTimeout(a,r))}return!0}function jx(e){let t=String(e||""),n=0;for(let r=0;r<64;r++){Mx.lastIndex=n;let o=Mx.exec(t);if(!o)break;n=o.index+o[0].length;let s=o[1]==="-",a=o[2]??o[3]??o[4],i=t.indexOf(`
150
+ `,o.index);if(i<0)break;let l=new RegExp("^"+(s?"\\t*":"")+VM(a)+"[ \\t]*$","m").exec(t.slice(i+1));if(!l)continue;let u=i+1+l.index+l[0].length;t=t.slice(0,i)+t.slice(u)}return t}function rp(e,t){return e.slice(t).replace(/^[\s;&|)]+/,"").replace(/"[^"]*"|'[^']*'/g,'""').split(/[;&|\n]/)[0]}function Fx(e){let t=jx(e),n=t.match(qM);if(!n)return null;let r=rp(t,n.index);return GM.test(r)?null:{repo:r.match(Lx)?.[1]??null,head:r.match(zM)?.[1]??null}}function Ux(e){let t=jx(e),n=t.match(KM);if(!n)return null;let r=rp(t,n.index),o=rp(t,n.index+n[0].length),s=null,a=o.trim().split(/\s+/).filter(Boolean);for(let i=0;i<a.length;i++){let c=a[i];if(c.startsWith("-")){XM.has(c)&&i++;continue}s=c.replace(/^["']+|["']+$/g,"")||null;break}return{repo:r.match(Lx)?.[1]??null,selector:s,auto:/\s--auto\b/.test(r)}}async function ZM(e,t,{exclude:n=()=>!1}={}){let r=async i=>{bn("observer");let{stdout:c}=await Nx("gh",["pr","list","--repo",e,"--author","@me","--state","all","--limit","10","--json",YM],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...i}}).catch(l=>{throw lr(l)&&ur(l),l});return JSON.parse(c||"[]")},o=i=>(i||[]).filter(c=>Date.parse(c.createdAt)>=t-UM&&!n(c)),s=await qt({slug:e}),a=o(await r(s));return!a.length&&s.GH_TOKEN&&(a=o(await r({}).catch(()=>[]))),a.sort((i,c)=>Date.parse(c.createdAt)-Date.parse(i.createdAt))}async function QM(e,t){if(t)return[t];let n=[];for(let r of Hx(e)){let o=await me(r).catch(()=>null);o&&!n.includes(o)&&n.push(o)}for(let r of await un().catch(()=>[])){let o=await me(r.path).catch(()=>null);o&&!n.includes(o)&&n.push(o)}return n}function Hx(e){let t=e.workspace;return t?.kind==="multi"?(t.repos??[]).map(n=>n?.base).filter(Boolean):[t?.base||e.cwd].filter(Boolean)}async function eN(e,t,n){let r=await is(e).catch(()=>[e.workspace?.branch].filter(Boolean)),o=t?.head??null,s=c=>r.includes(c)||o&&c===o,a=c=>o!=null&&!s(c.headRefName)||JM(c.headRefName,e.id),i=[];for(let c of await QM(e,t?.repo??null)){let l;try{l=await ZM(c,n,{exclude:a})}catch{continue}for(let u of l){let f=await qe(c,u.number);if(s(u.headRefName)){if(f&&f.trackId===e.id&&f.announced)return{settled:!0};if(f&&f.trackId!==e.id)continue;return{slug:c,pr:u}}f&&(f.trackId!==e.id||f.announced)||i.push({slug:c,pr:u})}}return i.length?(i.sort((c,l)=>Date.parse(l.pr.createdAt)-Date.parse(c.pr.createdAt)),i[0]):null}function Wx(e,t,{delays:n=Px,turnEnd:r}={}){let o=Fx(t.command);if(!o)return null;let s=!!Ux(t.command),a=`${e.id}|${t.id??t.ts??t.command}`;if(dr.has(a))return null;dr.add(a);let i=t.ts??Date.now(),c=(async()=>{try{for(let l of n){await new Promise(h=>setTimeout(h,l));let u=await eN(e,o,i).catch(()=>null);if(u?.settled)return null;if(!u)continue;let{slug:f,pr:d}=u,{link:p,created:m}=await mt({repo:f,number:d.number,trackId:e.id,url:d.url,headRef:d.headRefName,title:d.title,source:"observed"});return!m&&!(p?.trackId===e.id&&await wn(f,d.number))?null:(await np(t.box,t.agent,r),await _({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Date.now(),change:"opened",number:d.number,url:d.url,title:d.title,branch:d.headRefName,repo:f,...s?{selfMerge:!0}:{}}}),d)}return null}finally{dr.delete(a)}})();return c.catch(()=>dr.delete(a)),c}function qx(e,t,{delays:n=Px,turnEnd:r,openedWait:o}={}){let s=Ux(t.command);if(!s)return null;let a=`merge|${e.id}|${t.id??t.ts??t.command}`;if(dr.has(a))return null;dr.add(a);let i=(async()=>{try{let c=s.repo,l=s.selector,u=l?.match(/github\.com\/([\w.-]+\/[\w.-]+)\/pull\/(\d+)/);u&&([,c,l]=u);let f=[];if(c)f=[c];else{let m=Hx(e);if(m.length>1&&/^\d+$/.test(String(s.selector??"")))return null;for(let h of m){let g=await me(h).catch(()=>null);g&&!f.includes(g)&&f.push(g)}}if(l||=(await is(e).catch(()=>[])).filter(m=>m!==e.workspace?.branch)[0]||e.workspace?.branch,!f.length||!l)return null;c=f[0];let d=async(m,h)=>{let g=await qe(c,m.number);return g&&g.trackId!==e.id?null:(g||await mt({repo:c,number:m.number,trackId:e.id,url:m.url,headRef:m.headRefName,title:m.title,source:"merge-observed"}),await Na(c,m.number),h&&((await L(e).catch(()=>[])).some(E=>E.type==="pr.state.changed"&&(E.payload?.change==="auto-armed"||E.payload?.change==="merged")&&E.payload?.number===m.number)||(await np(t.box,t.agent,r),await _({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Date.now(),change:"auto-armed",number:m.number,url:m.url,title:m.title,branch:m.headRefName,repo:c}}))),m)},p=null;for(let m of n){await new Promise(N=>setTimeout(N,m));let h=[];for(let N of f)try{bn("observer");let{stdout:O}=await Nx("gh",["pr","view",String(l),"--repo",N,"--json",tN],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...await qt({slug:N})}}),T=JSON.parse(O||"null");T?.number&&h.push({slug:N,pr:T})}catch(O){lr(O)&&ur(O)}let g=h.find(N=>N.pr.state==="MERGED")??(h.length===1?h[0]:null);if(!g)continue;c=g.slug;let x=g.pr;if(!x?.number)continue;if(x.state==="CLOSED")return null;if(x.state!=="MERGED"){if(p=x,s.auto)return d(x,!0);continue}let k=await qe(c,x.number);if(k&&k.trackId!==e.id)return null;k||await mt({repo:c,number:x.number,trackId:e.id,url:x.url,headRef:x.headRefName,title:x.title,source:"merge-observed"}),await np(t.box,t.agent,r);let E=await L(e).catch(()=>[]);if(E.some(N=>N.type==="pr.state.changed"&&N.payload?.change==="merged"&&N.payload?.number===x.number))return null;let I=N=>N.some(O=>O.type==="pr.state.changed"&&O.payload?.change==="opened"&&O.payload?.number===x.number),M=0;if(!I(E)){if(Fx(t.command)&&await wn(c,x.number)){let N=Date.now();M=N+1,await _({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:N,change:"opened",number:x.number,url:x.url,title:x.title,branch:x.headRefName,repo:c,selfMerge:!0}})}else if((await qe(c,x.number))?.announced){let N=o?.capMs??HM,O=o?.pollMs??WM,T=Date.now()+N;for(;Date.now()<T&&(await new Promise(j=>setTimeout(j,O)),!I(await L(e).catch(()=>[]))););}}return await _({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Math.max(Date.now(),M),change:"merged",number:x.number,url:x.url,title:x.title,branch:x.headRefName,repo:c}}),await Sn(c,x.number).catch(()=>{}),await xn(c,x.number).catch(()=>{}),await ir(c,x.number,"merged"),x}return p?d(p,!1):null}finally{dr.delete(a)}})();return i.catch(()=>dr.delete(a)),i}var Nx,Px,LM,FM,UM,HM,WM,Dx,Bx,qM,KM,GM,Mx,VM,Lx,zM,JM,XM,YM,dr,tN,Kx=C(()=>{ue();Hn();et();Ba();gn();fr();Ha();cs();Nx=jM(BM),Px=[4e3,15e3,45e3],LM=2500,FM=5*6e4;UM=15e3,HM=9e4,WM=2e3,Dx=/(?:^|[;&|\n({`]\s*|\)\s*)(?:(?:then|do|else|elif|if|while|until|time)\s+)?/.source,Bx=/gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+/.source,qM=new RegExp(`${Dx}${Bx}create\\b`),KM=new RegExp(`${Dx}${Bx}merge\\b`),GM=/\s--web\b/,Mx=/<<(-?)\s*(?:'([^'\n]+)'|"([^"\n]+)"|\\?([A-Za-z_][\w-]*))/g,VM=e=>e.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");Lx=/(?:--repo|-R)[\s=]+([\w.-]+\/[\w.-]+)/,zM=/(?:--head|-H)[\s=]+([^\s"'`;&|]+)/,JM=Cx;XM=new Set(["--subject","-t","--body","-b","--body-file","-F","--match-head-commit","--author-email","-A","--repo","-R"]);YM="number,url,title,headRefName,createdAt";dr=new Set;tN="number,url,title,headRefName,state"});import nN from"node:fs/promises";import sp from"node:path";import rN from"node:os";function op(e,t){let n=new RegExp(`\\b${t}="([^"]*)"`).exec(e);return n?n[1]:null}function pl(e){let t=oN.exec(String(e||""));if(!t)return null;let[,n,r]=t,o=op(n,"from"),s=o?o.replace(/^uds:/,""):null,a=Gx(s);return{socket:s,pid:a,name:op(n,"from-name"),mode:op(n,"from-mode"),text:r.trim()}}function Gx(e){let t=/(\d+)\.sock$/.exec(String(e||""));return t?Number(t[1]):null}function sN(){return process.env.CLAUDE_CONFIG_DIR?sp.join(process.env.CLAUDE_CONFIG_DIR,"sessions"):sp.join(rN.homedir(),".claude","sessions")}async function aN(e){let t=Gx(e);if(!t)return null;try{let n=await nN.readFile(sp.join(sN(),`${t}.json`),"utf8"),r=JSON.parse(n);return{pid:t,sessionId:r.sessionId??null,cwd:r.cwd??null,name:r.name??null,tmux:r.tmux??null}}catch{return null}}async function Vx(e,t){let n=await aN(e?.socket),r=n?.cwd??null,o=null;if((n?.sessionId||r)&&typeof t=="function")try{o=await t(n?.sessionId??null,r)??null}catch{o=null}return{socket:e?.socket??null,pid:n?.pid??e?.pid??null,sessionId:n?.sessionId??null,cwd:r,tmux:n?.tmux??null,name:n?.name??e?.name??null,mode:e?.mode??null,trackId:o?.track?.id??null,trackName:o?.track?.name??null,boxId:o?.box?.name??null}}var oN,ap=C(()=>{oN=/<cross-session-message\b([^>]*)>([\s\S]*?)<\/cross-session-message>/});function ip(e=process.env){return!!(ke(e)&&e.BOSTRAT_PLANE_TOKEN)}async function cp({loopId:e,outcome:t,note:n=null,env:r=process.env}={}){if(!ip(r))return{ok:!1,source:"unconfigured"};let o=new AbortController,s=setTimeout(()=>o.abort(),zx);try{let a=await Jx(`${ke(r)}/v1/loops/${encodeURIComponent(e)}/report`,{method:"POST",headers:{authorization:`Bearer ${r.BOSTRAT_PLANE_TOKEN||""}`,"content-type":"application/json"},body:JSON.stringify({outcome:t,...n?{note:n}:{}}),signal:o.signal}),i=await a.json().catch(()=>({}));return a.ok?{ok:!0,source:"plane",status:a.status,run:i?.run||null}:{ok:!1,source:"plane",status:a.status,error:i?.error||`plane ${a.status}`}}catch(a){return{ok:!1,source:"unreachable",error:a?.message||String(a)}}finally{clearTimeout(s)}}async function Xx(e,{provider:t=null,cls:n="other",status:r=null,text:o=""}={},{env:s=process.env,now:a=Date.now}={}){if(!e?.id||!String(e.name||"").startsWith("\u21BB"))return{ok:!1,source:"not-a-loop-track"};if(!ip(s))return{ok:!1,source:"unconfigured"};let i=ml.get(e.id)||0;if(a()-i<iN)return{ok:!1,source:"debounced"};ml.set(e.id,a());let c=await hl({env:s}),l=c.loops.find(d=>d.trackId===e.id);if(!l)return ml.delete(e.id),{ok:!1,source:c.source==="plane"?"no-loop":c.source};let u=`${t||"provider"} ${r?r+" ":""}${n}: ${String(o||"").replace(/\s+/g," ").trim()}`.slice(0,500),f=await cp({loopId:l.id,outcome:"errored",note:u,env:s});return f.ok||ml.delete(e.id),{...f,loop:{id:l.id,name:l.name}}}async function hl({env:e=process.env}={}){if(!ip(e))return{loops:[],source:"unconfigured"};let t=new AbortController,n=setTimeout(()=>t.abort(),zx);try{let r=await Jx(`${ke(e)}/v1/loops`,{headers:{authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`},signal:t.signal});if(!r.ok)throw new Error(`plane ${r.status}`);let o=await r.json();return{loops:Array.isArray(o?.loops)?o.loops:[],source:"plane"}}catch(r){return{loops:[],source:"unreachable",error:r?.message||String(r)}}finally{clearTimeout(n)}}var zx,Jx,iN,ml,lp=C(()=>{et();zx=1e4,Jx=(...e)=>fetch(...e);iN=10*6e4,ml=new Map});import{randomUUID as cN}from"node:crypto";function Wa(e){return e.sourceId?`${e.role}|id:${e.sourceId}`:`${e.role}|${e.ts??"?"}|${String(e.text||"").slice(0,40)}`}function Yx(e){return e.id?`cmd|${e.box}|id:${e.id}`:`cmd|${e.box}|${e.ts??"?"}|${String(e.command||"").slice(0,40)}`}function Zx(e){return`job|${e.box}|id:${e.id}`}async function dp(e){return up.has(e.id)?up.get(e.id):(wl.has(e.id)||wl.set(e.id,L(e).then(t=>{let n={keys:new Set,cmdN:0};for(let r of t)if((r.type==="turn.user"||r.type==="turn.agent"||r.type==="provider.error")&&r.payload?.text!=null){let o=r.type==="turn.user"?"user":"assistant";r.payload.sourceId&&n.keys.add(Wa({role:o,sourceId:r.payload.sourceId})),n.keys.add(Wa({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(Wa({role:"user",sourceId:r.payload.sourceId})),n.keys.add(Wa({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(Yx({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(Zx({id:r.payload.id,box:r.boxId}));return up.set(e.id,n),n}).finally(()=>wl.delete(e.id))),wl.get(e.id))}async function Qx(e,t){let n=new Set;try{let r=(await dp(e)).keys;for(let o of t||[]){if(!o||o.ts==null||!String(o.text||"").trim()&&!o.images?.length)continue;let s=Wa(o);if(r.has(s))continue;r.add(s);let a=o.role==="user"?pl(o.text):null;if(a){await _(e,{type:"peer.message",actor:"peer",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{text:a.text,ts:o.ts,keyText:String(o.text||"").slice(0,40),from:await Vx(a,qa),boxRole:o.boxRole,sourceId:o.sourceId||void 0}});continue}let i=Dg(o);if(i){await _(e,{type:"provider.error",actor:"system",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{cls:i.cls,code:i.code||void 0,status:i.status||void 0,requestId:i.requestId||void 0,text:o.text,ts:o.ts,model:o.model||null,boxRole:o.boxRole,sourceId:o.sourceId||void 0}}),Xx(e,{provider:o.agent||null,cls:i.cls,status:i.status,text:o.text}).catch(()=>{});continue}if(o.role!=="user"&&o.box&&n.add(o.box),await _(e,{type:o.role==="user"?"turn.user":"turn.agent",actor:o.role==="user"?"user":"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{text:o.text,ts:o.ts,model:o.model||null,tools:o.tools||void 0,boxRole:o.boxRole,sourceId:o.sourceId||void 0,note:o.note||void 0,images:o.images?.length?o.images:void 0}}),o.role==="assistant"&&o.box===e.leadBox&&e.workspace?.branch){let c=Dk(o.text);if(c){let l=Lk(c),u;if(e.workspace?.kind==="multi"){let m=await ls(e).catch(()=>[]);u=m.length?m.map(h=>({name:h.name,slug:h.repo??null})):void 0}let f=(e.workspace?.kind==="multi"?null:await as(e.cwd).catch(()=>null))||e.workspace.branch,d=await _x(e,{branch:f,rebase:l}).catch(()=>null),p=d?null:jk(c);if(d&&d.available.length===0)continue;await _(e,{type:"pr.offered",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{offerId:cN(),ts:o.ts,excerpt:c,branch:f,base:e.workspace.baseRef?.replace(/^origin\//,"")||null,boxRole:o.boxRole,available:d?.available,defaults:d?.defaults,prState:d?.prState,openPr:d?.openPr||void 0,repos:d?.repos||u,offered:d?.defaults||p?.offered||void 0,toPr:p?.toPr||void 0}})}}}}catch{}return{agentTurnBoxes:n}}async function e0(e,t){try{let n=await dp(e),r=[...t||[]].filter(o=>o&&String(o.command||"").trim()).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=Yx(o);n.keys.has(s)||(n.keys.add(s),n.cmdN+=1,await _(e,{type:"tool.called",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{id:o.id??null,tool:o.tool||null,command:o.command,description:o.description||"",summary:o.summary||o.command,ts:o.ts??null,boxRole:o.boxRole,n:n.cmdN}}),Wx(e,o),qx(e,o))}}catch{}}async function t0(e,t){try{let n=await dp(e),r=[...t||[]].filter(o=>o&&o.id).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=Zx(o);n.keys.has(s)||(n.keys.add(s),await _(e,{type:"job.started",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{id:o.id,kind:o.kind||"agent",name:o.name||null,detail:o.detail||null,ts:o.ts??null,boxRole:o.boxRole}}))}}catch{}}var up,wl,n0=C(()=>{ue();Qo();Ix();Kx();cs();ap();fr();xc();lp();up=new Map,wl=new Map});function lN(e){let t=[],n=null;for(let r of String(e||"").split(`
151
+ `)){let o=r.trim();if(!o||o[0]!=="{")continue;let s;try{s=JSON.parse(o)}catch{continue}let a=s.payload||{};if(s.type==="turn_context"&&a.model&&(n=a.model),s.type==="event_msg"&&a.type==="token_count"&&a.info?.last_token_usage){let i=a.info.last_token_usage;t.push({ts:s.timestamp?Date.parse(s.timestamp):null,model:n,last:{input:i.input_tokens||0,cachedInput:i.cached_input_tokens||0,output:i.output_tokens||0,reasoningOutput:i.reasoning_output_tokens||0},occupancy:i.total_tokens??null,contextWindow:a.info.model_context_window??null})}}return t}async function uN(e,t){let n=`${e.id}:${t.name}`;if(!fp.has(n)){let r=await L(e),o=new Set;for(let s of r)s.type==="cost.recorded"&&s.boxId===t.name&&s.payload?.codexTs!=null&&o.add(s.payload.codexTs);fp.set(n,o)}return fp.get(n)}async function r0(e,t){try{if(t?.agent!=="codex"||!t.cwd)return;let n=await Nr(t.cwd,t.pinned?t.sessionId:null);if(!n)return;let r=await uN(e,t),o=lN(await it(n.file,262144)),s=o[o.length-1];for(let a of o){if(a.ts==null||r.has(a.ts))continue;r.add(a.ts);let i={input:Math.max(0,a.last.input-a.last.cachedInput),output:a.last.output,cacheRead:a.last.cachedInput,cacheWrite:0},c=a.model||t.model||"gpt-5.5";await _(e,{type:"cost.recorded",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{usd:tr(c,i),model:c,tokens:i,reasoningOutput:a.last.reasoningOutput||void 0,codexTs:a.ts,ts:a.ts}}),a===s&&a.contextWindow&&await _(e,{type:"context.usage",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{occupancy:a.occupancy,window:a.contextWindow,pct:a.occupancy!=null?a.occupancy/a.contextWindow:null,model:a.model||null,ts:a.ts}})}}catch{}}var fp,o0=C(()=>{ue();Dr();Nt();Aa();fp=new Map});import gl from"node:fs";import mp from"node:path";import dN from"node:os";async function mN({sinceMs:e,cookie:t,fetchImpl:n=fetch}){let r=[];for(let o=1;o<=20;o++){let s=await n(pN,{method:"POST",headers:{"content-type":"application/json",origin:"https://cursor.com",cookie:`WorkosCursorSessionToken=${t}`},body:JSON.stringify({teamId:0,startDate:String(e),endDate:String(Date.now()),page:o,pageSize:s0})});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<s0)break}return r}function hN(e){if(!e)return null;let t=Number(e.timestamp)||null,n=e.tokenUsage||null,r=n?{input:n.inputTokens||0,output:n.outputTokens||0,cacheRead:n.cacheReadTokens||0,cacheWrite:n.cacheWriteTokens||0}:null,o=e.conversationId||null;return{id:[o||"?",t??"?",r?`${r.input}.${r.output}.${r.cacheRead}.${r.cacheWrite}`:"?"].join(":"),conversationId:o,ts:t,model:e.model||e.modelIntent||null,kind:e.kindLabel||e.kind||null,isHeadless:e.isHeadless===!0,tokens:r,vendorCents:n?.totalCents??null,chargedCents:e.chargedCents??null}}function i0(){try{return JSON.parse(gl.readFileSync(yl(),"utf8"))}catch{return{sinceMs:0,seen:[]}}}function gN(e){try{gl.mkdirSync(mp.dirname(yl()),{recursive:!0});let t=yl()+".tmp";gl.writeFileSync(t,JSON.stringify(e)),gl.renameSync(t,yl())}catch{}}async function bN({fetchImpl:e,now:t=Date.now()}={}){if(pr.rows&&t-pr.at<wN)return pr.rows;let n=process.env.BOSTRAT_CURSOR_USAGE_COOKIE;if(!n)return null;let r=i0(),o=Math.max(r.sinceMs-6e4,t-24*36e5);try{let s=await mN({sinceMs:o,cookie:n,fetchImpl:e});pr={at:t,rows:s.map(hN).filter(Boolean),error:null}}catch(s){pr={at:t,rows:null,error:String(s?.message||s)}}return pr.rows}async function kN(e,t){let n=`${e.id}:${t.name}`;if(!pp.has(n)){let r=await L(e),o=new Set;for(let s of r)s.type==="cost.recorded"&&s.boxId===t.name&&s.payload?.cursorEventId&&o.add(s.payload.cursorEventId);pp.set(n,o)}return pp.get(n)}async function c0(e,t,{fetchImpl:n}={}){try{if(t?.agent!=="cursor"||!t.cwd||!a0())return;let r=await bN({fetchImpl:n});if(!r||!r.length)return;let o=await Rb(t.cwd,t.pinned?t.sessionId:null);if(!o?.chatId)return;let s=await kN(e,t),a=i0(),i=new Set(a.seen||[]),c=a.sinceMs||0;for(let l of r){if(!l.conversationId||l.conversationId!==o.chatId||s.has(l.id)||i.has(`${e.id}:${t.name}:${l.id}`))continue;s.add(l.id),i.add(`${e.id}:${t.name}:${l.id}`),l.ts&&l.ts>c&&(c=l.ts);let u=l.model||o.models[o.models.length-1]||"cursor-unknown",f=l.tokens||null,d=l.vendorCents!=null?l.vendorCents/100:0;!d&&f&&(d=tr(u,f)),!d&&l.chargedCents!=null&&(d=l.chargedCents/100),await _(e,{type:"cost.recorded",actor:"agent",source:"vendor",boxId:t.name,provider:"cursor",payload:{usd:d,model:u,...f?{tokens:f}:{},...l.vendorCents!=null?{vendorCents:l.vendorCents}:{},...l.chargedCents!=null?{chargedCents:l.chargedCents}:{},...l.kind?{kind:l.kind}:{},conversationId:l.conversationId,cursorEventId:l.id,ts:l.ts??void 0}})}gN({sinceMs:c,seen:[...i].slice(-yN)})}catch{}}var fN,a0,pN,s0,wN,pr,yl,yN,hp,pp,wp=C(()=>{ue();lf();Aa();fN=process.env.BOSTRAT_STATE_DIR||mp.join(process.env.HOME||dN.tmpdir(),".bostrat"),a0=(e=process.env)=>!!e.BOSTRAT_CURSOR_USAGE_COOKIE,pN="https://cursor.com/api/dashboard/get-filtered-usage-events",s0=100;wN=5*6e4,pr={at:0,rows:null,error:null},yl=()=>mp.join(fN,"cursor-usage.json");yN=5e3;hp=()=>({enabled:a0(),lastPollAt:pr.at||null,error:pr.error}),pp=new Map});import Va from"node:fs/promises";import lt from"node:path";import xN from"node:os";import SN from"node:net";import{randomUUID as vN}from"node:crypto";import{execFile as TN}from"node:child_process";import{promisify as EN}from"node:util";function CN(e){for(let t of vp(e))if(!m0.test(t))return t;return null}function h0(e){let t=vp(e),n=t.indexOf("--");return n===-1?t:t.slice(0,n)}function MN(e,t){let n=h0(t);for(let r=0;r<n.length;r++){let o=/^--prefix=(.+)$/.exec(n[r]);if(o)return lt.resolve(e,o[1]);if(n[r]==="--prefix"&&n[r+1])return lt.resolve(e,n[r+1])}return e}function PN(e){let t=!1,n=!1;for(let r of vp(e)){if(!t){if(m0.test(r))continue;t=!0;continue}if(r.startsWith("-")){let o=r.indexOf("="),s=o===-1?null:r.slice(o+1);if(s&&gp(s))return`serves the filesystem root ("${s}")`;n=o===-1;continue}if(n){if(n=!1,gp(r))return`serves the filesystem root ("${r}")`;continue}if(gp(r))return`serves the filesystem root ("${r}")`;if(NN(r))return`serves a path that escapes the workspace ("${r}")`}return null}async function BN(e,t){if(lt.resolve(e)===lt.resolve(t))return!0;let[n,r]=await Promise.all([bl(e),bl(t)]);return n===r}async function jN(e){let n=(await Va.readdir(e,{withFileTypes:!0}).catch(()=>[])).filter(o=>o.isDirectory()&&!o.name.startsWith(".")&&o.name!=="node_modules");return(await Promise.all(n.map(async o=>await w0(lt.join(e,o.name,kp))?`./${o.name}`:null))).filter(Boolean)}async function LN(e,t){let[n,r]=await Promise.all([bl(e),bl(t)]),o=lt.relative(n,r);if(o&&(o.startsWith("..")||lt.isAbsolute(o)))throw Ka(`serve directory escapes the Track workspace: ${t}`)}async function FN(e,t){let n=PN(t);if(n)throw Ka(`refusing this view: the command ${n} \u2014 serve a build dir, not the filesystem root`);if(!await DN(e))throw Ka(`serve directory does not exist: ${e}`);let r=CN(t);if(!r)return;if(!r.includes("/")&&!await ug(r,{loginShell:!0,failOpen:!0}))throw Ka(`\`${r}\` is not on the box's PATH \u2014 install it in the box first`);if(RN.test(t)||$N.has(r)||!IN.has(r)||!h0(t).includes("run")||ON.test(t))return;let o=MN(e,t);if(await w0(lt.join(o,kp)))return;let s=await jN(o),a=s.length?` \u2014 found one in ${s.join(", ")}; run bostrat-view from there`:"";throw Ka(`no ${kp} in ${o}${a}`)}async function En(){return Zt||(yp||=(async()=>{try{Zt=JSON.parse(await Va.readFile(p0,"utf8"))}catch{Zt={views:[],adoptWatermarks:{}}}finally{yp=null}return Zt.views||=[],Zt.adoptWatermarks||={},Zt})(),yp)}async function en(){await at(p0,Zt)}function Tn(e,t,n={}){return _({id:e.trackId,cwd:e.cwd},{type:"view.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,payload:{ts:Date.now(),change:t,viewId:e.id,name:e.name,slug:e.slug,port:e.port,cmd:e.cmd||null,...n}}).catch(()=>{})}function Ep(e){return Ga.get(e)||null}function y0(e,{name:t,box:n}={}){let r=Ga.get(e);if(r&&!r.finishedAt)throw new Error("a view is already being spun up for this Track");let o={trackId:e,name:t||"preview",box:n||null,step:"spinning-up",startedAt:Date.now(),finishedAt:null,viewId:null,error:null};return Ga.set(e,o),o}function xp(e,t){let n=Ga.get(e);n&&!n.finishedAt&&!n.viewId&&(n.viewId=t,n.step="booting")}function kl(e,{error:t=null}={}){let n=Ga.get(e);return!n||n.finishedAt?null:(n.finishedAt=Date.now(),t&&(n.error=t),n)}function b0(e){let t=[];for(let n of e?.events||[])n.type!=="view-spinup"||!n.box||!n.startedAt||!n.endedAt||t.push({box:n.box,from:n.startedAt,to:n.endedAt});return t}function Sp(e){return String(e||"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40).replace(/-+$/g,"")||"view"}function UN(e,t){let n=Sp(t),r=new Set(e.views.map(o=>o.slug));if(!r.has(n)&&!d0.has(n))return n;for(let o=2;;o++){let s=`${n}-${o}`;if(!r.has(s)&&!d0.has(s))return s}}function za(e,{timeoutMs:t=1200}={}){return new Promise(n=>{let r=SN.connect({port:e,host:"127.0.0.1"}),o=s=>{r.destroy(),n(s)};r.setTimeout(t,()=>o(!1)),r.once("connect",()=>o(!0)),r.once("error",()=>o(!1))})}async function Ap(e){if(process.platform!=="darwin"){await Qt("fuser",["-k",`${e}/tcp`]).catch(()=>{});return}let t="";try{({stdout:t}=await Qt("lsof",["-t","-sTCP:LISTEN","-i",`tcp:${e}`]))}catch{return}for(let n of t.split(/\s+/).filter(Boolean)){let r=Number(n);if(!(!r||r===process.pid))try{process.kill(r,"SIGKILL")}catch{}}}function k0(e=process.env){return new Set([Number(e.PORT)||3362,Number(e.BOSTRAT_TLS_PORT)||3443])}async function HN(e,t){let n=new Set(e.views.map(o=>o.port)),r=k0();if(t){let o=Number(t);if(!Number.isInteger(o)||o<1024||o>65535)throw new Error("invalid port");if(r.has(o))throw new Error(`port ${o} is the node's own API port`);if(n.has(o))throw new Error(`port ${o} is already owned by a view`);return o}for(let o=l0;o<=u0;o++)if(!(n.has(o)||r.has(o))&&!await za(o,{timeoutMs:250}))return o;throw new Error(`no free view port in ${l0}-${u0}`)}async function WN(e){try{let{stdout:t}=await Qt(F,H("list-sessions","-F","#{session_name}"));return t.split(`
152
+ `).some(n=>n.trim()===us(e))}catch{return!1}}async function Ja(e){try{await Qt(F,H("kill-session","-t",us(e)))}catch{}}async function _p(e){if(!await ia())throw new Error("host tmux server not running and auto-start failed \u2014 cannot spawn a view server");let t=us(e.slug),n=e.serveCwd??e.cwd,r=lt.dirname(process.execPath);await Qt(F,H("new-session","-d","-s",t,"-c",n)),await Qt(F,H("send-keys","-t",t,"-l",`export PORT=${e.port} PATH="${r}:$PATH"`)),await Qt(F,H("send-keys","-t",t,"Enter")),await Qt(F,H("send-keys","-t",t,"-l",e.cmd)),await Qt(F,H("send-keys","-t",t,"Enter"))}async function f0(e,t=12){try{let{stdout:n}=await Qt(F,H("capture-pane","-t",us(e),"-p"));return String(n||"").trimEnd().split(`
150
153
  `).filter(Boolean).slice(-t).join(`
151
- `)}catch{return""}}async function IN(e){if(e.state==="stopped"||e.state==="error")return!1;let t=e.origin!=="detected",n=t?await AN(e.slug):!0;if(t&&!n){let s=e.state==="starting";return e.state=s?"error":"stopped",s&&(e.error=await sx(e.slug)||"server exited before listening"),Sn.delete(e.id),await vn(e,e.state,e.error?{error:e.error}:{}),!0}if(await Wa(e.port))return Sn.delete(e.id),e.lastHealthyAt=Date.now(),e.state!=="live"?(e.state="live",e.error=null,await vn(e,"live"),!0):!1;if(e.state==="starting")return Date.now()-e.createdAt>_N?(e.state="error",e.error=await sx(e.slug)||"never started listening",await vn(e,"error",{error:e.error}),!0):!1;let o=(Sn.get(e.id)||0)+1;return Sn.set(e.id,o),o>=3&&e.state==="live"?(e.state="unhealthy",!0):!1}async function gl(){if(!pp){pp=!0;try{let e=await Tn(),t=!1;for(let n of e.views)await IN(n)&&(t=!0);t&&await Zt()}finally{pp=!1}}}async function yl({trackId:e}={}){await gl();let t=await Tn();return(e?t.views.filter(r=>r.trackId===e):t.views).map(r=>({...r}))}async function mx(e){let n=(await Tn()).views.find(r=>r.id===e);return n?{...n}:null}function Sp(e){return Yt&&Yt.views.find(t=>t.slug===e)||null}async function vp({trackId:e,name:t,cmd:n,cwd:r,serveCwd:o,port:s,box:a,origin:i="agent",branch:c=null}){if(!e)throw new Error("trackId required");if(typeof t!="string"||!t.trim())throw new Error("name (string) required");if(i!=="detected"&&(typeof n!="string"||!n.trim()))throw new Error("cmd (string) required");if(!r)throw new Error("cwd required");let l=o!=null,u=lt.resolve(r,o??"."),f=i==="detected"?null:async()=>{await SN(r,u),await vN(u,n)},d=await Tn();if(i!=="detected"){let h=wp(t),g=String(n).trim(),x=d.views.find(k=>k.trackId===e&&(k.slug===h||wp(k.name)===h||k.cmd===g&&lt.resolve(k.serveCwd??k.cwd)===u));if(x)return RN(d,x,{cmd:g,box:a,branch:c,serveCwd:l?u:void 0,validate:f})}if(f&&await f(),d.views.filter(h=>h.state==="live"||h.state==="starting").length>=mr)throw new Error(`view cap reached (${mr} live) \u2014 stop one first`);let m={id:aN().slice(0,8),trackId:e,box:a||null,name:t.trim(),slug:TN(d,t),cmd:n?String(n).trim():null,cwd:r,serveCwd:u,branch:c,port:await EN(d,s),origin:i,state:"starting",error:null,createdAt:Date.now(),lastHealthyAt:null};return i!=="detected"&&await xp(m),d.views.push(m),await Zt(),await vn(m,"created",{origin:i}),hp(e,m.id),i==="detected"&&await Wa(m.port)&&(m.state="live",m.lastHealthyAt=Date.now(),await Zt(),await vn(m,"live")),{...m}}async function RN(e,t,{cmd:n,box:r,branch:o,serveCwd:s,validate:a}){r&&(t.box=r),o&&(t.branch=o);let i=t.cmd!==n,c=s!==void 0&&!await kN(t.serveCwd??t.cwd,s);if((t.state==="live"||t.state==="starting")&&!i&&!c&&await Wa(t.port))return await Zt(),hp(t.trackId,t.id),{...t,reused:!0};if(a&&await a(),e.views.filter(f=>f.id!==t.id&&(f.state==="live"||f.state==="starting")).length>=mr)throw new Error(`view cap reached (${mr} live) \u2014 stop one first`);return t.origin==="detected"?(await kp(t.port),t.origin="agent"):await qa(t.slug),t.cmd=n,s!==void 0&&(t.serveCwd=s),t.state="starting",t.error=null,t.createdAt=Date.now(),Sn.delete(t.id),await xp(t),await Zt(),await vn(t,"created",{restarted:!0,reused:!0}),hp(t.trackId,t.id),{...t,reused:!0}}async function hx(e){let n=(await Tn()).views.find(r=>r.id===e);if(!n)throw new Error("view not found");return n.origin==="detected"?await kp(n.port):await qa(n.slug),n.state!=="stopped"&&(n.state="stopped",Sn.delete(n.id),await Zt(),await vn(n,"stopped")),{...n}}async function wx(e){let t=await Tn(),n=t.views.find(o=>o.id===e);if(!n)throw new Error("view not found");if(!n.cmd)throw new Error("a detected view has no known command \u2014 recreate it as a managed view");if(t.views.filter(o=>o.id!==e&&(o.state==="live"||o.state==="starting")).length>=mr)throw new Error(`view cap reached (${mr} live) \u2014 stop one first`);return await qa(n.slug),n.state="starting",n.error=null,n.createdAt=Date.now(),Sn.delete(n.id),await xp(n),await Zt(),await vn(n,"created",{restarted:!0}),{...n}}async function gx(e){let t=await Tn(),n=t.views.findIndex(o=>o.id===e);if(n===-1)throw new Error("view not found");let r=t.views[n];return r.origin==="detected"?await kp(r.port):await qa(r.slug),t.views.splice(n,1),Sn.delete(r.id),await Zt(),await vn(r,"deleted"),{ok:!0,id:e,slug:r.slug}}async function yx(e){let t=await Tn(),n=t.views.filter(r=>r.trackId===e);for(let r of n)r.origin!=="detected"&&await qa(r.slug),Sn.delete(r.id);return n.length&&(t.views=t.views.filter(r=>r.trackId!==e),await Zt()),n.length}async function bx(e,t){if(!e?.id||!Array.isArray(t)||!t.length)return[];let n=await Tn(),r=n.adoptWatermarks[e.id]??null,o=t.filter(c=>c.role==="assistant"&&c.ts!=null&&(r==null?!1:c.ts>r)),s=t.reduce((c,l)=>l.ts>c?l.ts:c,r??0);if(n.adoptWatermarks[e.id]!==s&&(n.adoptWatermarks[e.id]=s,await Zt()),!o.length)return[];let a=new Set;for(let c of o)for(let l of String(c.text||"").matchAll($N)){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(!px().has(c)&&!n.views.some(l=>l.port===c)&&await Wa(c))try{i.push(await vp({trackId:e.id,name:`${e.name} preview`,cmd:null,cwd:e.cwd,port:c,origin:"detected",branch:e.workspace?.branch??null}))}catch{}return i}var Xt,lN,ax,nx,rx,mr,uN,is,ox,Fa,dN,mp,fN,pN,mN,gp,ix,dp,gN,bN,lx,hl,Yt,fp,Ua,yp,ux,Sn,_N,pp,$N,bl=O(()=>{tt();ue();Wn();Xt=cN(iN),lN=process.env.BOSTRAT_STATE_DIR||lt.join(process.env.HOME||oN.tmpdir(),".bostrat"),ax=lt.join(lN,"views.json"),[nx,rx]=(process.env.BOSTRAT_VIEW_PORTS||"4300-4349").split("-").map(e=>Number(e)||0),mr=Number(process.env.BOSTRAT_VIEW_MAX)||3,uN="bostrat-view-",is=e=>`${uN}${e}`,ox=new Set(["bostrat","www","api","views","app"]),Fa=e=>Object.assign(new Error(e),{status:400}),dN=new Set(["npm","pnpm","yarn","bun"]),mp="package.json",fN=/[|;&`]|\$\(/,pN=new Set(["sh","bash","zsh","dash","env","exec","nohup","time"]),mN=/(^|\s)(-C|--cwd|--manifest-path|--dir)(=|\s)/,gp=e=>String(e).trim().split(/\s+/).filter(Boolean),ix=/^[A-Za-z_][A-Za-z0-9_]*=/;dp=e=>e==="/",gN=e=>e===".."||e.startsWith("../")||e.includes("/../")||e.endsWith("/..");bN=e=>Ha.stat(e).then(t=>t.isDirectory(),()=>!1),lx=e=>Ha.stat(e).then(t=>t.isFile(),()=>!1),hl=e=>Ha.realpath(e).catch(()=>lt.resolve(e));Yt=null,fp=null;Ua=new Map,yp=Number(process.env.BOSTRAT_VIEW_JOB_TIMEOUT)||3e5,ux=12e3;Sn=new Map,_N=12e4;pp=!1;$N=/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::(\d{2,5}))?(?:\/|\b)/g});function kl(e,t=Date.now()){let n=null;for(let r of e||[]){let o=r.payload?.ts??r.ts;r.type==="pr.offer.answered"?n=r.payload?.action==="pr"?{ts:o,offerId:r.payload?.offerId??null,box:r.boxId??null,offerType:"offer"}:null:r.type==="pr.exists.answered"?n=r.payload?.choice==="push"?{ts:o,offerId:r.payload?.offerId??null,box:r.boxId??null,offerType:"exists"}:null:r.type==="pr.state.changed"&&(r.payload?.change==="opened"||r.payload?.change==="pushed")&&n!=null&&o>=n.ts&&(n=null)}return n!=null&&t-n.ts>CN?null:n}function MN(e,t){return e?.firstSeen==null||t?.ts==null||e.firstSeen<t.ts}async function kx(e){let t=e?.workspace?.branch;if(!t)return;let n;try{n=await L(e)}catch{return}let r=kl(n);if(r==null)return;let o=(e.boxes||[]).find(u=>u.name===e.leadBox);if(await eo(e.leadBox,o?.agent).catch(()=>!1))return;let s=Date.now();if(s-(Tp.get(e.id)||0)<ON)return;Tp.set(e.id,s);let a;try{a=await Vt(e.cwd,{caller:"reconcile"})}catch{return}let i=await os(e).catch(()=>[t]),c=(a||[]).find(u=>i.includes(u.headRefName));if(!c)return;let l=await me(e.cwd).catch(()=>null);if(l){let{link:u,created:f}=await mt({repo:l,number:c.number,trackId:e.id,url:c.url,headRef:c.headRefName||t,title:c.title,source:"reconciled"});if(!f&&!(u?.trackId===e.id&&await hn(l,c.number))){if(!MN(u,r))return;let d=await L(e).catch(()=>null);if(d&&kl(d)==null)return;await _(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:{ts:Date.now(),change:"pushed",number:c.number,url:c.url,title:c.title,branch:t,repo:l}});return}}await _(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:{ts:Date.now(),change:"opened",number:c.number,url:c.url,title:c.title,branch:t,...l?{repo:l}:{}}}).catch(()=>{}),Tp.delete(e.id)}var ON,Tp,CN,Ep=O(()=>{ue();ns();Un();wn();Ba();ss();ON=6e3,Tp=new Map,CN=30*6e4});import Ap from"node:os";import{execFile as NN}from"node:child_process";import{promisify as PN}from"node:util";async function xl(){if(process.platform!=="darwin")return Ap.freemem();try{let{stdout:e}=await DN("vm_stat",[],{timeout:3e3}),t=Number(/page size of (\d+) bytes/.exec(e)?.[1])||4096,n=o=>Number(new RegExp(`Pages ${o}:\\s+(\\d+)\\.`).exec(e)?.[1])||0,r=(n("free")+n("inactive")+n("speculative"))*t;return r>0?r:Ap.freemem()}catch{return Ap.freemem()}}var DN,_p=O(()=>{DN=PN(NN)});import Ne from"node:fs/promises";import Pe from"node:path";import Tx from"node:os";import{randomUUID as BN}from"node:crypto";import{execFile as jN}from"node:child_process";import{promisify as LN}from"node:util";import{chromium as FN}from"playwright-core";async function tn(){return to||(Ip||=(async()=>{try{to=JSON.parse(await Ne.readFile(Ax,"utf8"))}catch{to={mocks:[]}}finally{Ip=null}return to.mocks||=[],to})(),Ip)}async function Tt(){await at(Ax,to)}function $x(e,t){en(e,t.v,t.videoRel?.endsWith(".webm")?"webm":"mp4"),t.posterRel&&en(e,t.v,"png")}function nt(e,t,n={}){return _({id:e.trackId,cwd:e.cwd},{type:"mock.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,provider:e.agent||null,payload:{ts:Date.now(),change:t,mockId:e.id,name:e.name,...e.group?{group:e.group}:{},...e.kind==="video"?{kind:"video"}:{},...n}}).catch(()=>{})}function Et(e,t){let n=Ga(e.cwd);return{html:Pe.join(n,`${e.id}.v${t}.html`),png:Pe.join(n,`${e.id}.v${t}.png`)}}function Ka(e,t,n){if(!t)return null;let r=n==="html"?t.htmlRel:n==="png"?t.pngRel??t.posterRel??null:n==="video"?t.videoRel??null:null;return r?Pe.join(e.cwd,r):null}function Bt(e,t=null){let n=e.versions||[];return t!=null?n.find(r=>r.v===Number(t))||null:n.length?n[n.length-1]:null}function Op(e){return e.length<24||e.readUInt32BE(12)!==1229472850?null:{width:e.readUInt32BE(16),height:e.readUInt32BE(20)}}function Sl(e){return Buffer.isBuffer(e)&&e.length>24&&e.subarray(0,8).equals(VN)}function zN(e){return!Buffer.isBuffer(e)||e.length<32?null:e.subarray(4,8).toString("latin1")==="ftyp"?{ext:"mp4",mime:"video/mp4"}:e.readUInt32BE(0)===440786851?{ext:"webm",mime:"video/webm"}:null}async function JN(e){let t=Buffer.alloc(24),n=await Ne.open(e,"r");try{await n.read(t,0,24,0)}finally{await n.close()}return t}function YN({imgW:e,imgH:t,bbox:n,pad:r,align:o=1}){if(!n||!(e>0)||!(t>0))return null;let s=n.right-n.left+1,a=n.bottom-n.top+1;if(s<=0||a<=0||s>=e*.9&&a>=t*.9)return null;let i=s+2*r,c=a+2*r;return i+=(o-i%o)%o,c+=(o-c%o)%o,{sx:n.left,sy:n.top,sw:s,sh:a,outW:i,outH:c,dx:Math.floor((i-s)/2),dy:Math.floor((c-a)/2)}}async function XN(e,t){return e.evaluate(async n=>{let r=new Image;await new Promise((m,h)=>{r.onload=m,r.onerror=()=>h(new Error("decode failed")),r.src=`data:image/png;base64,${n}`});let o=r.naturalWidth,s=r.naturalHeight;if(!o||!s||o*s>24e6)return null;let a=document.createElement("canvas");a.width=o,a.height=s;let i=a.getContext("2d",{willReadFrequently:!0});i.drawImage(r,0,0);let c=i.getImageData(0,0,o,s).data,l=[c[0],c[1],c[2]],u=o,f=s,d=-1,p=-1;for(let m=0;m<s;m++)for(let h=m*o*4,g=0;g<o;g++,h+=4)Math.abs(c[h]-l[0])+Math.abs(c[h+1]-l[1])+Math.abs(c[h+2]-l[2])>24&&(g<u&&(u=g),g>d&&(d=g),m<f&&(f=m),p=m);return d<0?null:{imgW:o,imgH:s,bg:l,bbox:{left:u,top:f,right:d,bottom:p}}},t.toString("base64"))}async function ZN(e,t,{bg:n,crop:r}){let o=await e.evaluate(async({b64:s,bg:a,crop:i})=>{let c=new Image;await new Promise((f,d)=>{c.onload=f,c.onerror=()=>d(new Error("decode failed")),c.src=`data:image/png;base64,${s}`});let l=document.createElement("canvas");l.width=i.outW,l.height=i.outH;let u=l.getContext("2d");return u.fillStyle=`rgb(${a[0]},${a[1]},${a[2]})`,u.fillRect(0,0,i.outW,i.outH),u.drawImage(c,i.sx,i.sy,i.sw,i.sh,i.dx,i.dy,i.sw,i.sh),l.toDataURL("image/png").split(",")[1]},{b64:t.toString("base64"),bg:n,crop:r});return Buffer.from(o,"base64")}async function QN({htmlPath:e,outPath:t,width:n}){let r=Date.now(),o;try{o=await FN.launch({executablePath:_x,args:["--disable-gpu"],timeout:3e4})}catch(s){throw new ht("chromium failed to launch",s?.message||"")}try{let a=await(await o.newContext({viewport:{width:n,height:800},deviceScaleFactor:cs})).newPage();a.setDefaultTimeout(ls),await a.goto(`file://${e}`,{waitUntil:"load",timeout:ls}),await a.waitForTimeout(250);let i;for(let l=1;;l++)try{i=await a.screenshot({fullPage:!0,timeout:ls});break}catch(u){if(l>=3||!/captureScreenshot|Unable to capture/i.test(u?.message||""))throw u;await a.waitForTimeout(500)}try{let l=await XN(a,i),u=l&&YN({...l,pad:WN*cs,align:cs});u&&(i=await ZN(a,i,{bg:l.bg,crop:u}))}catch{}if(i.length<Ix)throw new ht(`capture produced a ${i.length}-byte image`);let c=Op(i);if(!c)throw new ht("output is not a PNG");return await Ne.writeFile(t,i),{width:Math.round(c.width/cs),height:Math.round(c.height/cs),dpr:cs,renderMs:Date.now()-r}}catch(s){throw s instanceof ht?s:new ht(/timeout/i.test(s?.message||"")?`render timed out after ${ls}ms`:"chromium render failed",s?.message||"")}finally{await o.close().catch(()=>{})}}async function vx({htmlPath:e,outPath:t,width:n}){let r=await Ne.mkdtemp(Pe.join(Tx.tmpdir(),"bostrat-mock-profile-")),o=Date.now(),s="";try{try{s=(await $p(xx,["--headless","--no-remote","--profile",r,`--window-size=${n}`,"--screenshot",t,`file://${e}`],{env:{...process.env,MOZ_HEADLESS:"1"},timeout:ls,killSignal:"SIGKILL",maxBuffer:4194304})).stderr||""}catch(c){throw s=c?.stderr||"",c?.code==="ENOENT"?new ht(`firefox not found (${xx})`,""):new ht(c?.killed?`render timed out after ${ls}ms`:"firefox exited non-zero",s)}let a=await Ne.stat(t).catch(()=>null);if(!a||a.size<Ix)throw new ht(`render produced ${a?`a ${a.size}-byte file`:"no file"} (silent no-op \u2014 another firefox holding the profile?)`,s);let i=Op(await JN(t));if(!i)throw new ht("output is not a PNG",s);return{width:i.width,height:i.height,dpr:1,renderMs:Date.now()-o}}finally{await Ne.rm(r,{recursive:!0,force:!0}).catch(()=>{})}}async function eP(e){if(UN==="firefox")return vx(e);try{return await QN(e)}catch(t){if(!/failed to launch/i.test(t?.message||""))throw t;try{return await vx(e)}catch(n){throw/not found/.test(n?.message||"")?new ht(`no browser installed \u2014 chromium missing at ${_x} and no firefox on PATH; install chromium (Debian: apt install chromium fonts-dejavu-core fonts-liberation) or point BOSTRAT_CHROMIUM_BIN at a Chrome/Chromium binary`,t?.message||""):n}}}function Ox(e){return Rp=Rp.then(e,e),Rp}async function Cx(e,t){let n=await tn(),r=n.mocks.find(o=>o.id===e);if(r){r.state="rendering",await Tt(),await nt(r,"rendering",{version:t});try{let o=await xl();if(o<qN)throw new ht(`box is low on memory (${Math.round(o/1e6)} MB available) \u2014 not spawning a browser`);let s=Et(r,t),a=await tP({htmlPath:s.html,outPath:s.png,width:r.width});if(!n.mocks.some(i=>i.id===e)){await Ne.rm(s.png,{force:!0}).catch(()=>{});return}Cp(r,{v:t,source:"html",htmlRel:Pe.relative(r.cwd,s.html),pngRel:Pe.relative(r.cwd,s.png),width:a.width,height:a.height,dpr:a.dpr,renderMs:a.renderMs,createdAt:Date.now()}),await Tt(),await nt(r,"ready",{version:t,width:a.width,height:a.height,dpr:a.dpr}),Qt(r),en(r,t,"png")}catch(o){if(!n.mocks.some(s=>s.id===e))return;r.state="error",r.error=o?.message||String(o),await Tt(),await nt(r,"error",{version:t,error:r.error}),Qt(r)}}}function Cp(e,t){e.versions=(e.versions||[]).filter(r=>r.v!==t.v).concat(t),e.versions.sort((r,o)=>r.v-o.v);let n=e.versions[e.versions.length-1];e.readyVersion=n.v,e.height=n.height,e.dpr=n.dpr,e.renderMs=n.renderMs??null,n.v===e.version&&(e.state="ready",e.error=null)}function nP({trackId:e,name:t,cwd:n,width:r}){if(!e)throw new Error("trackId required");if(typeof t!="string"||!t.trim())throw new Error("name (string) required");if(!n)throw new Error("cwd required");let o=r==null?HN:Number(r);if(!Number.isInteger(o)||o<320||o>4e3)throw new Error("invalid width (320-4000)");return o}async function Va({trackId:e,group:t}={}){let n=await tn(),r=e?n.mocks.filter(o=>o.trackId===e):n.mocks;return t&&(r=r.filter(o=>o.group===t)),r.map(o=>({...o}))}async function En(e){let n=(await tn()).mocks.find(r=>r.id===e);return n?{...n}:null}function Mx({html:e,image:t,video:n}){if([typeof e=="string"&&e.trim(),!!t,!!n].filter(Boolean).length!==1)throw new Error("exactly one of html (string), image (png) or video (mp4/webm) required");if(t&&!Sl(t))throw new Error("image must be a PNG");if(n){let o=zN(n);if(!o)throw new Error("video must be an mp4 or webm (magic-byte check failed)");if(n.length>Sx)throw new Error(`video must be ${Sx/(1024*1024)} MB or smaller (got ${Math.round(n.length/(1024*1024))} MB)`);return o}return null}async function Nx({trackId:e,name:t,html:n,image:r,video:o,cwd:s,width:a,group:i,box:c,agent:l,prompt:u}){let f=nP({trackId:e,name:t,cwd:s,width:a}),d=typeof n=="string"&&n.trim(),p=Mx({html:n,image:r,video:o}),m=await tn(),h={id:BN().slice(0,8),trackId:e,box:c||null,agent:l||null,name:t.trim(),prompt:u?String(u).slice(0,500):null,group:i?String(i).trim():null,cwd:s,width:f,height:null,dpr:null,state:"queued",source:d?"html":o?"video":"image",kind:o?"video":"image",version:1,readyVersion:null,versions:[],error:null,renderMs:null,createdAt:Date.now(),updatedAt:Date.now()};return await Ne.mkdir(Ga(s),{recursive:!0}),m.mocks.push(h),d?(await Ne.writeFile(Et(h,1).html,n),await Tt(),await nt(h,"created"),Qt(h),en(h,1,"html"),Ox(()=>Cx(h.id,1))):o?(await Dx(h,1,o,p),await Tt(),await nt(h,"created"),await nt(h,"ready",{version:1,width:h.width,height:h.height,dpr:h.dpr,durationS:h.versions[0]?.durationS??null}),Qt(h),$x(h,h.versions[0])):(await Bx(h,1,r),await Tt(),await nt(h,"created"),await nt(h,"ready",{version:1,width:h.width,height:h.height,dpr:h.dpr}),Qt(h),en(h,1,"png")),{...h}}async function Px(e,{html:t,image:n,video:r,width:o}={}){let a=(await tn()).mocks.find(u=>u.id===e);if(!a)throw new Error("mock not found");let i=typeof t=="string"&&t.trim(),c=Mx({html:t,image:n,video:r});if(o!=null){let u=Number(o);if(!Number.isInteger(u)||u<320||u>4e3)throw new Error("invalid width (320-4000)");a.width=u}let l=a.version+1;return a.version=l,a.updatedAt=Date.now(),a.source=i?"html":r?"video":"image",a.kind=r?"video":"image",await Ne.mkdir(Ga(a.cwd),{recursive:!0}),i?(a.state="queued",await Ne.writeFile(Et(a,l).html,t),await Tt(),await nt(a,"updated",{version:l}),Qt(a),en(a,l,"html"),Ox(()=>Cx(a.id,l))):r?(await Dx(a,l,r,c),await Tt(),await nt(a,"updated",{version:l}),await nt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr,durationS:Bt(a)?.durationS??null}),Qt(a),$x(a,a.versions.find(u=>u.v===l))):(await Bx(a,l,n),await Tt(),await nt(a,"updated",{version:l}),await nt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr}),Qt(a),en(a,l,"png")),{...a}}async function rP(e){try{let{stdout:t}=await $p(KN,["-v","error","-print_format","json","-show_format","-show_streams",e],{timeout:Rx,killSignal:"SIGKILL",maxBuffer:4194304}),n=JSON.parse(t),r=(n.streams||[]).find(s=>s.codec_type==="video"),o=Number(n.format?.duration)||Number(r?.duration)||0;return{durationS:o>0?Math.round(o*10)/10:null,width:Number(r?.width)||null,height:Number(r?.height)||null}}catch{return null}}async function oP(e,t){try{await $p(GN,["-y","-v","error","-i",e,"-frames:v","1","-f","image2",t],{timeout:Rx,killSignal:"SIGKILL",maxBuffer:4*1024*1024});let n=await Ne.stat(t).catch(()=>null);return!!n&&n.size>0}catch{return!1}}async function Dx(e,t,n,r){let o=Ga(e.cwd),s=Pe.join(o,`${e.id}.v${t}.${r.ext}`),a=Pe.join(o,`${e.id}.v${t}.poster.png`);await Ne.writeFile(s,n);let i=await rP(s),c=await oP(s,a);Cp(e,{v:t,source:"video",htmlRel:null,pngRel:null,videoRel:Pe.relative(e.cwd,s),posterRel:c?Pe.relative(e.cwd,a):null,mimeType:r.mime,bytes:n.length,durationS:i?.durationS??null,width:i?.width??null,height:i?.height??null,dpr:1,renderMs:null,createdAt:Date.now()}),i?.width&&(e.width=i.width)}async function Bx(e,t,n){let r=Op(n);if(!r)throw new Error("image must be a PNG");let o=Et(e,t);await Ne.writeFile(o.png,n),Cp(e,{v:t,source:"image",htmlRel:null,pngRel:Pe.relative(e.cwd,o.png),width:r.width,height:r.height,dpr:1,renderMs:null,createdAt:Date.now()}),e.width=r.width}async function jx(e){let t=await tn(),n=t.mocks.find(o=>o.id===e);if(!n)throw new Error("mock not found");if(n.readyVersion==null)throw new Error(`mock is ${n.state} \u2014 nothing to pick yet`);let r=n.group?t.mocks.filter(o=>o.trackId===n.trackId&&o.group===n.group&&o.id!==e&&o.readyVersion!=null).map(o=>({mockId:o.id,name:o.name})):[];return await nt(n,"picked",{version:n.readyVersion,siblings:r}),{mock:{...n},siblings:r}}async function Lx(e){let t=await tn(),n=t.mocks.findIndex(o=>o.id===e);if(n===-1)throw new Error("mock not found");let r=t.mocks[n];t.mocks.splice(n,1);for(let o=1;o<=r.version;o++){let s=Et(r,o);await Ne.rm(s.html,{force:!0}).catch(()=>{}),await Ne.rm(s.png,{force:!0}).catch(()=>{})}for(let o of r.versions||[])for(let s of[o.videoRel,o.posterRel])s&&await Ne.rm(Pe.join(r.cwd,s),{force:!0}).catch(()=>{});return await Tt(),await nt(r,"deleted"),$t("mocks",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function Fx(e){let n=(await tn()).mocks.filter(i=>i.trackId===e.id);if(!n.length)return 0;let r=Pe.join(Ex,"mock-archive",e.id),o=Ga(e.cwd),s=Pe.join(r,".bostrat","mocks");await Ne.mkdir(s,{recursive:!0});let a=await Ne.readdir(o).catch(()=>[]);for(let i of a)await Ne.copyFile(Pe.join(o,i),Pe.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 Ne.stat(Pe.join(r,l)).catch(()=>null))?.isFile())throw new Error(`mock evacuation incomplete: ${l} missing from the archive`)}i.cwd=r,i.trackDeletedAt=Date.now(),i.trackName=e.name||e.id,i.updatedAt=Date.now(),Qt(i)}return await Tt(),n.length}async function Ux(e){let t=await tn(),n=t.mocks.filter(r=>r.trackId===e);if(n.length){t.mocks=t.mocks.filter(r=>r.trackId!==e),await Tt();for(let r of n)$t("mocks",r.id).catch(()=>{})}return n.length}async function Hx(){if(!Ee())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await je("mocks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await tn();for(let r of n.mocks){await Qt(r);for(let o of r.versions||[])o.htmlRel&&await en(r,o.v,"html"),(o.pngRel||o.posterRel)&&await en(r,o.v,"png"),o.videoRel&&await en(r,o.v,o.videoRel.endsWith(".webm")?"webm":"mp4")}return{pushed:n.mocks.length,source:"plane"}}var $p,Ex,Ax,UN,_x,xx,HN,cs,WN,Ix,ls,qN,Sx,KN,GN,Rx,ht,to,Ip,Qt,en,Ga,VN,tP,Rp,us=O(()=>{ue();Wn();_p();Kn();$p=LN(jN),Ex=process.env.BOSTRAT_STATE_DIR||Pe.join(process.env.HOME||Tx.tmpdir(),".bostrat"),Ax=Pe.join(Ex,"mocks.json"),UN=process.env.BOSTRAT_MOCK_ENGINE||"chromium",_x=process.env.BOSTRAT_CHROMIUM_BIN||"/usr/bin/chromium",xx=process.env.BOSTRAT_FIREFOX_BIN||"firefox",HN=1300,cs=2,WN=32,Ix=1500,ls=Number(process.env.BOSTRAT_MOCK_TIMEOUT_MS)||75e3,qN=700*1024*1024,Sx=100*1024*1024,KN=process.env.BOSTRAT_FFPROBE_BIN||"ffprobe",GN=process.env.BOSTRAT_FFMPEG_BIN||"ffmpeg",Rx=2e4,ht=class extends Error{constructor(t,n=""){super(n?`${t}
154
+ `)}catch{return""}}async function KN(e){if(e.state==="stopped"||e.state==="error")return!1;let t=e.origin!=="detected",n=t?await WN(e.slug):!0;if(t&&!n){let s=e.state==="starting";return e.state=s?"error":"stopped",s&&(e.error=await f0(e.slug)||"server exited before listening"),vn.delete(e.id),await Tn(e,e.state,e.error?{error:e.error}:{}),!0}if(await za(e.port))return vn.delete(e.id),e.lastHealthyAt=Date.now(),e.state!=="live"?(e.state="live",e.error=null,await Tn(e,"live"),!0):!1;if(e.state==="starting")return Date.now()-e.createdAt>qN?(e.state="error",e.error=await f0(e.slug)||"never started listening",await Tn(e,"error",{error:e.error}),!0):!1;let o=(vn.get(e.id)||0)+1;return vn.set(e.id,o),o>=3&&e.state==="live"?(e.state="unhealthy",!0):!1}async function xl(){if(!bp){bp=!0;try{let e=await En(),t=!1;for(let n of e.views)await KN(n)&&(t=!0);t&&await en()}finally{bp=!1}}}async function Sl({trackId:e}={}){await xl();let t=await En();return(e?t.views.filter(r=>r.trackId===e):t.views).map(r=>({...r}))}async function x0(e){let n=(await En()).views.find(r=>r.id===e);return n?{...n}:null}function Ip(e){return Zt&&Zt.views.find(t=>t.slug===e)||null}async function Rp({trackId:e,name:t,cmd:n,cwd:r,serveCwd:o,port:s,box:a,origin:i="agent",branch:c=null}){if(!e)throw new Error("trackId required");if(typeof t!="string"||!t.trim())throw new Error("name (string) required");if(i!=="detected"&&(typeof n!="string"||!n.trim()))throw new Error("cmd (string) required");if(!r)throw new Error("cwd required");let l=o!=null,u=lt.resolve(r,o??"."),f=i==="detected"?null:async()=>{await LN(r,u),await FN(u,n)},d=await En();if(i!=="detected"){let h=Sp(t),g=String(n).trim(),x=d.views.find(k=>k.trackId===e&&(k.slug===h||Sp(k.name)===h||k.cmd===g&&lt.resolve(k.serveCwd??k.cwd)===u));if(x)return GN(d,x,{cmd:g,box:a,branch:c,serveCwd:l?u:void 0,validate:f})}if(f&&await f(),d.views.filter(h=>h.state==="live"||h.state==="starting").length>=mr)throw new Error(`view cap reached (${mr} live) \u2014 stop one first`);let m={id:vN().slice(0,8),trackId:e,box:a||null,name:t.trim(),slug:UN(d,t),cmd:n?String(n).trim():null,cwd:r,serveCwd:u,branch:c,port:await HN(d,s),origin:i,state:"starting",error:null,createdAt:Date.now(),lastHealthyAt:null};return i!=="detected"&&await _p(m),d.views.push(m),await en(),await Tn(m,"created",{origin:i}),xp(e,m.id),i==="detected"&&await za(m.port)&&(m.state="live",m.lastHealthyAt=Date.now(),await en(),await Tn(m,"live")),{...m}}async function GN(e,t,{cmd:n,box:r,branch:o,serveCwd:s,validate:a}){r&&(t.box=r),o&&(t.branch=o);let i=t.cmd!==n,c=s!==void 0&&!await BN(t.serveCwd??t.cwd,s);if((t.state==="live"||t.state==="starting")&&!i&&!c&&await za(t.port))return await en(),xp(t.trackId,t.id),{...t,reused:!0};if(a&&await a(),e.views.filter(f=>f.id!==t.id&&(f.state==="live"||f.state==="starting")).length>=mr)throw new Error(`view cap reached (${mr} live) \u2014 stop one first`);return t.origin==="detected"?(await Ap(t.port),t.origin="agent"):await Ja(t.slug),t.cmd=n,s!==void 0&&(t.serveCwd=s),t.state="starting",t.error=null,t.createdAt=Date.now(),vn.delete(t.id),await _p(t),await en(),await Tn(t,"created",{restarted:!0,reused:!0}),xp(t.trackId,t.id),{...t,reused:!0}}async function S0(e){let n=(await En()).views.find(r=>r.id===e);if(!n)throw new Error("view not found");return n.origin==="detected"?await Ap(n.port):await Ja(n.slug),n.state!=="stopped"&&(n.state="stopped",vn.delete(n.id),await en(),await Tn(n,"stopped")),{...n}}async function v0(e){let t=await En(),n=t.views.find(o=>o.id===e);if(!n)throw new Error("view not found");if(!n.cmd)throw new Error("a detected view has no known command \u2014 recreate it as a managed view");if(t.views.filter(o=>o.id!==e&&(o.state==="live"||o.state==="starting")).length>=mr)throw new Error(`view cap reached (${mr} live) \u2014 stop one first`);return await Ja(n.slug),n.state="starting",n.error=null,n.createdAt=Date.now(),vn.delete(n.id),await _p(n),await en(),await Tn(n,"created",{restarted:!0}),{...n}}async function T0(e){let t=await En(),n=t.views.findIndex(o=>o.id===e);if(n===-1)throw new Error("view not found");let r=t.views[n];return r.origin==="detected"?await Ap(r.port):await Ja(r.slug),t.views.splice(n,1),vn.delete(r.id),await en(),await Tn(r,"deleted"),{ok:!0,id:e,slug:r.slug}}async function E0(e){let t=await En(),n=t.views.filter(r=>r.trackId===e);for(let r of n)r.origin!=="detected"&&await Ja(r.slug),vn.delete(r.id);return n.length&&(t.views=t.views.filter(r=>r.trackId!==e),await en()),n.length}async function A0(e,t){if(!e?.id||!Array.isArray(t)||!t.length)return[];let n=await En(),r=n.adoptWatermarks[e.id]??null,o=t.filter(c=>c.role==="assistant"&&c.ts!=null&&(r==null?!1:c.ts>r)),s=t.reduce((c,l)=>l.ts>c?l.ts:c,r??0);if(n.adoptWatermarks[e.id]!==s&&(n.adoptWatermarks[e.id]=s,await en()),!o.length)return[];let a=new Set;for(let c of o)for(let l of String(c.text||"").matchAll(VN)){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(!k0().has(c)&&!n.views.some(l=>l.port===c)&&await za(c))try{i.push(await Rp({trackId:e.id,name:`${e.name} preview`,cmd:null,cwd:e.cwd,port:c,origin:"detected",branch:e.workspace?.branch??null}))}catch{}return i}var Qt,AN,p0,l0,u0,mr,_N,us,d0,Ka,IN,kp,RN,$N,ON,vp,m0,gp,NN,DN,w0,bl,Zt,yp,Ga,Tp,g0,vn,qN,bp,VN,vl=C(()=>{Ve();ue();qn();Qt=EN(TN),AN=process.env.BOSTRAT_STATE_DIR||lt.join(process.env.HOME||xN.tmpdir(),".bostrat"),p0=lt.join(AN,"views.json"),[l0,u0]=(process.env.BOSTRAT_VIEW_PORTS||"4300-4349").split("-").map(e=>Number(e)||0),mr=Number(process.env.BOSTRAT_VIEW_MAX)||3,_N="bostrat-view-",us=e=>`${_N}${e}`,d0=new Set(["bostrat","www","api","views","app"]),Ka=e=>Object.assign(new Error(e),{status:400}),IN=new Set(["npm","pnpm","yarn","bun"]),kp="package.json",RN=/[|;&`]|\$\(/,$N=new Set(["sh","bash","zsh","dash","env","exec","nohup","time"]),ON=/(^|\s)(-C|--cwd|--manifest-path|--dir)(=|\s)/,vp=e=>String(e).trim().split(/\s+/).filter(Boolean),m0=/^[A-Za-z_][A-Za-z0-9_]*=/;gp=e=>e==="/",NN=e=>e===".."||e.startsWith("../")||e.includes("/../")||e.endsWith("/..");DN=e=>Va.stat(e).then(t=>t.isDirectory(),()=>!1),w0=e=>Va.stat(e).then(t=>t.isFile(),()=>!1),bl=e=>Va.realpath(e).catch(()=>lt.resolve(e));Zt=null,yp=null;Ga=new Map,Tp=Number(process.env.BOSTRAT_VIEW_JOB_TIMEOUT)||3e5,g0=12e3;vn=new Map,qN=12e4;bp=!1;VN=/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::(\d{2,5}))?(?:\/|\b)/g});function Tl(e,t=Date.now()){let n=null;for(let r of e||[]){let o=r.payload?.ts??r.ts;r.type==="pr.offer.answered"?n=r.payload?.action==="pr"?{ts:o,offerId:r.payload?.offerId??null,box:r.boxId??null,offerType:"offer"}:null:r.type==="pr.exists.answered"?n=r.payload?.choice==="push"?{ts:o,offerId:r.payload?.offerId??null,box:r.boxId??null,offerType:"exists"}:null:r.type==="pr.state.changed"&&(r.payload?.change==="opened"||r.payload?.change==="pushed")&&n!=null&&o>=n.ts&&(n=null)}return n!=null&&t-n.ts>JN?null:n}function XN(e,t){return e?.firstSeen==null||t?.ts==null||e.firstSeen<t.ts}async function _0(e){let t=e?.workspace?.branch;if(!t)return;let n;try{n=await L(e)}catch{return}let r=Tl(n);if(r==null)return;let o=(e.boxes||[]).find(u=>u.name===e.leadBox);if(await Qr(e.leadBox,o?.agent).catch(()=>!1))return;let s=Date.now();if(s-($p.get(e.id)||0)<zN)return;$p.set(e.id,s);let a;try{a=await Jt(e.cwd,{caller:"reconcile"})}catch{return}let i=await is(e).catch(()=>[t]),c=(a||[]).find(u=>i.includes(u.headRefName));if(!c)return;let l=await me(e.cwd).catch(()=>null);if(l){let{link:u,created:f}=await mt({repo:l,number:c.number,trackId:e.id,url:c.url,headRef:c.headRefName||t,title:c.title,source:"reconciled"});if(!f&&!(u?.trackId===e.id&&await wn(l,c.number))){if(!XN(u,r))return;let d=await L(e).catch(()=>null);if(d&&Tl(d)==null)return;await _(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:{ts:Date.now(),change:"pushed",number:c.number,url:c.url,title:c.title,branch:t,repo:l}});return}}await _(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:{ts:Date.now(),change:"opened",number:c.number,url:c.url,title:c.title,branch:t,...l?{repo:l}:{}}}).catch(()=>{}),$p.delete(e.id)}var zN,$p,JN,Op=C(()=>{ue();ss();Hn();gn();Ha();cs();zN=6e3,$p=new Map,JN=30*6e4});import Cp from"node:os";import{execFile as YN}from"node:child_process";import{promisify as ZN}from"node:util";async function El(){if(process.platform!=="darwin")return Cp.freemem();try{let{stdout:e}=await QN("vm_stat",[],{timeout:3e3}),t=Number(/page size of (\d+) bytes/.exec(e)?.[1])||4096,n=o=>Number(new RegExp(`Pages ${o}:\\s+(\\d+)\\.`).exec(e)?.[1])||0,r=(n("free")+n("inactive")+n("speculative"))*t;return r>0?r:Cp.freemem()}catch{return Cp.freemem()}}var QN,Mp=C(()=>{QN=ZN(YN)});import Pe from"node:fs/promises";import De from"node:path";import O0 from"node:os";import{randomUUID as eP}from"node:crypto";import{execFile as tP}from"node:child_process";import{promisify as nP}from"node:util";import{chromium as rP}from"playwright-core";async function rn(){return eo||(Np||=(async()=>{try{eo=JSON.parse(await Pe.readFile(M0,"utf8"))}catch{eo={mocks:[]}}finally{Np=null}return eo.mocks||=[],eo})(),Np)}async function Tt(){await at(M0,eo)}function B0(e,t){nn(e,t.v,t.videoRel?.endsWith(".webm")?"webm":"mp4"),t.posterRel&&nn(e,t.v,"png")}function nt(e,t,n={}){return _({id:e.trackId,cwd:e.cwd},{type:"mock.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,provider:e.agent||null,payload:{ts:Date.now(),change:t,mockId:e.id,name:e.name,...e.group?{group:e.group}:{},...e.kind==="video"?{kind:"video"}:{},...n}}).catch(()=>{})}function Et(e,t){let n=Ya(e.cwd);return{html:De.join(n,`${e.id}.v${t}.html`),png:De.join(n,`${e.id}.v${t}.png`)}}function Xa(e,t,n){if(!t)return null;let r=n==="html"?t.htmlRel:n==="png"?t.pngRel??t.posterRel??null:n==="video"?t.videoRel??null:null;return r?De.join(e.cwd,r):null}function Bt(e,t=null){let n=e.versions||[];return t!=null?n.find(r=>r.v===Number(t))||null:n.length?n[n.length-1]:null}function Bp(e){return e.length<24||e.readUInt32BE(12)!==1229472850?null:{width:e.readUInt32BE(16),height:e.readUInt32BE(20)}}function Al(e){return Buffer.isBuffer(e)&&e.length>24&&e.subarray(0,8).equals(uP)}function dP(e){return!Buffer.isBuffer(e)||e.length<32?null:e.subarray(4,8).toString("latin1")==="ftyp"?{ext:"mp4",mime:"video/mp4"}:e.readUInt32BE(0)===440786851?{ext:"webm",mime:"video/webm"}:null}async function fP(e){let t=Buffer.alloc(24),n=await Pe.open(e,"r");try{await n.read(t,0,24,0)}finally{await n.close()}return t}function pP({imgW:e,imgH:t,bbox:n,pad:r,align:o=1}){if(!n||!(e>0)||!(t>0))return null;let s=n.right-n.left+1,a=n.bottom-n.top+1;if(s<=0||a<=0||s>=e*.9&&a>=t*.9)return null;let i=s+2*r,c=a+2*r;return i+=(o-i%o)%o,c+=(o-c%o)%o,{sx:n.left,sy:n.top,sw:s,sh:a,outW:i,outH:c,dx:Math.floor((i-s)/2),dy:Math.floor((c-a)/2)}}async function mP(e,t){return e.evaluate(async n=>{let r=new Image;await new Promise((m,h)=>{r.onload=m,r.onerror=()=>h(new Error("decode failed")),r.src=`data:image/png;base64,${n}`});let o=r.naturalWidth,s=r.naturalHeight;if(!o||!s||o*s>24e6)return null;let a=document.createElement("canvas");a.width=o,a.height=s;let i=a.getContext("2d",{willReadFrequently:!0});i.drawImage(r,0,0);let c=i.getImageData(0,0,o,s).data,l=[c[0],c[1],c[2]],u=o,f=s,d=-1,p=-1;for(let m=0;m<s;m++)for(let h=m*o*4,g=0;g<o;g++,h+=4)Math.abs(c[h]-l[0])+Math.abs(c[h+1]-l[1])+Math.abs(c[h+2]-l[2])>24&&(g<u&&(u=g),g>d&&(d=g),m<f&&(f=m),p=m);return d<0?null:{imgW:o,imgH:s,bg:l,bbox:{left:u,top:f,right:d,bottom:p}}},t.toString("base64"))}async function hP(e,t,{bg:n,crop:r}){let o=await e.evaluate(async({b64:s,bg:a,crop:i})=>{let c=new Image;await new Promise((f,d)=>{c.onload=f,c.onerror=()=>d(new Error("decode failed")),c.src=`data:image/png;base64,${s}`});let l=document.createElement("canvas");l.width=i.outW,l.height=i.outH;let u=l.getContext("2d");return u.fillStyle=`rgb(${a[0]},${a[1]},${a[2]})`,u.fillRect(0,0,i.outW,i.outH),u.drawImage(c,i.sx,i.sy,i.sw,i.sh,i.dx,i.dy,i.sw,i.sh),l.toDataURL("image/png").split(",")[1]},{b64:t.toString("base64"),bg:n,crop:r});return Buffer.from(o,"base64")}async function wP({htmlPath:e,outPath:t,width:n}){let r=Date.now(),o;try{o=await rP.launch({executablePath:N0,args:["--disable-gpu"],timeout:3e4})}catch(s){throw new ht("chromium failed to launch",s?.message||"")}try{let a=await(await o.newContext({viewport:{width:n,height:800},deviceScaleFactor:ds})).newPage();a.setDefaultTimeout(fs),await a.goto(`file://${e}`,{waitUntil:"load",timeout:fs}),await a.waitForTimeout(250);let i;for(let l=1;;l++)try{i=await a.screenshot({fullPage:!0,timeout:fs});break}catch(u){if(l>=3||!/captureScreenshot|Unable to capture/i.test(u?.message||""))throw u;await a.waitForTimeout(500)}try{let l=await mP(a,i),u=l&&pP({...l,pad:aP*ds,align:ds});u&&(i=await hP(a,i,{bg:l.bg,crop:u}))}catch{}if(i.length<P0)throw new ht(`capture produced a ${i.length}-byte image`);let c=Bp(i);if(!c)throw new ht("output is not a PNG");return await Pe.writeFile(t,i),{width:Math.round(c.width/ds),height:Math.round(c.height/ds),dpr:ds,renderMs:Date.now()-r}}catch(s){throw s instanceof ht?s:new ht(/timeout/i.test(s?.message||"")?`render timed out after ${fs}ms`:"chromium render failed",s?.message||"")}finally{await o.close().catch(()=>{})}}async function $0({htmlPath:e,outPath:t,width:n}){let r=await Pe.mkdtemp(De.join(O0.tmpdir(),"bostrat-mock-profile-")),o=Date.now(),s="";try{try{s=(await Dp(I0,["--headless","--no-remote","--profile",r,`--window-size=${n}`,"--screenshot",t,`file://${e}`],{env:{...process.env,MOZ_HEADLESS:"1"},timeout:fs,killSignal:"SIGKILL",maxBuffer:4194304})).stderr||""}catch(c){throw s=c?.stderr||"",c?.code==="ENOENT"?new ht(`firefox not found (${I0})`,""):new ht(c?.killed?`render timed out after ${fs}ms`:"firefox exited non-zero",s)}let a=await Pe.stat(t).catch(()=>null);if(!a||a.size<P0)throw new ht(`render produced ${a?`a ${a.size}-byte file`:"no file"} (silent no-op \u2014 another firefox holding the profile?)`,s);let i=Bp(await fP(t));if(!i)throw new ht("output is not a PNG",s);return{width:i.width,height:i.height,dpr:1,renderMs:Date.now()-o}}finally{await Pe.rm(r,{recursive:!0,force:!0}).catch(()=>{})}}async function gP(e){if(oP==="firefox")return $0(e);try{return await wP(e)}catch(t){if(!/failed to launch/i.test(t?.message||""))throw t;try{return await $0(e)}catch(n){throw/not found/.test(n?.message||"")?new ht(`no browser installed \u2014 chromium missing at ${N0} and no firefox on PATH; install chromium (Debian: apt install chromium fonts-dejavu-core fonts-liberation) or point BOSTRAT_CHROMIUM_BIN at a Chrome/Chromium binary`,t?.message||""):n}}}function j0(e){return Pp=Pp.then(e,e),Pp}async function L0(e,t){let n=await rn(),r=n.mocks.find(o=>o.id===e);if(r){r.state="rendering",await Tt(),await nt(r,"rendering",{version:t});try{let o=await El();if(o<iP)throw new ht(`box is low on memory (${Math.round(o/1e6)} MB available) \u2014 not spawning a browser`);let s=Et(r,t),a=await yP({htmlPath:s.html,outPath:s.png,width:r.width});if(!n.mocks.some(i=>i.id===e)){await Pe.rm(s.png,{force:!0}).catch(()=>{});return}jp(r,{v:t,source:"html",htmlRel:De.relative(r.cwd,s.html),pngRel:De.relative(r.cwd,s.png),width:a.width,height:a.height,dpr:a.dpr,renderMs:a.renderMs,createdAt:Date.now()}),await Tt(),await nt(r,"ready",{version:t,width:a.width,height:a.height,dpr:a.dpr}),tn(r),nn(r,t,"png")}catch(o){if(!n.mocks.some(s=>s.id===e))return;r.state="error",r.error=o?.message||String(o),await Tt(),await nt(r,"error",{version:t,error:r.error}),tn(r)}}}function jp(e,t){e.versions=(e.versions||[]).filter(r=>r.v!==t.v).concat(t),e.versions.sort((r,o)=>r.v-o.v);let n=e.versions[e.versions.length-1];e.readyVersion=n.v,e.height=n.height,e.dpr=n.dpr,e.renderMs=n.renderMs??null,n.v===e.version&&(e.state="ready",e.error=null)}function bP({trackId:e,name:t,cwd:n,width:r}){if(!e)throw new Error("trackId required");if(typeof t!="string"||!t.trim())throw new Error("name (string) required");if(!n)throw new Error("cwd required");let o=r==null?sP:Number(r);if(!Number.isInteger(o)||o<320||o>4e3)throw new Error("invalid width (320-4000)");return o}async function Za({trackId:e,group:t}={}){let n=await rn(),r=e?n.mocks.filter(o=>o.trackId===e):n.mocks;return t&&(r=r.filter(o=>o.group===t)),r.map(o=>({...o}))}async function An(e){let n=(await rn()).mocks.find(r=>r.id===e);return n?{...n}:null}function F0({html:e,image:t,video:n}){if([typeof e=="string"&&e.trim(),!!t,!!n].filter(Boolean).length!==1)throw new Error("exactly one of html (string), image (png) or video (mp4/webm) required");if(t&&!Al(t))throw new Error("image must be a PNG");if(n){let o=dP(n);if(!o)throw new Error("video must be an mp4 or webm (magic-byte check failed)");if(n.length>R0)throw new Error(`video must be ${R0/(1024*1024)} MB or smaller (got ${Math.round(n.length/(1024*1024))} MB)`);return o}return null}async function U0({trackId:e,name:t,html:n,image:r,video:o,cwd:s,width:a,group:i,box:c,agent:l,prompt:u}){let f=bP({trackId:e,name:t,cwd:s,width:a}),d=typeof n=="string"&&n.trim(),p=F0({html:n,image:r,video:o}),m=await rn(),h={id:eP().slice(0,8),trackId:e,box:c||null,agent:l||null,name:t.trim(),prompt:u?String(u).slice(0,500):null,group:i?String(i).trim():null,cwd:s,width:f,height:null,dpr:null,state:"queued",source:d?"html":o?"video":"image",kind:o?"video":"image",version:1,readyVersion:null,versions:[],error:null,renderMs:null,createdAt:Date.now(),updatedAt:Date.now()};return await Pe.mkdir(Ya(s),{recursive:!0}),m.mocks.push(h),d?(await Pe.writeFile(Et(h,1).html,n),await Tt(),await nt(h,"created"),tn(h),nn(h,1,"html"),j0(()=>L0(h.id,1))):o?(await W0(h,1,o,p),await Tt(),await nt(h,"created"),await nt(h,"ready",{version:1,width:h.width,height:h.height,dpr:h.dpr,durationS:h.versions[0]?.durationS??null}),tn(h),B0(h,h.versions[0])):(await q0(h,1,r),await Tt(),await nt(h,"created"),await nt(h,"ready",{version:1,width:h.width,height:h.height,dpr:h.dpr}),tn(h),nn(h,1,"png")),{...h}}async function H0(e,{html:t,image:n,video:r,width:o}={}){let a=(await rn()).mocks.find(u=>u.id===e);if(!a)throw new Error("mock not found");let i=typeof t=="string"&&t.trim(),c=F0({html:t,image:n,video:r});if(o!=null){let u=Number(o);if(!Number.isInteger(u)||u<320||u>4e3)throw new Error("invalid width (320-4000)");a.width=u}let l=a.version+1;return a.version=l,a.updatedAt=Date.now(),a.source=i?"html":r?"video":"image",a.kind=r?"video":"image",await Pe.mkdir(Ya(a.cwd),{recursive:!0}),i?(a.state="queued",await Pe.writeFile(Et(a,l).html,t),await Tt(),await nt(a,"updated",{version:l}),tn(a),nn(a,l,"html"),j0(()=>L0(a.id,l))):r?(await W0(a,l,r,c),await Tt(),await nt(a,"updated",{version:l}),await nt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr,durationS:Bt(a)?.durationS??null}),tn(a),B0(a,a.versions.find(u=>u.v===l))):(await q0(a,l,n),await Tt(),await nt(a,"updated",{version:l}),await nt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr}),tn(a),nn(a,l,"png")),{...a}}async function kP(e){try{let{stdout:t}=await Dp(cP,["-v","error","-print_format","json","-show_format","-show_streams",e],{timeout:D0,killSignal:"SIGKILL",maxBuffer:4194304}),n=JSON.parse(t),r=(n.streams||[]).find(s=>s.codec_type==="video"),o=Number(n.format?.duration)||Number(r?.duration)||0;return{durationS:o>0?Math.round(o*10)/10:null,width:Number(r?.width)||null,height:Number(r?.height)||null}}catch{return null}}async function xP(e,t){try{await Dp(lP,["-y","-v","error","-i",e,"-frames:v","1","-f","image2",t],{timeout:D0,killSignal:"SIGKILL",maxBuffer:4*1024*1024});let n=await Pe.stat(t).catch(()=>null);return!!n&&n.size>0}catch{return!1}}async function W0(e,t,n,r){let o=Ya(e.cwd),s=De.join(o,`${e.id}.v${t}.${r.ext}`),a=De.join(o,`${e.id}.v${t}.poster.png`);await Pe.writeFile(s,n);let i=await kP(s),c=await xP(s,a);jp(e,{v:t,source:"video",htmlRel:null,pngRel:null,videoRel:De.relative(e.cwd,s),posterRel:c?De.relative(e.cwd,a):null,mimeType:r.mime,bytes:n.length,durationS:i?.durationS??null,width:i?.width??null,height:i?.height??null,dpr:1,renderMs:null,createdAt:Date.now()}),i?.width&&(e.width=i.width)}async function q0(e,t,n){let r=Bp(n);if(!r)throw new Error("image must be a PNG");let o=Et(e,t);await Pe.writeFile(o.png,n),jp(e,{v:t,source:"image",htmlRel:null,pngRel:De.relative(e.cwd,o.png),width:r.width,height:r.height,dpr:1,renderMs:null,createdAt:Date.now()}),e.width=r.width}async function K0(e){let t=await rn(),n=t.mocks.find(o=>o.id===e);if(!n)throw new Error("mock not found");if(n.readyVersion==null)throw new Error(`mock is ${n.state} \u2014 nothing to pick yet`);let r=n.group?t.mocks.filter(o=>o.trackId===n.trackId&&o.group===n.group&&o.id!==e&&o.readyVersion!=null).map(o=>({mockId:o.id,name:o.name})):[];return await nt(n,"picked",{version:n.readyVersion,siblings:r}),{mock:{...n},siblings:r}}async function G0(e){let t=await rn(),n=t.mocks.findIndex(o=>o.id===e);if(n===-1)throw new Error("mock not found");let r=t.mocks[n];t.mocks.splice(n,1);for(let o=1;o<=r.version;o++){let s=Et(r,o);await Pe.rm(s.html,{force:!0}).catch(()=>{}),await Pe.rm(s.png,{force:!0}).catch(()=>{})}for(let o of r.versions||[])for(let s of[o.videoRel,o.posterRel])s&&await Pe.rm(De.join(r.cwd,s),{force:!0}).catch(()=>{});return await Tt(),await nt(r,"deleted"),$t("mocks",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function V0(e){let n=(await rn()).mocks.filter(i=>i.trackId===e.id);if(!n.length)return 0;let r=De.join(C0,"mock-archive",e.id),o=Ya(e.cwd),s=De.join(r,".bostrat","mocks");await Pe.mkdir(s,{recursive:!0});let a=await Pe.readdir(o).catch(()=>[]);for(let i of a)await Pe.copyFile(De.join(o,i),De.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 Pe.stat(De.join(r,l)).catch(()=>null))?.isFile())throw new Error(`mock evacuation incomplete: ${l} missing from the archive`)}i.cwd=r,i.trackDeletedAt=Date.now(),i.trackName=e.name||e.id,i.updatedAt=Date.now(),tn(i)}return await Tt(),n.length}async function z0(e){let t=await rn(),n=t.mocks.filter(r=>r.trackId===e);if(n.length){t.mocks=t.mocks.filter(r=>r.trackId!==e),await Tt();for(let r of n)$t("mocks",r.id).catch(()=>{})}return n.length}async function J0(){if(!Ae())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await Fe("mocks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await rn();for(let r of n.mocks){await tn(r);for(let o of r.versions||[])o.htmlRel&&await nn(r,o.v,"html"),(o.pngRel||o.posterRel)&&await nn(r,o.v,"png"),o.videoRel&&await nn(r,o.v,o.videoRel.endsWith(".webm")?"webm":"mp4")}return{pushed:n.mocks.length,source:"plane"}}var Dp,C0,M0,oP,N0,I0,sP,ds,aP,P0,fs,iP,R0,cP,lP,D0,ht,eo,Np,tn,nn,Ya,uP,yP,Pp,ps=C(()=>{ue();qn();Mp();Gn();Dp=nP(tP),C0=process.env.BOSTRAT_STATE_DIR||De.join(process.env.HOME||O0.tmpdir(),".bostrat"),M0=De.join(C0,"mocks.json"),oP=process.env.BOSTRAT_MOCK_ENGINE||"chromium",N0=process.env.BOSTRAT_CHROMIUM_BIN||"/usr/bin/chromium",I0=process.env.BOSTRAT_FIREFOX_BIN||"firefox",sP=1300,ds=2,aP=32,P0=1500,fs=Number(process.env.BOSTRAT_MOCK_TIMEOUT_MS)||75e3,iP=700*1024*1024,R0=100*1024*1024,cP=process.env.BOSTRAT_FFPROBE_BIN||"ffprobe",lP=process.env.BOSTRAT_FFMPEG_BIN||"ffmpeg",D0=2e4,ht=class extends Error{constructor(t,n=""){super(n?`${t}
152
155
  ${n.trim().split(`
153
156
  `).slice(-6).join(`
154
- `)}`:t),this.name="MockRenderError"}},to=null,Ip=null;Qt=e=>et("mocks",{...e},{trackId:e.trackId}).catch(()=>{}),en=(e,t,n)=>{let r=(e.versions||[]).find(s=>s.v===t),o=n==="mp4"||n==="webm"?Ka(e,r,"video"):r&&Ka(e,r,n)||(n==="html"?Et(e,t).html:null);return o?qn("mocks",e.id,t,n,o).catch(()=>{}):Promise.resolve()};Ga=e=>Pe.join(e,".bostrat","mocks");VN=Buffer.from([137,80,78,71,13,10,26,10]);tP=eP,Rp=Promise.resolve()});import sP from"node:fs/promises";import Vx from"node:path";import aP from"node:os";import{randomUUID as zx}from"node:crypto";async function _n(){return An||(Mp||=(async()=>{let e=!0;try{An=JSON.parse(await sP.readFile(Jx,"utf8"))}catch{An={flows:[]},e=!1}finally{Mp=null}if(An.flows||=[],!e&&Ee()){let{records:t,source:n}=await je("flows").catch(()=>({records:[],source:"error"}));if(n==="plane"){for(let r of t)!r.deletedAt&&r.data?.id&&An.flows.push(r.data);An.flows.length&&await ds().catch(()=>{})}}return An})(),Mp)}async function ds(){await at(Jx,An)}function Np(e,t,n={}){return _({id:e.trackId,cwd:e.cwd},{type:"flow.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,provider:e.agent||null,payload:{ts:Date.now(),change:t,flowId:e.id,name:e.name,stepCount:e.steps.length,mockIds:[...new Set(e.steps.map(r=>r.mockId))],...n}}).catch(()=>{})}async function Yx({trackId:e,steps:t,prevSteps:n=[]}){if(!Array.isArray(t)||t.length<1||t.length>Wx)throw new Error(`steps must be an array of 1-${Wx}`);let r=await Va({trackId:e}),o=[...n],s=[];for(let i=0;i<t.length;i++){let c=t[i]||{},l=`step ${i+1}`,u=typeof c.caption=="string"?c.caption.trim():"";if(!u)throw new Error(`${l}: caption (string) required`);if(u.length>Kx)throw new Error(`${l}: caption over ${Kx} chars`);let f=c.title==null?null:String(c.title).trim()||null;if(f&&f.length>Gx)throw new Error(`${l}: title over ${Gx} chars`);let d=String(c.mock??"").trim().replace(/^mock:/,"");if(!d)throw new Error(`${l}: mock (name or id) required`);let p=r.filter(k=>k.id===d);if(p.length||(p=r.filter(k=>k.name.toLowerCase()===d.toLowerCase())),!p.length)throw new Error(`${l}: no mock matching "${d}" in this Track \u2014 see \`bostrat-mock ls\``);if(p.length>1)throw new Error(`${l}: "${d}" is ambiguous (${p.map(k=>`mock:${k.id}`).join(", ")}) \u2014 use the id`);let m=p[0],h=null;if(c.v!=null&&(h=Number(c.v),!Number.isInteger(h)||!(m.versions||[]).some(k=>k.v===h)))throw new Error(`${l}: "${m.name}" has no captured v${c.v} to pin`);let g=o.findIndex(k=>k.mockId===m.id),x=g>=0?o.splice(g,1)[0].id:zx().slice(0,8);s.push({id:x,mockId:m.id,caption:u,title:f,v:h})}let a={};for(let i of s)i.mockId in a||(a[i.mockId]=r.find(c=>c.id===i.mockId)?.readyVersion??null);return{steps:s,resolved:a}}function cP(e){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");if(e.trim().length>qx)throw new Error(`name over ${qx} chars`);return e.trim()}async function Xx({trackId:e}={}){let t=await _n();return(e?t.flows.filter(r=>r.trackId===e):t.flows).map(r=>({...r}))}async function lP(e){let n=(await _n()).flows.find(r=>r.id===e);return n?{...n}:null}async function Zx(e){let t=await lP(e);if(!t)return null;let n=new Map((await Va({trackId:t.trackId})).map(r=>[r.id,r]));return t.steps=t.steps.map(r=>{let o=n.get(r.mockId);if(!o)return{...r,missing:!0,mockName:null,mockState:null,servedV:null,width:null,height:null};let s=Bt(o,r.v);return{...r,missing:!1,mockName:o.name,mockState:o.state,servedV:s?.v??null,width:s?.width??null,height:s?.height??null}}),t}async function Qx({trackId:e,name:t,steps:n,cwd:r,box:o,agent:s}){if(!e)throw new Error("trackId required");if(!r)throw new Error("cwd required");let a=cP(t),i=await _n(),c=i.flows.find(p=>p.trackId===e&&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 Yx({trackId:e,steps:n}),f=Date.now(),d={id:zx().slice(0,8),trackId:e,box:o||null,agent:s||null,name:a,cwd:r,version:1,versions:[{v:1,steps:l,resolved:u,note:null,createdAt:f}],steps:l,createdAt:f,updatedAt:f};return i.flows.push(d),await ds(),await Np(d,"created"),vl(d),{...d}}async function eS(e,{steps:t,note:n}={}){let o=(await _n()).flows.find(i=>i.id===e);if(!o)throw new Error("flow not found");let{steps:s,resolved:a}=await Yx({trackId:o.trackId,steps:t,prevSteps:o.steps});return o.version+=1,o.versions.push({v:o.version,steps:s,resolved:a,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),o.steps=s,o.updatedAt=Date.now(),await ds(),await Np(o,"updated",{version:o.version,...n?{note:String(n).slice(0,200)}:{}}),vl(o),{...o}}async function tS(e){let t=await _n(),n=t.flows.findIndex(o=>o.id===e);if(n===-1)throw new Error("flow not found");let r=t.flows[n];return t.flows.splice(n,1),await ds(),await Np(r,"deleted"),$t("flows",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function nS(e){return(await _n()).flows.filter(n=>n.steps.some(r=>r.mockId===e)).map(n=>({...n}))}async function rS(e){let n=(await _n()).flows.filter(r=>r.trackId===e.id);for(let r of n)r.trackDeletedAt=Date.now(),r.trackName=e.name||e.id,r.updatedAt=Date.now(),vl(r);return n.length&&await ds(),n.length}async function oS(e){let t=await _n(),n=t.flows.filter(r=>r.trackId===e);if(n.length){t.flows=t.flows.filter(r=>r.trackId!==e),await ds();for(let r of n)$t("flows",r.id).catch(()=>{})}return n.length}async function sS(){if(!Ee())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await je("flows");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await _n();for(let r of n.flows)await vl(r);return{pushed:n.flows.length,source:"plane"}}var iP,Jx,Wx,qx,Kx,Gx,An,Mp,vl,Pp=O(()=>{ue();Wn();us();Kn();iP=process.env.BOSTRAT_STATE_DIR||Vx.join(process.env.HOME||aP.tmpdir(),".bostrat"),Jx=Vx.join(iP,"flows.json"),Wx=20,qx=80,Kx=500,Gx=80,An=null,Mp=null;vl=e=>et("flows",{...e},{trackId:e.trackId}).catch(()=>{})});import $n from"node:fs/promises";import On from"node:path";import uP from"node:os";import{randomUUID as dP}from"node:crypto";function za(e){return fP.filter(({re:t})=>t.test(e)).map(({label:t})=>t)}async function nn(){return In||(Dp||=(async()=>{let e=!0;try{In=JSON.parse(await $n.readFile(iS,"utf8"))}catch{In={runbooks:[]},e=!1}finally{Dp=null}return In.runbooks||=[],!e&&Ee()&&await pP().catch(()=>{}),In})(),Dp)}async function ro(){await at(iS,In)}function El(e){return Ja(et("runbooks",{...e},{trackId:e.trackId}))}async function pP(){let{records:e,source:t}=await je("runbooks");if(!(t!=="plane"||!e.length)){await $n.mkdir(Tl,{recursive:!0});for(let n of e){if(n.deletedAt||!n.data?.id)continue;let r=n.data;for(let o of r.versions||[]){let s=await Zs("runbooks",r.id,o.v,"md");typeof s=="string"&&await $n.writeFile(Rn(r,o.v),s).catch(()=>{})}In.runbooks.push(r)}In.runbooks.length&&await ro()}}function fs(e,t,n={}){return _({id:e.trackId,cwd:e.cwd},{type:"runbook.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,provider:e.agent||null,payload:{ts:Date.now(),change:t,runbookId:e.id,name:e.name,status:e.status,...n}}).catch(()=>{})}function Rn(e,t){return On.join(Tl,`${e.id}.v${t}.md`)}function cS(e,t=null){let n=e.versions||[];return t!=null?n.find(r=>r.v===Number(t))||null:n.length?n[n.length-1]:null}function lS(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Buffer.byteLength(e,"utf8");if(t>aS)throw new Error(`runbook is ${Math.round(t/1024)} KB \u2014 over the ${aS/1024} KB cap; a doc that size belongs in the repo, not a runbook`);let n=za(e);if(n.length)throw new Error(`runbook appears to contain a secret VALUE (${n.join(", ")}) \u2014 runbooks ship off-box; name the secret and where it goes, never its value. Replace it with a placeholder like <your key> and retry.`);return t}function mP(e,t){if(e.trackDeletedAt)throw new Error(`runbook is orphaned (its Track was deleted) \u2014 cannot ${t} it`)}async function hP({trackId:e,status:t}={}){let n=await nn(),r=e?n.runbooks.filter(o=>o.trackId===e):n.runbooks;return t&&(r=r.filter(o=>o.status===t)),r.map(o=>({...o}))}async function uS({trackId:e,status:t}={}){let n=await nn(),r=await hP({trackId:e,status:t});if(!Ee())return{runbooks:r,fleetDegraded:!1};let{records:o,source:s}=await je("runbooks");if(s!=="plane")return{runbooks:r,fleetDegraded:!0};let a=new Set(n.runbooks.map(c=>c.id)),i=o.filter(c=>!c.deletedAt&&c.data?.id&&!a.has(c.data.id)).map(c=>({...c.data,originNode:c.originNode||null,remote:!0})).filter(c=>(!e||c.trackId===e)&&(!t||c.status===t));return{runbooks:[...r,...i],fleetDegraded:!1}}async function Bp(e){let t=await wP(e);if(t)return t;if(!Ee())return null;let{records:n,source:r}=await je("runbooks");if(r!=="plane")return null;let o=n.find(s=>!s.deletedAt&&s.data?.id===e);return o?{...o.data,originNode:o.originNode||null,remote:!0}:null}async function dS(e,t){let n=await Zs("runbooks",e.id,t,"md");return typeof n=="string"?n:null}async function wP(e){let n=(await nn()).runbooks.find(r=>r.id===e);return n?{...n}:null}async function fS({trackId:e,trackName:t,name:n,md:r,cwd:o,box:s,agent:a}){if(!e)throw new Error("trackId required");if(typeof n!="string"||!n.trim())throw new Error("name (string) required");let i=lS(r),c=await nn(),l={id:dP().slice(0,8),trackId:e,trackName:t||e,box:s||null,agent:a||null,name:n.trim(),status:"open",version:1,versions:[],trackDeletedAt:null,cwd:o||null,createdAt:Date.now(),updatedAt:Date.now()};return await $n.mkdir(Tl,{recursive:!0}),await $n.writeFile(Rn(l,1),r),l.versions.push({v:1,mdRel:On.relative(no,Rn(l,1)),bytes:i,note:null,createdAt:Date.now()}),c.runbooks.push(l),await ro(),await fs(l,"created",{version:1}),El(l),Ja(qn("runbooks",l.id,1,"md",Rn(l,1))),{...l}}async function pS(e,{md:t,note:n}={}){let o=(await nn()).runbooks.find(i=>i.id===e);if(!o)throw new Error("runbook not found");mP(o,"update");let s=lS(t),a=o.version+1;return o.version=a,o.updatedAt=Date.now(),await $n.mkdir(Tl,{recursive:!0}),await $n.writeFile(Rn(o,a),t),o.versions.push({v:a,mdRel:On.relative(no,Rn(o,a)),bytes:s,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),await ro(),await fs(o,"updated",{version:a,...n?{note:String(n).slice(0,200)}:{}}),El(o),Ja(qn("runbooks",o.id,a,"md",Rn(o,a))),{...o}}async function mS(e,t){if(t!=="open"&&t!=="done")throw new Error('status must be "open" or "done"');let r=(await nn()).runbooks.find(o=>o.id===e);if(!r)throw new Error("runbook not found");return r.status===t?{...r}:(r.status=t,r.updatedAt=Date.now(),await ro(),await fs(r,t==="done"?"done":"reopened"),El(r),{...r})}async function hS(e){let t=await nn(),n=t.runbooks.findIndex(o=>o.id===e);if(n===-1)throw new Error("runbook not found");let r=t.runbooks[n];t.runbooks.splice(n,1);for(let o of r.versions||[])await $n.rm(On.join(no,o.mdRel),{force:!0}).catch(()=>{});return await ro(),r.trackDeletedAt||await fs(r,"deleted"),Ja($t("runbooks",r.id)),{ok:!0,id:e,name:r.name}}async function wS(e){let n=(await nn()).runbooks.filter(r=>r.trackId===e&&!r.trackDeletedAt);for(let r of n)r.trackDeletedAt=Date.now(),r.updatedAt=Date.now(),await fs(r,"orphaned"),r.cwd=null,El(r);return n.length&&await ro(),n.length}async function gS(e){let t=await nn(),n=t.runbooks.filter(r=>r.trackId===e);for(let r of n){await fs(r,"deleted");for(let o of r.versions||[])await $n.rm(On.join(no,o.mdRel),{force:!0}).catch(()=>{});Ja($t("runbooks",r.id))}return n.length&&(t.runbooks=t.runbooks.filter(r=>r.trackId!==e),await ro()),n.length}async function yS(){if(!Ee())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await je("runbooks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await nn();for(let r of n.runbooks){await et("runbooks",{...r},{trackId:r.trackId}).catch(()=>{});for(let o of r.versions||[])await qn("runbooks",r.id,o.v,"md",On.join(no,o.mdRel)).catch(()=>{})}return{pushed:n.runbooks.length,source:"plane"}}var no,iS,Tl,aS,fP,In,Dp,Ja,Al=O(()=>{Wn();ue();Kn();no=process.env.BOSTRAT_STATE_DIR||On.join(process.env.HOME||uP.tmpdir(),".bostrat"),iS=On.join(no,"runbooks.json"),Tl=On.join(no,"runbooks"),aS=256*1024,fP=[{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/}];In=null,Dp=null;Ja=e=>Promise.resolve(e).catch(()=>{})});import jp from"node:fs/promises";import Ya from"node:path";import{randomUUID as gP}from"node:crypto";function Fp(e){let t=String(e||"").toLowerCase().replace(/^\./,"");return yP.has(t)?"image":bP.has(t)?"doc":null}function kP(e){let r=Ya.basename(String(e||"")).replace(/[\x00-\x1f]/g,"").replace(/[^A-Za-z0-9._-]+/g,"_").replace(/^_+|_+$/g,"").slice(-80)||"file";return r.startsWith(".")?`f${r}`:r}async function xS(e,{filename:t,buffer:n}){if(!e)throw new Error("cwd required");if(!Buffer.isBuffer(n)||n.length===0)throw new Error("empty upload");if(n.length>bS)throw new Error(`file too large \u2014 max ${Math.floor(bS/(1024*1024))} MB`);let r=kP(t),o=Ya.extname(r).slice(1),s=Fp(o);if(!s)throw new Error(`unsupported file type "${o||"unknown"}" \u2014 attach an image or a document`);let a=gP().slice(0,8),i=Lp(e);await jp.mkdir(i,{recursive:!0});let c=`${a}-${r}`;return await jp.writeFile(Ya.join(i,c),n,{mode:384}),await jp.chmod(Ya.join(i,c),384).catch(()=>{}),{id:a,name:r,rel:`${kS}/${c}`,kind:s,size:n.length}}function SS(e){let t=e.map(r=>`\`${r}\``).join(", ");return`[Attached \u2014 please read ${e.length===1?"this file":`these ${e.length} files`}: ${t}]`}function Up(e){return e.role==="user"&&xP.test((e.text||"").trim())}var kS,Lp,bS,yP,bP,xP,Hp=O(()=>{kS=".bostrat/uploads",Lp=e=>Ya.join(e,kS),bS=Number(process.env.BOSTRAT_MAX_UPLOAD_BYTES)||24*1024*1024,yP=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","tif","tiff","heic","heif","avif","ico"]),bP=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"]);xP=/\[Attached — please read (?:this file|these \d+ files): [^\]]*\]$/});function oo(e,t,n=Date.now()){return t?e.idleSince==null?(e.idleSince=n,!1):n-e.idleSince>=6500:(e.idleSince=null,!1)}var vS=O(()=>{});import{execFile as SP}from"node:child_process";import{promisify as vP}from"node:util";function Wp(e){return`refs/bostrat/wip/${e}`}function AP(e,t=Date.now()){return`refs/bostrat/rescue/${e}-${t}`}function AS(e=process.env){let t=String(e.BOSTRAT_WIP_SYNC_MS??"").trim().toLowerCase();return t!=="0"&&t!=="off"&&t!=="false"}function _P(e=process.env){let t=Number(e.BOSTRAT_WIP_SYNC_MS);return Number.isFinite(t)&&t>0?t:EP}async function qp(e,{log:t=console}={}){let{id:n,cwd:r}=e??{};if(!n||!r)return{pushed:!1,reason:"no-workspace"};try{await hr(r,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await hr(r,["remote","get-url","origin"])}catch{return TS.has(r)||(TS.add(r),t.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 Wo(r,"bostrat: wip snapshot"),{stdout:s}=await hr(r,["rev-parse",`${o}^{tree}`]),a=s.trim();if(_l.get(r)===a)return{pushed:!1,reason:"unchanged"};let i=Wp(n);return await hr(r,["push","--force","origin",`${o}:${i}`],ES),_l.set(r,a),await _({id:n,cwd:r},{type:"code.pushed",actor:"orchestrator",payload:{ref:i,sha:o,wip:!0,ts:Date.now()}}).catch(()=>{}),t.log?.(`[wip-sync] ${n}: pushed ${o.slice(0,7)} \u2192 ${i}`),{pushed:!0,sha:o,ref:i}}catch(o){return t.log?.(`[wip-sync] ${n}: push failed (will retry): ${String(o?.message||o).split(`
155
- `)[0]}`),{pushed:!1,reason:"push-failed"}}}async function Kp(e,{log:t=console}={}){let{id:n,cwd:r}=e??{};if(!n||!r)return{pushed:!1,reason:"no-workspace"};try{await hr(r,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await hr(r,["remote","get-url","origin"])}catch{return{pushed:!1,reason:"no-origin"}}try{let o=await Wo(r,"bostrat: transfer rescue snapshot"),{stdout:s}=await hr(r,["rev-parse",`${o}^{tree}`]),a=s.trim();if(_l.get(r)===a)return{pushed:!1,reason:"unchanged"};let i=AP(n);return await hr(r,["push","origin",`${o}:${i}`],ES),_l.set(r,a),await _({id:n,cwd:r},{type:"code.pushed",actor:"orchestrator",payload:{ref:i,sha:o,rescue:!0,ts:Date.now()}}).catch(()=>{}),t.log?.(`[wip-sync] ${n}: rescued stranded work ${o.slice(0,7)} \u2192 ${i}`),{pushed:!0,sha:o,ref:i}}catch(o){return t.log?.(`[wip-sync] ${n}: rescue push failed: ${String(o?.message||o).split(`
156
- `)[0]}`),{pushed:!1,reason:"push-failed"}}}function _S({listTracks:e,sweepMs:t=_P(),log:n=console}){let r=!1,o=async()=>{if(!r){r=!0;try{let a=await e()??[];for(let i of a)i?.archivedAt||i?.kind==="setup"||i?.transferredTo||await qp(i,{log:n})}catch(a){n.log?.(`[wip-sync] sweep failed: ${a?.message||a}`)}finally{r=!1}}},s=setInterval(o,t);return s.unref?.(),o(),{stop:()=>clearInterval(s),cycle:o}}var TP,EP,ES,hr,_l,TS,Gp=O(()=>{Lc();ue();TP=vP(SP),EP=12e4,ES=6e4;hr=(e,t,n=15e3)=>TP("git",["-C",e,...t],{timeout:n,maxBuffer:4*1024*1024}),_l=new Map,TS=new Set});import IP from"node:fs";import Vp from"node:fs/promises";import RP from"node:path";function MP(e=process.env){return!!(ke(e)&&e.BOSTRAT_PLANE_TOKEN)}async function IS(e,{env:t=process.env,fetchImpl:n=(...o)=>fetch(...o),log:r=console}={}){let o=e?.id;if(!o)return{restored:!1,reason:"no track id"};if(!MP(t))return{restored:!1,reason:"plane not configured"};let s=So(e),a=RP.join(s,`${o}.ndjson`);try{if(IP.statSync(a).size>0)return{restored:!1,reason:"log not empty"}}catch{}let i=ke(t),c={authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`},l=[],u=0;for(;;){let d=new AbortController,p=setTimeout(()=>d.abort(),CP),m;try{m=await n(`${i}/v1/spine/${encodeURIComponent(o)}?after=${u}&limit=${$P}`,{headers:c,signal:d.signal})}finally{clearTimeout(p)}if(m.status===404)return{restored:!1,reason:"unknown to plane"};if(!m.ok)return{restored:!1,reason:`plane ${m.status}`};let h=await m.json();for(let g of h.events||[])l.push(JSON.stringify(g));if(l.length>OP)return{restored:!1,reason:"event count over safety cap"};if(h.next==null)break;u=h.next}if(!l.length)return{restored:!1,reason:"unknown to plane"};await Vp.mkdir(s,{recursive:!0});let f=`${a}.pull-${process.pid}-${Date.now()}`;return await Vp.writeFile(f,l.join(`
157
+ `)}`:t),this.name="MockRenderError"}},eo=null,Np=null;tn=e=>tt("mocks",{...e},{trackId:e.trackId}).catch(()=>{}),nn=(e,t,n)=>{let r=(e.versions||[]).find(s=>s.v===t),o=n==="mp4"||n==="webm"?Xa(e,r,"video"):r&&Xa(e,r,n)||(n==="html"?Et(e,t).html:null);return o?Kn("mocks",e.id,t,n,o).catch(()=>{}):Promise.resolve()};Ya=e=>De.join(e,".bostrat","mocks");uP=Buffer.from([137,80,78,71,13,10,26,10]);yP=gP,Pp=Promise.resolve()});import SP from"node:fs/promises";import eS from"node:path";import vP from"node:os";import{randomUUID as tS}from"node:crypto";async function In(){return _n||(Lp||=(async()=>{let e=!0;try{_n=JSON.parse(await SP.readFile(nS,"utf8"))}catch{_n={flows:[]},e=!1}finally{Lp=null}if(_n.flows||=[],!e&&Ae()){let{records:t,source:n}=await Fe("flows").catch(()=>({records:[],source:"error"}));if(n==="plane"){for(let r of t)!r.deletedAt&&r.data?.id&&_n.flows.push(r.data);_n.flows.length&&await ms().catch(()=>{})}}return _n})(),Lp)}async function ms(){await at(nS,_n)}function Fp(e,t,n={}){return _({id:e.trackId,cwd:e.cwd},{type:"flow.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,provider:e.agent||null,payload:{ts:Date.now(),change:t,flowId:e.id,name:e.name,stepCount:e.steps.length,mockIds:[...new Set(e.steps.map(r=>r.mockId))],...n}}).catch(()=>{})}async function rS({trackId:e,steps:t,prevSteps:n=[]}){if(!Array.isArray(t)||t.length<1||t.length>X0)throw new Error(`steps must be an array of 1-${X0}`);let r=await Za({trackId:e}),o=[...n],s=[];for(let i=0;i<t.length;i++){let c=t[i]||{},l=`step ${i+1}`,u=typeof c.caption=="string"?c.caption.trim():"";if(!u)throw new Error(`${l}: caption (string) required`);if(u.length>Z0)throw new Error(`${l}: caption over ${Z0} chars`);let f=c.title==null?null:String(c.title).trim()||null;if(f&&f.length>Q0)throw new Error(`${l}: title over ${Q0} chars`);let d=String(c.mock??"").trim().replace(/^mock:/,"");if(!d)throw new Error(`${l}: mock (name or id) required`);let p=r.filter(k=>k.id===d);if(p.length||(p=r.filter(k=>k.name.toLowerCase()===d.toLowerCase())),!p.length)throw new Error(`${l}: no mock matching "${d}" in this Track \u2014 see \`bostrat-mock ls\``);if(p.length>1)throw new Error(`${l}: "${d}" is ambiguous (${p.map(k=>`mock:${k.id}`).join(", ")}) \u2014 use the id`);let m=p[0],h=null;if(c.v!=null&&(h=Number(c.v),!Number.isInteger(h)||!(m.versions||[]).some(k=>k.v===h)))throw new Error(`${l}: "${m.name}" has no captured v${c.v} to pin`);let g=o.findIndex(k=>k.mockId===m.id),x=g>=0?o.splice(g,1)[0].id:tS().slice(0,8);s.push({id:x,mockId:m.id,caption:u,title:f,v:h})}let a={};for(let i of s)i.mockId in a||(a[i.mockId]=r.find(c=>c.id===i.mockId)?.readyVersion??null);return{steps:s,resolved:a}}function EP(e){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");if(e.trim().length>Y0)throw new Error(`name over ${Y0} chars`);return e.trim()}async function oS({trackId:e}={}){let t=await In();return(e?t.flows.filter(r=>r.trackId===e):t.flows).map(r=>({...r}))}async function AP(e){let n=(await In()).flows.find(r=>r.id===e);return n?{...n}:null}async function sS(e){let t=await AP(e);if(!t)return null;let n=new Map((await Za({trackId:t.trackId})).map(r=>[r.id,r]));return t.steps=t.steps.map(r=>{let o=n.get(r.mockId);if(!o)return{...r,missing:!0,mockName:null,mockState:null,servedV:null,width:null,height:null};let s=Bt(o,r.v);return{...r,missing:!1,mockName:o.name,mockState:o.state,servedV:s?.v??null,width:s?.width??null,height:s?.height??null}}),t}async function aS({trackId:e,name:t,steps:n,cwd:r,box:o,agent:s}){if(!e)throw new Error("trackId required");if(!r)throw new Error("cwd required");let a=EP(t),i=await In(),c=i.flows.find(p=>p.trackId===e&&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 rS({trackId:e,steps:n}),f=Date.now(),d={id:tS().slice(0,8),trackId:e,box:o||null,agent:s||null,name:a,cwd:r,version:1,versions:[{v:1,steps:l,resolved:u,note:null,createdAt:f}],steps:l,createdAt:f,updatedAt:f};return i.flows.push(d),await ms(),await Fp(d,"created"),_l(d),{...d}}async function iS(e,{steps:t,note:n}={}){let o=(await In()).flows.find(i=>i.id===e);if(!o)throw new Error("flow not found");let{steps:s,resolved:a}=await rS({trackId:o.trackId,steps:t,prevSteps:o.steps});return o.version+=1,o.versions.push({v:o.version,steps:s,resolved:a,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),o.steps=s,o.updatedAt=Date.now(),await ms(),await Fp(o,"updated",{version:o.version,...n?{note:String(n).slice(0,200)}:{}}),_l(o),{...o}}async function cS(e){let t=await In(),n=t.flows.findIndex(o=>o.id===e);if(n===-1)throw new Error("flow not found");let r=t.flows[n];return t.flows.splice(n,1),await ms(),await Fp(r,"deleted"),$t("flows",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function lS(e){return(await In()).flows.filter(n=>n.steps.some(r=>r.mockId===e)).map(n=>({...n}))}async function uS(e){let n=(await In()).flows.filter(r=>r.trackId===e.id);for(let r of n)r.trackDeletedAt=Date.now(),r.trackName=e.name||e.id,r.updatedAt=Date.now(),_l(r);return n.length&&await ms(),n.length}async function dS(e){let t=await In(),n=t.flows.filter(r=>r.trackId===e);if(n.length){t.flows=t.flows.filter(r=>r.trackId!==e),await ms();for(let r of n)$t("flows",r.id).catch(()=>{})}return n.length}async function fS(){if(!Ae())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await Fe("flows");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await In();for(let r of n.flows)await _l(r);return{pushed:n.flows.length,source:"plane"}}var TP,nS,X0,Y0,Z0,Q0,_n,Lp,_l,Up=C(()=>{ue();qn();ps();Gn();TP=process.env.BOSTRAT_STATE_DIR||eS.join(process.env.HOME||vP.tmpdir(),".bostrat"),nS=eS.join(TP,"flows.json"),X0=20,Y0=80,Z0=500,Q0=80,_n=null,Lp=null;_l=e=>tt("flows",{...e},{trackId:e.trackId}).catch(()=>{})});import On from"node:fs/promises";import Cn from"node:path";import _P from"node:os";import{randomUUID as IP}from"node:crypto";function Qa(e){return RP.filter(({re:t})=>t.test(e)).map(({label:t})=>t)}async function on(){return Rn||(Hp||=(async()=>{let e=!0;try{Rn=JSON.parse(await On.readFile(mS,"utf8"))}catch{Rn={runbooks:[]},e=!1}finally{Hp=null}return Rn.runbooks||=[],!e&&Ae()&&await $P().catch(()=>{}),Rn})(),Hp)}async function no(){await at(mS,Rn)}function Rl(e){return ei(tt("runbooks",{...e},{trackId:e.trackId}))}async function $P(){let{records:e,source:t}=await Fe("runbooks");if(!(t!=="plane"||!e.length)){await On.mkdir(Il,{recursive:!0});for(let n of e){if(n.deletedAt||!n.data?.id)continue;let r=n.data;for(let o of r.versions||[]){let s=await na("runbooks",r.id,o.v,"md");typeof s=="string"&&await On.writeFile($n(r,o.v),s).catch(()=>{})}Rn.runbooks.push(r)}Rn.runbooks.length&&await no()}}function hs(e,t,n={}){return _({id:e.trackId,cwd:e.cwd},{type:"runbook.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,provider:e.agent||null,payload:{ts:Date.now(),change:t,runbookId:e.id,name:e.name,status:e.status,...n}}).catch(()=>{})}function $n(e,t){return Cn.join(Il,`${e.id}.v${t}.md`)}function hS(e,t=null){let n=e.versions||[];return t!=null?n.find(r=>r.v===Number(t))||null:n.length?n[n.length-1]:null}function wS(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Buffer.byteLength(e,"utf8");if(t>pS)throw new Error(`runbook is ${Math.round(t/1024)} KB \u2014 over the ${pS/1024} KB cap; a doc that size belongs in the repo, not a runbook`);let n=Qa(e);if(n.length)throw new Error(`runbook appears to contain a secret VALUE (${n.join(", ")}) \u2014 runbooks ship off-box; name the secret and where it goes, never its value. Replace it with a placeholder like <your key> and retry.`);return t}function OP(e,t){if(e.trackDeletedAt)throw new Error(`runbook is orphaned (its Track was deleted) \u2014 cannot ${t} it`)}async function CP({trackId:e,status:t}={}){let n=await on(),r=e?n.runbooks.filter(o=>o.trackId===e):n.runbooks;return t&&(r=r.filter(o=>o.status===t)),r.map(o=>({...o}))}async function gS({trackId:e,status:t}={}){let n=await on(),r=await CP({trackId:e,status:t});if(!Ae())return{runbooks:r,fleetDegraded:!1};let{records:o,source:s}=await Fe("runbooks");if(s!=="plane")return{runbooks:r,fleetDegraded:!0};let a=new Set(n.runbooks.map(c=>c.id)),i=o.filter(c=>!c.deletedAt&&c.data?.id&&!a.has(c.data.id)).map(c=>({...c.data,originNode:c.originNode||null,remote:!0})).filter(c=>(!e||c.trackId===e)&&(!t||c.status===t));return{runbooks:[...r,...i],fleetDegraded:!1}}async function Wp(e){let t=await MP(e);if(t)return t;if(!Ae())return null;let{records:n,source:r}=await Fe("runbooks");if(r!=="plane")return null;let o=n.find(s=>!s.deletedAt&&s.data?.id===e);return o?{...o.data,originNode:o.originNode||null,remote:!0}:null}async function yS(e,t){let n=await na("runbooks",e.id,t,"md");return typeof n=="string"?n:null}async function MP(e){let n=(await on()).runbooks.find(r=>r.id===e);return n?{...n}:null}async function bS({trackId:e,trackName:t,name:n,md:r,cwd:o,box:s,agent:a}){if(!e)throw new Error("trackId required");if(typeof n!="string"||!n.trim())throw new Error("name (string) required");let i=wS(r),c=await on(),l={id:IP().slice(0,8),trackId:e,trackName:t||e,box:s||null,agent:a||null,name:n.trim(),status:"open",version:1,versions:[],trackDeletedAt:null,cwd:o||null,createdAt:Date.now(),updatedAt:Date.now()};return await On.mkdir(Il,{recursive:!0}),await On.writeFile($n(l,1),r),l.versions.push({v:1,mdRel:Cn.relative(to,$n(l,1)),bytes:i,note:null,createdAt:Date.now()}),c.runbooks.push(l),await no(),await hs(l,"created",{version:1}),Rl(l),ei(Kn("runbooks",l.id,1,"md",$n(l,1))),{...l}}async function kS(e,{md:t,note:n}={}){let o=(await on()).runbooks.find(i=>i.id===e);if(!o)throw new Error("runbook not found");OP(o,"update");let s=wS(t),a=o.version+1;return o.version=a,o.updatedAt=Date.now(),await On.mkdir(Il,{recursive:!0}),await On.writeFile($n(o,a),t),o.versions.push({v:a,mdRel:Cn.relative(to,$n(o,a)),bytes:s,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),await no(),await hs(o,"updated",{version:a,...n?{note:String(n).slice(0,200)}:{}}),Rl(o),ei(Kn("runbooks",o.id,a,"md",$n(o,a))),{...o}}async function xS(e,t){if(t!=="open"&&t!=="done")throw new Error('status must be "open" or "done"');let r=(await on()).runbooks.find(o=>o.id===e);if(!r)throw new Error("runbook not found");return r.status===t?{...r}:(r.status=t,r.updatedAt=Date.now(),await no(),await hs(r,t==="done"?"done":"reopened"),Rl(r),{...r})}async function SS(e){let t=await on(),n=t.runbooks.findIndex(o=>o.id===e);if(n===-1)throw new Error("runbook not found");let r=t.runbooks[n];t.runbooks.splice(n,1);for(let o of r.versions||[])await On.rm(Cn.join(to,o.mdRel),{force:!0}).catch(()=>{});return await no(),r.trackDeletedAt||await hs(r,"deleted"),ei($t("runbooks",r.id)),{ok:!0,id:e,name:r.name}}async function vS(e){let n=(await on()).runbooks.filter(r=>r.trackId===e&&!r.trackDeletedAt);for(let r of n)r.trackDeletedAt=Date.now(),r.updatedAt=Date.now(),await hs(r,"orphaned"),r.cwd=null,Rl(r);return n.length&&await no(),n.length}async function TS(e){let t=await on(),n=t.runbooks.filter(r=>r.trackId===e);for(let r of n){await hs(r,"deleted");for(let o of r.versions||[])await On.rm(Cn.join(to,o.mdRel),{force:!0}).catch(()=>{});ei($t("runbooks",r.id))}return n.length&&(t.runbooks=t.runbooks.filter(r=>r.trackId!==e),await no()),n.length}async function ES(){if(!Ae())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await Fe("runbooks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await on();for(let r of n.runbooks){await tt("runbooks",{...r},{trackId:r.trackId}).catch(()=>{});for(let o of r.versions||[])await Kn("runbooks",r.id,o.v,"md",Cn.join(to,o.mdRel)).catch(()=>{})}return{pushed:n.runbooks.length,source:"plane"}}var to,mS,Il,pS,RP,Rn,Hp,ei,$l=C(()=>{qn();ue();Gn();to=process.env.BOSTRAT_STATE_DIR||Cn.join(process.env.HOME||_P.tmpdir(),".bostrat"),mS=Cn.join(to,"runbooks.json"),Il=Cn.join(to,"runbooks"),pS=256*1024,RP=[{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/}];Rn=null,Hp=null;ei=e=>Promise.resolve(e).catch(()=>{})});import qp from"node:fs/promises";import ti from"node:path";import{randomUUID as NP}from"node:crypto";function Gp(e){let t=String(e||"").toLowerCase().replace(/^\./,"");return PP.has(t)?"image":DP.has(t)?"doc":null}function BP(e){let r=ti.basename(String(e||"")).replace(/[\x00-\x1f]/g,"").replace(/[^A-Za-z0-9._-]+/g,"_").replace(/^_+|_+$/g,"").slice(-80)||"file";return r.startsWith(".")?`f${r}`:r}async function IS(e,{filename:t,buffer:n}){if(!e)throw new Error("cwd required");if(!Buffer.isBuffer(n)||n.length===0)throw new Error("empty upload");if(n.length>AS)throw new Error(`file too large \u2014 max ${Math.floor(AS/(1024*1024))} MB`);let r=BP(t),o=ti.extname(r).slice(1),s=Gp(o);if(!s)throw new Error(`unsupported file type "${o||"unknown"}" \u2014 attach an image or a document`);let a=NP().slice(0,8),i=Kp(e);await qp.mkdir(i,{recursive:!0});let c=`${a}-${r}`;return await qp.writeFile(ti.join(i,c),n,{mode:384}),await qp.chmod(ti.join(i,c),384).catch(()=>{}),{id:a,name:r,rel:`${_S}/${c}`,kind:s,size:n.length}}function RS(e){let t=e.map(r=>`\`${r}\``).join(", ");return`[Attached \u2014 please read ${e.length===1?"this file":`these ${e.length} files`}: ${t}]`}function Vp(e){return e.role==="user"&&jP.test((e.text||"").trim())}var _S,Kp,AS,PP,DP,jP,zp=C(()=>{_S=".bostrat/uploads",Kp=e=>ti.join(e,_S),AS=Number(process.env.BOSTRAT_MAX_UPLOAD_BYTES)||24*1024*1024,PP=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","tif","tiff","heic","heif","avif","ico"]),DP=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"]);jP=/\[Attached — please read (?:this file|these \d+ files): [^\]]*\]$/});function ro(e,t,n=Date.now()){return t?e.idleSince==null?(e.idleSince=n,!1):n-e.idleSince>=6500:(e.idleSince=null,!1)}var $S=C(()=>{});import{execFile as LP}from"node:child_process";import{promisify as FP}from"node:util";function Jp(e){return`refs/bostrat/wip/${e}`}function WP(e,t=Date.now()){return`refs/bostrat/rescue/${e}-${t}`}function MS(e=process.env){let t=String(e.BOSTRAT_WIP_SYNC_MS??"").trim().toLowerCase();return t!=="0"&&t!=="off"&&t!=="false"}function qP(e=process.env){let t=Number(e.BOSTRAT_WIP_SYNC_MS);return Number.isFinite(t)&&t>0?t:HP}async function Xp(e,{log:t=console}={}){let{id:n,cwd:r}=e??{};if(!n||!r)return{pushed:!1,reason:"no-workspace"};try{await hr(r,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await hr(r,["remote","get-url","origin"])}catch{return OS.has(r)||(OS.add(r),t.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 Go(r,"bostrat: wip snapshot"),{stdout:s}=await hr(r,["rev-parse",`${o}^{tree}`]),a=s.trim();if(Ol.get(r)===a)return{pushed:!1,reason:"unchanged"};let i=Jp(n);return await hr(r,["push","--force","origin",`${o}:${i}`],CS),Ol.set(r,a),await _({id:n,cwd:r},{type:"code.pushed",actor:"orchestrator",payload:{ref:i,sha:o,wip:!0,ts:Date.now()}}).catch(()=>{}),t.log?.(`[wip-sync] ${n}: pushed ${o.slice(0,7)} \u2192 ${i}`),{pushed:!0,sha:o,ref:i}}catch(o){return t.log?.(`[wip-sync] ${n}: push failed (will retry): ${String(o?.message||o).split(`
158
+ `)[0]}`),{pushed:!1,reason:"push-failed"}}}async function Yp(e,{log:t=console}={}){let{id:n,cwd:r}=e??{};if(!n||!r)return{pushed:!1,reason:"no-workspace"};try{await hr(r,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await hr(r,["remote","get-url","origin"])}catch{return{pushed:!1,reason:"no-origin"}}try{let o=await Go(r,"bostrat: transfer rescue snapshot"),{stdout:s}=await hr(r,["rev-parse",`${o}^{tree}`]),a=s.trim();if(Ol.get(r)===a)return{pushed:!1,reason:"unchanged"};let i=WP(n);return await hr(r,["push","origin",`${o}:${i}`],CS),Ol.set(r,a),await _({id:n,cwd:r},{type:"code.pushed",actor:"orchestrator",payload:{ref:i,sha:o,rescue:!0,ts:Date.now()}}).catch(()=>{}),t.log?.(`[wip-sync] ${n}: rescued stranded work ${o.slice(0,7)} \u2192 ${i}`),{pushed:!0,sha:o,ref:i}}catch(o){return t.log?.(`[wip-sync] ${n}: rescue push failed: ${String(o?.message||o).split(`
159
+ `)[0]}`),{pushed:!1,reason:"push-failed"}}}function NS({listTracks:e,sweepMs:t=qP(),log:n=console}){let r=!1,o=async()=>{if(!r){r=!0;try{let a=await e()??[];for(let i of a)i?.archivedAt||i?.kind==="setup"||i?.transferredTo||await Xp(i,{log:n})}catch(a){n.log?.(`[wip-sync] sweep failed: ${a?.message||a}`)}finally{r=!1}}},s=setInterval(o,t);return s.unref?.(),o(),{stop:()=>clearInterval(s),cycle:o}}var UP,HP,CS,hr,Ol,OS,Zp=C(()=>{Wc();ue();UP=FP(LP),HP=12e4,CS=6e4;hr=(e,t,n=15e3)=>UP("git",["-C",e,...t],{timeout:n,maxBuffer:4*1024*1024}),Ol=new Map,OS=new Set});import KP from"node:fs";import Qp from"node:fs/promises";import GP from"node:path";function XP(e=process.env){return!!(ke(e)&&e.BOSTRAT_PLANE_TOKEN)}async function PS(e,{env:t=process.env,fetchImpl:n=(...o)=>fetch(...o),log:r=console}={}){let o=e?.id;if(!o)return{restored:!1,reason:"no track id"};if(!XP(t))return{restored:!1,reason:"plane not configured"};let s=So(e),a=GP.join(s,`${o}.ndjson`);try{if(KP.statSync(a).size>0)return{restored:!1,reason:"log not empty"}}catch{}let i=ke(t),c={authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`},l=[],u=0;for(;;){let d=new AbortController,p=setTimeout(()=>d.abort(),JP),m;try{m=await n(`${i}/v1/spine/${encodeURIComponent(o)}?after=${u}&limit=${VP}`,{headers:c,signal:d.signal})}finally{clearTimeout(p)}if(m.status===404)return{restored:!1,reason:"unknown to plane"};if(!m.ok)return{restored:!1,reason:`plane ${m.status}`};let h=await m.json();for(let g of h.events||[])l.push(JSON.stringify(g));if(l.length>zP)return{restored:!1,reason:"event count over safety cap"};if(h.next==null)break;u=h.next}if(!l.length)return{restored:!1,reason:"unknown to plane"};await Qp.mkdir(s,{recursive:!0});let f=`${a}.pull-${process.pid}-${Date.now()}`;return await Qp.writeFile(f,l.join(`
157
160
  `)+`
158
- `),await Vp.rename(f,a),r.log?.(`[spine-pull] rehydrated ${o}: ${l.length} event(s) \u2192 ${a}`),{restored:!0,rows:l.length}}var $P,OP,CP,RS=O(()=>{Qe();ue();$P=1e3,OP=5e5,CP=3e4});var cv={};$u(cv,{HANDOFF_LATEST_REL:()=>so,KNOWN_AGENTS:()=>ii,TRACK_NAME_MAX:()=>im,addTrackRepo:()=>Sm,adoptTrack:()=>Lm,agentAvailability:()=>Ol,announceNodeUpdate:()=>on,answerFullscreenOffer:()=>Cm,answerPrompt:()=>Ml,archiveTrack:()=>io,archiveTrackForMergedPr:()=>kn,augmentFirstPromptAfterHandoff:()=>LS,buildAgentCmd:()=>BS,canResumeSubtask:()=>sv,cancelQueued:()=>ui,cancelQueuedToDraft:()=>hm,cancelStopJob:()=>di,cancelSubtask:()=>Wl,changedRepos:()=>as,commitTransferOut:()=>Ul,createSetupTrack:()=>Em,createTrack:()=>Dl,deleteTrack:()=>_m,demoteTransferredTracks:()=>jm,ensureLeadEpochs:()=>Ll,forceMergeSubtask:()=>Wm,getHandoffJob:()=>xs,getSubtaskJob:()=>DD,getTrack:()=>ne,getTransferOutJob:()=>Pm,healDeadLead:()=>si,interruptLead:()=>Pl,isArchiving:()=>AD,isHandoffNoteEcho:()=>rm,isInterruptEcho:()=>om,isModelSwitchEcho:()=>sm,leadCliDead:()=>Im,listSubtaskJobs:()=>co,listTracks:()=>ae,matchTranscriptsToBoxes:()=>HS,mergeNotifyMessage:()=>tv,navigatePrompt:()=>mm,notifyTrackForMergedPr:()=>xn,notifyTrackForResolvedPr:()=>Bl,pendingOffers:()=>fm,queueShipCompleteNotify:()=>gm,queuedMessages:()=>ao,reapArchivedOrphans:()=>Om,reconcileHandoffOutcome:()=>nv,reconcileInterruptedHandoffs:()=>Nm,reconcileInterruptedSubtasks:()=>Fm,reconcileSubtaskOutcome:()=>ov,refreshStandingInstructions:()=>Tm,refuseIfTransferred:()=>Bm,rehydrateLead:()=>pi,removeTrackRepo:()=>vm,renameTrack:()=>$m,reposOf:()=>gt,resolveTrackBox:()=>La,resolveTrackBoxByHookToken:()=>dm,restartLead:()=>jl,resumeAgentCmd:()=>um,sayToLead:()=>It,sendOptionsForAgent:()=>Gt,setTrackDraft:()=>km,setTrackModel:()=>xm,startLeadHandoff:()=>Fl,startSpinUpView:()=>ym,startSubtask:()=>Hm,startTransferOut:()=>Dm,stopJobActive:()=>KS,subtaskMessages:()=>pm,trackMessages:()=>Cl,unarchiveTrack:()=>Rm});import W from"node:fs/promises";import G from"node:path";import{randomUUID as ks}from"node:crypto";import{execFile as NP}from"node:child_process";import{promisify as PP}from"node:util";function BS(e,{skipPermissions:t=!0}={}){let n=$l[e];if(!n)throw new Error(`unknown agent "${e}"`);let r=process.env[n.envVar];return r||(t&&n.skipFlag?`${n.base} ${n.skipFlag}`:n.base)}function um(e,t,{skipPermissions:n=!0,cwd:r=null,peerName:o=null}={}){let s=$l[e];if(!s)throw new Error(`unknown agent "${e}"`);let a=process.env[s.envVar];if(a)return a;let i=n&&s.skipFlag?` ${s.skipFlag}`:"";switch(e){case"claude":{if(!t)return`${s.base}${i}`;if(r&&!Mt(r,t)){let c=o&&_e(o)?` --name ${o}`:"";return`${s.base} --session-id ${t}${c}${i}`}return`${s.base} --resume ${t}${i}`}case"cursor":return`${s.base} --continue${i}`;case"codex":return`${s.base} resume --last${i}`;default:return`${s.base}${i}`}}function ci(e){let t=$l[e];if(t)return process.env[t.envVar]||t.base}async function Ol({maxAgeMs:e=6e4}={}){if(wr.value&&Date.now()-wr.at<e)return wr.value;let t=wr.value,n=await Promise.all(ii.map(async r=>{let o=await dc(ci(r),{retries:[]});return o===Io?[r,t?.[r]??!0]:[r,o===uc]}));return wr.value=Object.fromEntries(n),wr.at=Date.now(),wr.value}async function li(e,t=!0){let n=BS(e,{skipPermissions:t});if(await dc(n)===_o){wr.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.":od[r]?`Install it on this node: ${od[r]}`:"Its CLI must be installed and on PATH first.";throw new Error(`agent "${e}" isn't available on this box (command not found: ${r}). ${o}`)}return n}function LS(e,t=so){return`${e.trim()}
161
+ `),await Qp.rename(f,a),r.log?.(`[spine-pull] rehydrated ${o}: ${l.length} event(s) \u2192 ${a}`),{restored:!0,rows:l.length}}var VP,zP,JP,DS=C(()=>{et();ue();VP=1e3,zP=5e5,JP=3e4});var hv={};Nu(hv,{HANDOFF_LATEST_REL:()=>oo,KNOWN_AGENTS:()=>fi,TRACK_NAME_MAX:()=>fm,addTrackRepo:()=>_m,adoptTrack:()=>qm,agentAvailability:()=>Pl,announceNodeUpdate:()=>an,answerFullscreenOffer:()=>Bm,answerPrompt:()=>Bl,archiveTrack:()=>io,archiveTrackForMergedPr:()=>xn,augmentFirstPromptAfterHandoff:()=>GS,buildAgentCmd:()=>qS,canResumeSubtask:()=>fv,cancelQueued:()=>mi,cancelQueuedToDraft:()=>km,cancelStopJob:()=>hi,cancelSubtask:()=>Vl,changedRepos:()=>ls,commitTransferOut:()=>Kl,createSetupTrack:()=>$m,createTrack:()=>Fl,deleteTrack:()=>Cm,demoteTransferredTracks:()=>Wm,ensureLeadEpochs:()=>Wl,forceMergeSubtask:()=>zm,getHandoffJob:()=>Es,getSubtaskJob:()=>YD,getTrack:()=>ne,getTransferOutJob:()=>Fm,healDeadLead:()=>ui,interruptLead:()=>Ll,isArchiving:()=>UD,isHandoffNoteEcho:()=>cm,isInterruptEcho:()=>lm,isModelSwitchEcho:()=>um,leadCliDead:()=>Mm,listSubtaskJobs:()=>co,listTracks:()=>ae,matchTranscriptsToBoxes:()=>JS,mergeNotifyMessage:()=>cv,navigatePrompt:()=>bm,notifyTrackForMergedPr:()=>Sn,notifyTrackForResolvedPr:()=>Ul,pendingOffers:()=>gm,queueShipCompleteNotify:()=>Sm,queuedMessages:()=>so,reapArchivedOrphans:()=>Dm,reconcileHandoffOutcome:()=>lv,reconcileInterruptedHandoffs:()=>Lm,reconcileInterruptedSubtasks:()=>Km,reconcileSubtaskOutcome:()=>dv,refreshStandingInstructions:()=>Rm,refuseIfTransferred:()=>Hm,rehydrateLead:()=>gi,removeTrackRepo:()=>Im,renameTrack:()=>Pm,reposOf:()=>gt,resolveTrackBox:()=>qa,resolveTrackBoxByHookToken:()=>wm,restartLead:()=>Hl,resumeAgentCmd:()=>hm,sayToLead:()=>It,sendOptionsForAgent:()=>zt,setTrackDraft:()=>Em,setTrackModel:()=>Am,startLeadHandoff:()=>ql,startSpinUpView:()=>vm,startSubtask:()=>Vm,startTransferOut:()=>Um,stopJobActive:()=>ZS,subtaskMessages:()=>ym,trackMessages:()=>Dl,unarchiveTrack:()=>Nm});import W from"node:fs/promises";import G from"node:path";import{randomUUID as vs}from"node:crypto";import{execFile as YP}from"node:child_process";import{promisify as ZP}from"node:util";function qS(e,{skipPermissions:t=!0}={}){let n=Nl[e];if(!n)throw new Error(`unknown agent "${e}"`);let r=process.env[n.envVar];return r||(t&&n.skipFlag?`${n.base} ${n.skipFlag}`:n.base)}function hm(e,t,{skipPermissions:n=!0,cwd:r=null,peerName:o=null}={}){let s=Nl[e];if(!s)throw new Error(`unknown agent "${e}"`);let a=process.env[s.envVar];if(a)return a;let i=n&&s.skipFlag?` ${s.skipFlag}`:"";switch(e){case"claude":{if(!t)return`${s.base}${i}`;if(r&&!Mt(r,t)){let c=o&&_e(o)?` --name ${o}`:"";return`${s.base} --session-id ${t}${c}${i}`}return`${s.base} --resume ${t}${i}`}case"cursor":return`${s.base} --continue${i}`;case"codex":return`${s.base} resume --last${i}`;default:return`${s.base}${i}`}}function Ts(e){let t=Nl[e];if(t)return process.env[t.envVar]||t.base}async function Pl({maxAgeMs:e=6e4}={}){if(wr.value&&Date.now()-wr.at<e)return wr.value;let t=wr.value,n=await Promise.all(fi.map(async r=>{let o=await hc(Ts(r),{retries:[]});return o===Io?[r,t?.[r]??!0]:[r,o===mc]}));return wr.value=Object.fromEntries(n),wr.at=Date.now(),wr.value}async function pi(e,t=!0){let n=qS(e,{skipPermissions:t});if(await hc(n)===_o){wr.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.":cd[r]?`Install it on this node: ${cd[r]}`:"Its CLI must be installed and on PATH first.";throw new Error(`agent "${e}" isn't available on this box (command not found: ${r}). ${o}`)}return n}function GS(e,t=oo){return`${e.trim()}
159
162
 
160
- (Read ${t} for handoff context from the prior lead \u2014 you are now the lead; none of the prior chat is in your context. Then respond to the user above.)`}function rm(e){return e.role==="user"&&jP.test((e.text||"").trim())}async function z(){return At||(zp||=(async()=>{try{At=JSON.parse(await W.readFile(DS,"utf8"))}catch{At={tracks:[]}}finally{zp=null}return At})(),zp)}async function X(){await at(DS,At)}function UP(e,t){let n=JSON.stringify({trackId:e,...t})+`
161
- `;return Jp=Jp.then(()=>W.mkdir(rn,{recursive:!0})).then(()=>W.appendFile(DP,n)).catch(()=>{}),Jp}async function on({current:e,latest:t,min:n=null,installKind:r=null,required:o=!1,status:s="available",policy:a=null,error:i=null,reason:c=null}={}){if(!t)return{announced:0};if(s==="available"){let f=null;try{f=JSON.parse(await W.readFile(Yp,"utf8"))}catch{}if(f?.latest===t&&f?.current===e)return{announced:0,deduped:!0}}let l=await z(),u=0;for(let f of l.tracks)f.archivedAt||f.transferredTo||!f.leadBox||(he(f,"node-update",{status:s,current:e??null,latest:t,...n?{min:n}:{},...r?{installKind:r}:{},...a?{policy:a}:{},...i?{error:String(i).slice(0,400)}:{},...c?{reason:c}:{},required:o===!0}),u++);if(await X().catch(()=>{}),s==="available")try{await W.mkdir(G.dirname(Yp),{recursive:!0}),await W.writeFile(Yp,JSON.stringify({current:e,latest:t,at:Date.now()}))}catch{}return{announced:u}}function FS(e){if(!e)return null;let t=typeof e=="string"?[e]:Array.isArray(e?.codes)&&e.codes.length?e.codes:e?.code?[e.code]:[],n=[...new Set(t.filter(s=>HP.has(s)))];if(!n.length)return null;let r=typeof e=="object"?e?.note:null,o=r&&String(r).slice(0,500).trim()||null;return{code:n[0],...n.length>1?{codes:n}:{},note:o}}async function US(e,t,n,{kind:r}={}){let o=await se(t);if(!o)throw new Error(`box "${t}" is not running`);let s=ci(o.agent);await Xn({cwd:o.cwd,sessionId:o.sessionId,sessionName:t,agent:o.agent,agentCmd:s}),await Fe(t,n,{...Gt(o.agent,n),kind:r||"orchestration"}),await Y({flow:"orchestration",phase:"sent",trackId:e,sessionName:t,agent:o.agent,kind:r||"orchestration",promptHead:n.slice(0,160)});let a=await z(),i=re(a,e);if(!i)return;let c=i.boxes.find(l=>l.name===t);he(i,"orchestration-prompt",{box:t,agent:c?.agent||o.agent,boxRole:c?.role,prompt:n,kind:r||"orchestration"}),await X()}async function WP(e){let t=G.join(So(e),`${e.id}.ndjson`),n;try{n=await W.stat(t)}catch{return null}let r=$S.get(e.id);if(r&&r.mtimeMs===n.mtimeMs)return r.at;let o=null;for(let s of await L(e)){if(s.type!=="turn.agent")continue;let a=s.payload?.ts??s.ts;a&&(!o||a>o)&&(o=a)}return $S.set(e.id,{mtimeMs:n.mtimeMs,at:o}),o}async function qP(e,t){let n=t.find(r=>r.name===e.leadBox);return n?.state!=="live"?{working:!1,prompted:!1}:Jf(n.name,n.agent)}async function _t(e,t=null){let n=t??new Map((await Ot()).map(i=>[i.name,i])),r=e.boxes.map(i=>{let c=n.get(i.name),l=Mn.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([WP(e),qP(e,r)]);return{...e,boxes:r,lastResponseAt:o,working:s,prompted:a,archiving:oi.has(e.id)}}function HS(e,t,n){let r=[...e].sort((l,u)=>l.createdAt-u.createdAt),o=[...t].sort((l,u)=>l.birthMs-u.birthMs),s=new Set,a=[];for(let l of r)l.sessionId&&n(l.sessionId)&&!s.has(l.sessionId)?s.add(l.sessionId):a.push(l);let i=new Map(r.map((l,u)=>[l,u])),c=[];for(let l of a){if(l.sessionId&&n(l.sessionId)){c.push({box:l.name,sessionId:null});continue}if(!l.sessionId||l.pinned)continue;let u=i.get(l),f=l.createdAt-KP,d=r[u+1]?.createdAt??1/0,p=o.find(m=>!s.has(m.id)&&m.birthMs>=f&&m.birthMs<d);p&&(s.add(p.id),c.push({box:l.name,sessionId:p.id}))}return c}async function WS(e){let t=new Map;for(let r of e.tracks)for(let o of r.boxes)o.agent==="claude"&&o.cwd&&(t.has(o.cwd)||t.set(o.cwd,[]),t.get(o.cwd).push({track:r,box:o}));let n=!1;for(let[r,o]of t){let s=o.map(d=>d.box.sessionId),a=wg(r),i=new Set(a.map(d=>d.id)),c=s.every(d=>d&&i.has(d)),l=new Set(s).size===s.length;if(c&&l)continue;let u=o.map(d=>d.box),f=HS(u,a,d=>i.has(d));for(let d of f){let p=u.find(m=>m.name===d.box);p&&(p.sessionId=d.sessionId),await ig(d.box,d.sessionId),n=!0}}return n}async function ae(){let e=await z();await WS(e)&&await X();let t=new Map((await Ot()).map(n=>[n.name,n]));return Promise.all(e.tracks.map(n=>_t(n,t)))}async function La(e,t){let n=await z();if(e)for(let r of n.tracks||[]){let o=r.boxes.find(s=>s.sessionId&&s.sessionId===e);if(o)return{track:r,box:o}}if(t)for(let r of n.tracks||[]){let o=r.boxes.find(s=>s.cwd===t);if(o)return{track:r,box:o}}return null}async function dm(e){let t=js(e);if(!t)return null;let n=await z();for(let r of n.tracks||[])for(let o of r.boxes||[])if(o.hookTokenHash&&tw(o.hookTokenHash,t))return{track:r,box:o};return null}async function ne(e){let t=await z(),n=re(t,e);return n?(await WS(t)&&await X(),_t(n)):null}async function fm(e){let t=await L(e).catch(()=>[]),n;try{n=Zn(t)}catch{return[]}return Ey(n).map(r=>({kind:r.kind,id:r.offerId??r.proposalId??r.id,ts:r.ts??null}))}function om(e){if(e.role!=="user")return!1;let t=(e.text||"").trim();return(GP[e.agent]||[]).some(n=>n.test(t))}function sm(e){let t=(e.text||"").trim();return t?VP.some(n=>n.test(t)):!1}async function Cl(e,t={}){let n=await ne(e);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=xs(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=bp(n.id),c=!!(i&&!i.finishedAt),l=c&&i.startedAt&&i.box?[{box:i.box,from:i.startedAt,to:Date.now()+1e12}]:[],u=[...fx(n),...l],d={windows:[...Vy(n),...zy(n,Mc),...a,...u]},m=(await Promise.all(n.boxes.map(b=>lf(b,t)))).flat(),h=m.map(b=>{let P={kind:"message",...b};if(P.role==="assistant"&&(P.text||"").trim()&&P.tools?.length){let Me=Ta(P.agent).cliTools,We=P.tools.filter(Ht=>!Me.has(Ht));return{...P,tools:We.length?We:void 0}}return P}).map(b=>{if(b.role!=="user")return b;let P=$c(b.text);return P?P.kind==="suppress"?null:{...b,note:P,text:wy(P)}:b}).filter(Boolean).filter(b=>!(b.role==="user"&&r.has((b.text||"").trim()))).filter(b=>!om(b)).filter(b=>!sm(b)).filter(b=>!rm(b)).filter(b=>!Up(b)).filter(b=>b.role!=="assistant"||!!(b.text||"").trim()||!!b.images?.length).filter(b=>!Jy(b,d)),g=h.filter(b=>b.failed&&b.text===Dr);if(g.length){let b=new Map;for(let P of g){if(!b.has(P.box)){let Ht=[...(await Ae(P.box,{lines:Le}).catch(()=>"")).matchAll(/^\s*■\s+(.+?)\s*$/gm)].map(te=>te[1]);b.set(P.box,Ht.length?Ht[Ht.length-1]:null)}let Me=b.get(P.box);Me&&(P.text=`\u25A0 ${Me}`)}}let x=await Promise.all(n.boxes.map(b=>_b(b,t)));await z0(n,x.flat());let{agentTurnBoxes:k}=await G0(n,h);for(let b of n.boxes)k.has(b.name)&&b.cwd&&tc(b.cwd);await Sk(n),await bx(n,h).catch(()=>{});for(let b of n.boxes)b.agent==="codex"&&b.state==="live"&&await Y0(n,b),b.agent==="cursor"&&b.state==="live"&&await tx(n,b);let E=await Promise.all(n.boxes.map(b=>Ab(b,t)));await V0(n,E.flat().filter(b=>!Xp(b.box,b.ts,u)));let I=await L(n),M=c&&i.viewId?i.viewId:null,N=Nk(I),C=Zn(I).filter(b=>!(b.kind==="message"&&(om(b)||sm(b)||rm(b)||Up(b)))&&!(b.kind==="view-card"&&M&&b.viewId===M)),T=Pk(C,N),j=C.filter(b=>!(b.kind==="message"&&b.role==="assistant"&&!T.has(b)&&Xp(b.box,b.ts,N))),Z=Wd(I,j).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=>!Xp(b.anchorBox,b.anchorTs??b.ts,u)),fe=vy(Ty([...j,...Z].filter(b=>b.ts!=null).sort((b,P)=>b.ts-P.ts))),ie=JP(n),D=ie.size?fe.filter(b=>b.kind==="event"||!ie.has(b.box??b.anchorBox)):fe,R=n.boxes.find(b=>b.name===n.leadBox)||null,U=R?await aa(R.cwd,R.sessionId,{fallbackNewest:!1}):null;if(!U&&R){let b=[...I].reverse().find(P=>P.type==="context.usage"&&P.boxId===R.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 pe=[...m].reverse().find(b=>b.role==="assistant"&&b.model),Se=pe?.model||null,He=[...n.events||[]].reverse().find(b=>b.type==="model-change"),le=U?.model||Se;He&&(!pe?.ts||He.at>=pe.ts)&&(le=He.to);let q=R?await Ae(R.name,{lines:Le}).catch(()=>""):"",J=R&&Vr(R.agent,q)?await fn(R.name).catch(()=>q):q,ee=R?or(R,J):null;if(ee&&R){let b=Bc(R,ee,J);if(b){let P=Wb(R.name,ee.promptId);P.action!=="give-up"&&(P.action==="send"&&($e(R.name,b.keys,{kind:"auto-reject"}).catch(()=>{}),P.first&&_(n,{type:"prompt.autoRejected",actor:"system",source:"pane",boxId:R.name,provider:R.agent,payload:{ts:Date.now(),promptId:ee.promptId,rule:b.id}}).catch(()=>{})),ee=null)}}!ee&&R&&!pa(R.agent,q)&&!ao(n.id).length&&(ee=Ud(D,{leadBoxId:R.name,provider:R.agent,isAnswered:b=>I.some(P=>P.type==="prompt.answered"&&P.payload?.promptId===b)})),ee&&vk(n,R,ee);let Xe=D.filter(b=>!(b.kind==="message"&&b.role==="assistant"&&b.ask&&!String(b.text||"").trim()&&!b.images?.length)),w=!!R&&il(R.name,R.agent,q)&&!ee;R&&!R.readyAt&&(w||ee||q&&vc(R.agent,q))&&(R.readyAt=Date.now(),await X());let v=!!R&&!R.readyAt&&Date.now()-(n.createdAt||0)<zP;if(n.kind==="setup"&&n.setup?.provider&&!n.setup.connectedAt&&R&&vc(R.agent,q)&&!ee){let b=await z(),P=re(b,n.id);P?.setup&&!P.setup.connectedAt&&(P.setup.connectedAt=Date.now(),n.setup.connectedAt=P.setup.connectedAt,await _(P,{type:"provider.connected",actor:"system",source:"pane",boxId:R.name,provider:R.agent,payload:{provider:R.agent,ts:P.setup.connectedAt}}).catch(()=>{}),await X())}let $=s?{running:!0,step:o.step,toAgent:o.toAgent||null}:null,ve=null;if(c){let b=Date.now()-i.startedAt;if(i.viewId&&!w){let P=wl(n.id);P&&(he(n,"view-spinup",{box:i.box,startedAt:i.startedAt,endedAt:P.finishedAt}),await X())}else if(ee||b>ux&&!w&&!i.viewId||b>yp){let P=ee?"needs-input":b>yp?"timeout":"no-view";wl(n.id,{error:P})&&await _(n,{type:"view.spinup.failed",actor:"orchestrator",source:"orchestrator",boxId:i.box,provider:R?.agent||null,payload:{ts:i.startedAt,name:i.name,reason:P}}).catch(()=>{})}else ve={running:!0,step:i.step,name:i.name}}return{trackId:n.id,leadBox:n.leadBox,items:Xe,context:U?{pct:U.pct,occupancy:U.occupancy,window:U.window,windowKnown:U.windowKnown,model:U.model}:null,models:{current:le,options:hk(R?.agent)},pendingPrompt:ee,working:w,stopping:KS(n.id),leadStarting:v,handoff:$,view:ve,queued:ao(n.id).filter(b=>b.kind!=="ship-notify"&&b.kind!=="prompt-answer"),draft:n.draft||null,draftRev:n.draftRev||0}}function JP(e){let t=new Set;for(let n of e.boxes||[])n.role==="subtask"&&n.name&&t.add(n.name);for(let n of Object.values(e.subtasks||{}))n?.box&&t.add(n.box);return t}async function pm(e,t){let n=await ne(e);if(!n)return null;let r=co(e).find(f=>f.id===t)||null;if(!r)return null;let o=r.box||null;if(!o)return{items:[],working:!1,box:null,agent:r.agent,task:r.task};let s=await L(n),a=Zn(s).filter(f=>f.box===o&&!(f.kind==="message"&&f.role==="assistant"&&f.ask&&!String(f.text||"").trim()&&!f.images?.length)),i=Wd(s.filter(f=>f.boxId===o),a.filter(f=>f.kind==="message")).map(f=>({kind:"command-batch",id:f.id,ts:f.pending?f.ts:(f.anchorTs??f.ts)-1,anchorTs:f.anchorTs,anchorBox:f.anchorBox,agent:f.agent,boxRole:f.boxRole,commands:f.commands,pending:f.pending})),c=[...a,...i].filter(f=>f.ts!=null).sort((f,d)=>f.ts-d.ts),l=n.boxes.find(f=>f.name===o)||null,u=!1;if(l&&l.state==="live"){let f=await Ae(o,{lines:Le}).catch(()=>"");u=il(o,l.agent||r.agent,f)}return{items:c,working:u,box:o,agent:r.agent,task:r.task}}async function Ml(e,{promptId:t,answers:n,text:r}={}){let o=re(await z(),e);if(!o)throw new Error(`track "${e}" not found`);di(e,"prompt-answer");let s=o.boxes.find(m=>m.name===o.leadBox);if(!s)throw new Error(`track "${e}" has no lead box`);if(!await se(o.leadBox))throw new Error(`lead box "${o.leadBox}" is not running`);let i=await wf(s);if(i||(i=await YP(o,s)),!i)throw new Error("no pending prompt to answer");if(t&&t!==i.promptId)throw new Error("prompt changed since it was shown \u2014 reload and answer the current prompt");let c;if(i.answerMode==="text"){let m=typeof r=="string"?r.trim():"";if(!m)throw new Error("this prompt needs a code \u2014 paste it into the card");if(/\s/.test(m)||m.length>2048)throw new Error("that doesn't look like a sign-in code \u2014 paste the code exactly as shown");await Fe(o.leadBox,m,{enter:!0,kind:"answer-prompt"}),c={mode:"text-input",value:"\u2039code\u203A",count:1,redacted:!0}}else if(i.answerMode==="esc")await $e(o.leadBox,["Escape"],{kind:"answer-prompt"}),c={mode:"keys",value:"Escape",count:1};else if(i.answerMode==="say"){let m=ky(i,n||[],typeof r=="string"?r:"");if(!m)throw new Error("no answer selected \u2014 pick an option or reply in chat");await It(o.id,m,{kind:"prompt-answer"}),c={mode:"say",value:m,count:1}}else if(i.provider==="claude"||i.answerMode==="keys"){let m=Lb(i,n||[]);await $e(o.leadBox,m,{kind:"answer-prompt"}),c={mode:"keys",value:m.join(" "),count:m.length}}else{let m=qg(i,n||[]);await Fe(o.leadBox,m,{enter:!0,kind:"answer-prompt"}),c={mode:"text",value:m,count:1}}if(i.answerMode==="say"){let m=i.questions||[];for(let h=0;h<m.length;h++){let g=m[h],x=new Set(Array.isArray(n?.[h])?n[h]:[]),k=[...x].map(I=>g.options?.[I]).filter(Boolean).map(I=>({label:I.label,description:I.description||""})),E=(g.options||[]).map((I,M)=>x.has(M)?null:I?.label).filter(Boolean);Mf(o,s,i,{...c,groupId:i.groupId||i.promptId,questionIndex:h,questionTotal:i.questionTotal??m.length,header:g.header||"",question:g.question||"",multiSelect:!!g.multiSelect,chosen:k,rejected:E})}return await Y({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]:[]),f=[...u].map(m=>l.options?.[m]).filter(Boolean).map(m=>({label:m.label,description:m.description||""})),d=(l.options||[]).map((m,h)=>u.has(h)?null:m?.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:f,rejected:d,...p?{control:p}:{}},await Y({flow:"prompt",phase:"answered",sessionName:o.leadBox,agent:s.agent,provider:i.provider,promptId:i.promptId,...c}).catch(()=>{}),Mf(o,s,i,c),{ok:!0,promptId:i.promptId,sent:c.count}}async function YP(e,t){if(!t)return null;let n=await L(e).catch(()=>[]);return Ud(Zn(n),{leadBoxId:t.name,provider:t.agent,isAnswered:r=>n.some(o=>o.type==="prompt.answered"&&o.payload?.promptId===r)})}async function mm(e,{promptId:t,questionIndex:n}={}){let r=re(await z(),e);if(!r)throw new Error(`track "${e}" not found`);let o=r.boxes.find(l=>l.name===r.leadBox);if(!o)throw new Error(`track "${e}" has no lead box`);if(!await se(r.leadBox))throw new Error(`lead box "${r.leadBox}" is not running`);let a=await wf(o);if(!a)throw new Error("no pending prompt to navigate");if(a.provider!=="claude")throw new Error("prompt navigation not supported for this provider");if(a.review)throw new Error("cannot navigate on the review screen \u2014 answer or cancel");let i=a.questionTotal??1;if(i<2)throw new Error("not a multi-question prompt");if(!Number.isInteger(n)||n<0||n>=i)throw new Error("questionIndex out of range");if(t&&t!==a.promptId)throw new Error("prompt changed since it was shown \u2014 reload and try again");let c=Fb(a,n);return c.length?(await $e(r.leadBox,c,{kind:"navigate-prompt"}),await Y({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 Nl(e){let t=ei.get(e);return t||(t={items:[],timer:null,flushing:!1,idleSince:null},ei.set(e,t)),t}function ao(e){return(ei.get(e)?.items??[]).map(t=>({...t}))}function ui(e){let t=ei.get(e);if(!t)return[];let n=t.items.splice(0);return t.idleSince=null,t.timer&&(clearInterval(t.timer),t.timer=null),n}async function hm(e){let t=ui(e),n=t.filter(o=>o.text&&!o.kind).map(o=>o.text),r=null;if(n.length){let o=re(await z(),e);if(o)return r=gs(o,n),await X(),{removed:t,restored:r,draftRev:o.draftRev||0}}return{removed:t,restored:r,draftRev:null}}function wm(e){let t=Nl(e);t.timer||(t.timer=setInterval(()=>ZP(e).catch(()=>{}),XP))}async function ZP(e){let t=ei.get(e);if(!(!t||t.flushing)){if(!t.items.length){t.timer&&(clearInterval(t.timer),t.timer=null);return}t.flushing=!0;try{let n=re(await z(),e);if(!n||n.archivedAt){ui(e);return}let r=xs(e);if(r&&!r.finishedAt&&r.step!=="done"&&!r.error){oo(t,!1);return}let o=await se(n.leadBox),s=n.boxes.find(c=>c.name===n.leadBox);if(o&&await Im(o)&&(o=await si(n,s,"queue")?await se(n.leadBox):null,await X()),!o){oo(t,!1);return}if(Jr(s?.agent)){oo(t,!1);return}let a=await Ae(n.leadBox,{lines:Le}).catch(()=>"");if(Sc(s?.agent,a)){oo(t,!1);return}if(Vr(s?.agent,a)){let c=await fn(n.leadBox).catch(()=>a);if(or(s,c)){oo(t,!1);return}}if(!oo(t,!0))return;let i=t.items.shift();t.idleSince=null;try{await am(n,s,o,i.text,i.kind??null,i.attachments??null)}catch(c){if(c?.code!=="cli-not-running")throw c;t.items.unshift(i),await si(n,s,"queue-gate")}await X()}finally{t.flushing=!1}}}async function qS(e,t,n,r){let o=Jr(t?.agent);if(!o)return;if(!r&&typeof n=="string"&&n.trim()&&(gs(e,[n]),await X()),sk(e.id,o))try{await _(e,{type:"usage.cap.hit",actor:"system",provider:t?.agent??null,boxId:e.leadBox,payload:{...o,blockedKind:r??null}})}catch{}let s=new Error(`${t?.agent??"the lead provider"} is paused \u2014 its ${o.window} spend limit is reached ($${o.spentUsd.toFixed(2)} of $${o.limitUsd.toFixed(2)})`);throw s.usageCap=o,s}async function QP(e,t){let n=await Ae(e.leadBox,{lines:Le}).catch(()=>"");if(!Vr(t?.agent,n))return!1;let r=await fn(e.leadBox).catch(()=>n);return!!or(t,r)}async function am(e,t,n,r,o=null,s=null){await qS(e,t,r,o);let a=ti.get(e.id)||0,i=r,c=!1,l=e.pendingHandoffHydrate||null;e.pendingHandoffHydrate&&(i=LS(r,e.pendingHandoffHydrate.artifact||so),delete e.pendingHandoffHydrate,c=!0);let u=Array.isArray(s)?s.filter(d=>d&&d.rel):[];if(u.length){let d=SS(u.map(p=>p.rel));i=i.trim()?`${i.trim()}
163
+ (Read ${t} for handoff context from the prior lead \u2014 you are now the lead; none of the prior chat is in your context. Then respond to the user above.)`}function cm(e){return e.role==="user"&&tD.test((e.text||"").trim())}async function z(){return At||(em||=(async()=>{try{At=JSON.parse(await W.readFile(WS,"utf8"))}catch{At={tracks:[]}}finally{em=null}return At})(),em)}async function Y(){await at(WS,At)}function oD(e,t){let n=JSON.stringify({trackId:e,...t})+`
164
+ `;return tm=tm.then(()=>W.mkdir(sn,{recursive:!0})).then(()=>W.appendFile(QP,n)).catch(()=>{}),tm}async function an({current:e,latest:t,min:n=null,installKind:r=null,required:o=!1,status:s="available",policy:a=null,error:i=null,reason:c=null}={}){if(!t)return{announced:0};if(s==="available"){let f=null;try{f=JSON.parse(await W.readFile(nm,"utf8"))}catch{}if(f?.latest===t&&f?.current===e)return{announced:0,deduped:!0}}let l=await z(),u=0;for(let f of l.tracks)f.archivedAt||f.transferredTo||!f.leadBox||(he(f,"node-update",{status:s,current:e??null,latest:t,...n?{min:n}:{},...r?{installKind:r}:{},...a?{policy:a}:{},...i?{error:String(i).slice(0,400)}:{},...c?{reason:c}:{},required:o===!0}),u++);if(await Y().catch(()=>{}),s==="available")try{await W.mkdir(G.dirname(nm),{recursive:!0}),await W.writeFile(nm,JSON.stringify({current:e,latest:t,at:Date.now()}))}catch{}return{announced:u}}function VS(e){if(!e)return null;let t=typeof e=="string"?[e]:Array.isArray(e?.codes)&&e.codes.length?e.codes:e?.code?[e.code]:[],n=[...new Set(t.filter(s=>sD.has(s)))];if(!n.length)return null;let r=typeof e=="object"?e?.note:null,o=r&&String(r).slice(0,500).trim()||null;return{code:n[0],...n.length>1?{codes:n}:{},note:o}}async function zS(e,t,n,{kind:r}={}){let o=await se(t);if(!o)throw new Error(`box "${t}" is not running`);let s=Ts(o.agent);await Yn({cwd:o.cwd,sessionId:o.sessionId,sessionName:t,agent:o.agent,agentCmd:s}),await Le(t,n,{...zt(o.agent,n),kind:r||"orchestration"});let a=await xa({sessionName:t,agent:o.agent,agentCmd:s,text:n,trackId:e,flow:"orchestration"});await X({flow:"orchestration",phase:"sent",submitted:a,trackId:e,sessionName:t,agent:o.agent,kind:r||"orchestration",promptHead:n.slice(0,160)});let i=await z(),c=re(i,e);if(!c)return;let l=c.boxes.find(u=>u.name===t);he(c,"orchestration-prompt",{box:t,agent:l?.agent||o.agent,boxRole:l?.role,prompt:n,kind:r||"orchestration"}),await Y()}async function aD(e){let t=G.join(So(e),`${e.id}.ndjson`),n;try{n=await W.stat(t)}catch{return null}let r=BS.get(e.id);if(r&&r.mtimeMs===n.mtimeMs)return r.at;let o=null;for(let s of await L(e)){if(s.type!=="turn.agent")continue;let a=s.payload?.ts??s.ts;a&&(!o||a>o)&&(o=a)}return BS.set(e.id,{mtimeMs:n.mtimeMs,at:o}),o}async function iD(e,t){let n=t.find(r=>r.name===e.leadBox);return n?.state!=="live"?{working:!1,prompted:!1}:tp(n.name,n.agent)}async function _t(e,t=null){let n=t??new Map((await Ot()).map(i=>[i.name,i])),r=e.boxes.map(i=>{let c=n.get(i.name),l=Nn.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([aD(e),iD(e,r)]);return{...e,boxes:r,lastResponseAt:o,working:s,prompted:a,archiving:li.has(e.id)}}function JS(e,t,n){let r=[...e].sort((l,u)=>l.createdAt-u.createdAt),o=[...t].sort((l,u)=>l.birthMs-u.birthMs),s=new Set,a=[];for(let l of r)l.sessionId&&n(l.sessionId)&&!s.has(l.sessionId)?s.add(l.sessionId):a.push(l);let i=new Map(r.map((l,u)=>[l,u])),c=[];for(let l of a){if(l.sessionId&&n(l.sessionId)){c.push({box:l.name,sessionId:null});continue}if(!l.sessionId||l.pinned)continue;let u=i.get(l),f=l.createdAt-cD,d=r[u+1]?.createdAt??1/0,p=o.find(m=>!s.has(m.id)&&m.birthMs>=f&&m.birthMs<d);p&&(s.add(p.id),c.push({box:l.name,sessionId:p.id}))}return c}async function XS(e){let t=new Map;for(let r of e.tracks)for(let o of r.boxes)o.agent==="claude"&&o.cwd&&(t.has(o.cwd)||t.set(o.cwd,[]),t.get(o.cwd).push({track:r,box:o}));let n=!1;for(let[r,o]of t){let s=o.map(d=>d.box.sessionId),a=Sg(r),i=new Set(a.map(d=>d.id)),c=s.every(d=>d&&i.has(d)),l=new Set(s).size===s.length;if(c&&l)continue;let u=o.map(d=>d.box),f=JS(u,a,d=>i.has(d));for(let d of f){let p=u.find(m=>m.name===d.box);p&&(p.sessionId=d.sessionId),await pg(d.box,d.sessionId),n=!0}}return n}async function ae(){let e=await z();await XS(e)&&await Y();let t=new Map((await Ot()).map(n=>[n.name,n]));return Promise.all(e.tracks.map(n=>_t(n,t)))}async function qa(e,t){let n=await z();if(e)for(let r of n.tracks||[]){let o=r.boxes.find(s=>s.sessionId&&s.sessionId===e);if(o)return{track:r,box:o}}if(t)for(let r of n.tracks||[]){let o=r.boxes.find(s=>s.cwd===t);if(o)return{track:r,box:o}}return null}async function wm(e){let t=Hs(e);if(!t)return null;let n=await z();for(let r of n.tracks||[])for(let o of r.boxes||[])if(o.hookTokenHash&&iw(o.hookTokenHash,t))return{track:r,box:o};return null}async function ne(e){let t=await z(),n=re(t,e);return n?(await XS(t)&&await Y(),_t(n)):null}async function gm(e){let t=await L(e).catch(()=>[]),n;try{n=Zn(t)}catch{return[]}return Oy(n).map(r=>({kind:r.kind,id:r.offerId??r.proposalId??r.id,ts:r.ts??null}))}function lm(e){if(e.role!=="user")return!1;let t=(e.text||"").trim();return(lD[e.agent]||[]).some(n=>n.test(t))}function um(e){let t=(e.text||"").trim();return t?uD.some(n=>n.test(t)):!1}async function Dl(e,t={}){let n=await ne(e);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=Es(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=Ep(n.id),c=!!(i&&!i.finishedAt),l=c&&i.startedAt&&i.box?[{box:i.box,from:i.startedAt,to:Date.now()+1e12}]:[],u=[...b0(n),...l],d={windows:[...eb(n),...tb(n,Bc),...a,...u]},m=(await Promise.all(n.boxes.map(b=>hf(b,t)))).flat(),h=m.map(b=>{let P={kind:"message",...b};if(P.role==="assistant"&&(P.text||"").trim()&&P.tools?.length){let Me=Ra(P.agent).cliTools,We=P.tools.filter(Ht=>!Me.has(Ht));return{...P,tools:We.length?We:void 0}}return P}).map(b=>{if(b.role!=="user")return b;let P=Nc(b.text);return P?P.kind==="suppress"?null:{...b,note:P,text:Sy(P)}:b}).filter(Boolean).filter(b=>!(b.role==="user"&&r.has((b.text||"").trim()))).filter(b=>!lm(b)).filter(b=>!um(b)).filter(b=>!cm(b)).filter(b=>!Vp(b)).filter(b=>b.role!=="assistant"||!!(b.text||"").trim()||!!b.images?.length).filter(b=>!nb(b,d)),g=h.filter(b=>b.failed&&b.text===Pr);if(g.length){let b=new Map;for(let P of g){if(!b.has(P.box)){let Ht=[...(await Te(P.box,{lines:je}).catch(()=>"")).matchAll(/^\s*■\s+(.+?)\s*$/gm)].map(te=>te[1]);b.set(P.box,Ht.length?Ht[Ht.length-1]:null)}let Me=b.get(P.box);Me&&(P.text=`\u25A0 ${Me}`)}}let x=await Promise.all(n.boxes.map(b=>Nb(b,t)));await t0(n,x.flat());let{agentTurnBoxes:k}=await Qx(n,h);for(let b of n.boxes)k.has(b.name)&&b.cwd&&sc(b.cwd);await Rk(n),await A0(n,h).catch(()=>{});for(let b of n.boxes)b.agent==="codex"&&b.state==="live"&&await r0(n,b),b.agent==="cursor"&&b.state==="live"&&await c0(n,b);let E=await Promise.all(n.boxes.map(b=>Mb(b,t)));await e0(n,E.flat().filter(b=>!rm(b.box,b.ts,u)));let I=await L(n),M=c&&i.viewId?i.viewId:null,N=Uk(I),O=Zn(I).filter(b=>!(b.kind==="message"&&(lm(b)||um(b)||cm(b)||Vp(b)))&&!(b.kind==="view-card"&&M&&b.viewId===M)),T=Hk(O,N),j=O.filter(b=>!(b.kind==="message"&&b.role==="assistant"&&!T.has(b)&&rm(b.box,b.ts,N))),Z=Jd(I,j).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=>!rm(b.anchorBox,b.anchorTs??b.ts,u)),fe=Ry($y([...j,...Z].filter(b=>b.ts!=null).sort((b,P)=>b.ts-P.ts))),ie=fD(n),D=ie.size?fe.filter(b=>b.kind==="event"||!ie.has(b.box??b.anchorBox)):fe,R=n.boxes.find(b=>b.name===n.leadBox)||null,U=R?await ua(R.cwd,R.sessionId,{fallbackNewest:!1}):null;if(!U&&R){let b=[...I].reverse().find(P=>P.type==="context.usage"&&P.boxId===R.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 pe=[...m].reverse().find(b=>b.role==="assistant"&&b.model),Se=pe?.model||null,He=[...n.events||[]].reverse().find(b=>b.type==="model-change"),le=U?.model||Se;He&&(!pe?.ts||He.at>=pe.ts)&&(le=He.to);let q=R?await Te(R.name,{lines:je}).catch(()=>""):"",J=R&&Gr(R.agent,q)?await pn(R.name).catch(()=>q):q,ee=R?or(R,J):null;if(ee&&R){let b=Uc(R,ee,J);if(b){let P=Xb(R.name,ee.promptId);P.action!=="give-up"&&(P.action==="send"&&(Ie(R.name,b.keys,{kind:"auto-reject"}).catch(()=>{}),P.first&&_(n,{type:"prompt.autoRejected",actor:"system",source:"pane",boxId:R.name,provider:R.agent,payload:{ts:Date.now(),promptId:ee.promptId,rule:b.id}}).catch(()=>{})),ee=null)}}!ee&&R&&!Bo(R.agent,q)&&!so(n.id).length&&(ee=Vd(D,{leadBoxId:R.name,provider:R.agent,isAnswered:b=>I.some(P=>P.type==="prompt.answered"&&P.payload?.promptId===b)})),ee&&$k(n,R,ee);let Ze=D.filter(b=>!(b.kind==="message"&&b.role==="assistant"&&b.ask&&!String(b.text||"").trim()&&!b.images?.length)),w=!!R&&dl(R.name,R.agent,q)&&!ee;R&&!R.readyAt&&(w||ee||q&&jo(R.agent,q))&&(R.readyAt=Date.now(),await Y());let v=!!R&&!R.readyAt&&Date.now()-(n.createdAt||0)<dD;if(n.kind==="setup"&&n.setup?.provider&&!n.setup.connectedAt&&R&&jo(R.agent,q)&&!ee){let b=await z(),P=re(b,n.id);P?.setup&&!P.setup.connectedAt&&(P.setup.connectedAt=Date.now(),n.setup.connectedAt=P.setup.connectedAt,await _(P,{type:"provider.connected",actor:"system",source:"pane",boxId:R.name,provider:R.agent,payload:{provider:R.agent,ts:P.setup.connectedAt}}).catch(()=>{}),await Y())}let $=s?{running:!0,step:o.step,toAgent:o.toAgent||null}:null,ve=null;if(c){let b=Date.now()-i.startedAt;if(i.viewId&&!w){let P=kl(n.id);P&&(he(n,"view-spinup",{box:i.box,startedAt:i.startedAt,endedAt:P.finishedAt}),await Y())}else if(ee||b>g0&&!w&&!i.viewId||b>Tp){let P=ee?"needs-input":b>Tp?"timeout":"no-view";kl(n.id,{error:P})&&await _(n,{type:"view.spinup.failed",actor:"orchestrator",source:"orchestrator",boxId:i.box,provider:R?.agent||null,payload:{ts:i.startedAt,name:i.name,reason:P}}).catch(()=>{})}else ve={running:!0,step:i.step,name:i.name}}return{trackId:n.id,leadBox:n.leadBox,items:Ze,context:U?{pct:U.pct,occupancy:U.occupancy,window:U.window,windowKnown:U.windowKnown,model:U.model}:null,models:{current:le,options:Sk(R?.agent)},pendingPrompt:ee,working:w,stopping:ZS(n.id),leadStarting:v,handoff:$,view:ve,queued:so(n.id).filter(b=>b.kind!=="ship-notify"&&b.kind!=="prompt-answer"),draft:n.draft||null,draftRev:n.draftRev||0}}function fD(e){let t=new Set;for(let n of e.boxes||[])n.role==="subtask"&&n.name&&t.add(n.name);for(let n of Object.values(e.subtasks||{}))n?.box&&t.add(n.box);return t}async function ym(e,t){let n=await ne(e);if(!n)return null;let r=co(e).find(f=>f.id===t)||null;if(!r)return null;let o=r.box||null;if(!o)return{items:[],working:!1,box:null,agent:r.agent,task:r.task};let s=await L(n),a=Zn(s).filter(f=>f.box===o&&!(f.kind==="message"&&f.role==="assistant"&&f.ask&&!String(f.text||"").trim()&&!f.images?.length)),i=Jd(s.filter(f=>f.boxId===o),a.filter(f=>f.kind==="message")).map(f=>({kind:"command-batch",id:f.id,ts:f.pending?f.ts:(f.anchorTs??f.ts)-1,anchorTs:f.anchorTs,anchorBox:f.anchorBox,agent:f.agent,boxRole:f.boxRole,commands:f.commands,pending:f.pending})),c=[...a,...i].filter(f=>f.ts!=null).sort((f,d)=>f.ts-d.ts),l=n.boxes.find(f=>f.name===o)||null,u=!1;if(l&&l.state==="live"){let f=await Te(o,{lines:je}).catch(()=>"");u=dl(o,l.agent||r.agent,f)}return{items:c,working:u,box:o,agent:r.agent,task:r.task}}async function Bl(e,{promptId:t,answers:n,text:r}={}){let o=re(await z(),e);if(!o)throw new Error(`track "${e}" not found`);hi(e,"prompt-answer");let s=o.boxes.find(m=>m.name===o.leadBox);if(!s)throw new Error(`track "${e}" has no lead box`);if(!await se(o.leadBox))throw new Error(`lead box "${o.leadBox}" is not running`);let i=await Sf(s);if(i||(i=await pD(o,s)),!i)throw new Error("no pending prompt to answer");if(t&&t!==i.promptId)throw new Error("prompt changed since it was shown \u2014 reload and answer the current prompt");let c;if(i.answerMode==="text"){let m=typeof r=="string"?r.trim():"";if(!m)throw new Error("this prompt needs a code \u2014 paste it into the card");if(/\s/.test(m)||m.length>2048)throw new Error("that doesn't look like a sign-in code \u2014 paste the code exactly as shown");await Le(o.leadBox,m,{enter:!0,kind:"answer-prompt"}),c={mode:"text-input",value:"\u2039code\u203A",count:1,redacted:!0}}else if(i.answerMode==="esc")await Ie(o.leadBox,["Escape"],{kind:"answer-prompt"}),c={mode:"keys",value:"Escape",count:1};else if(i.answerMode==="say"){let m=Ay(i,n||[],typeof r=="string"?r:"");if(!m)throw new Error("no answer selected \u2014 pick an option or reply in chat");await It(o.id,m,{kind:"prompt-answer"}),c={mode:"say",value:m,count:1}}else if(i.provider==="claude"||i.answerMode==="keys"){let m=Gb(i,n||[]);await Ie(o.leadBox,m,{kind:"answer-prompt"}),c={mode:"keys",value:m.join(" "),count:m.length}}else{let m=Xg(i,n||[]);await Le(o.leadBox,m,{enter:!0,kind:"answer-prompt"}),c={mode:"text",value:m,count:1}}if(i.answerMode==="say"){let m=i.questions||[];for(let h=0;h<m.length;h++){let g=m[h],x=new Set(Array.isArray(n?.[h])?n[h]:[]),k=[...x].map(I=>g.options?.[I]).filter(Boolean).map(I=>({label:I.label,description:I.description||""})),E=(g.options||[]).map((I,M)=>x.has(M)?null:I?.label).filter(Boolean);Lf(o,s,i,{...c,groupId:i.groupId||i.promptId,questionIndex:h,questionTotal:i.questionTotal??m.length,header:g.header||"",question:g.question||"",multiSelect:!!g.multiSelect,chosen:k,rejected:E})}return await X({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]:[]),f=[...u].map(m=>l.options?.[m]).filter(Boolean).map(m=>({label:m.label,description:m.description||""})),d=(l.options||[]).map((m,h)=>u.has(h)?null:m?.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:f,rejected:d,...p?{control:p}:{}},await X({flow:"prompt",phase:"answered",sessionName:o.leadBox,agent:s.agent,provider:i.provider,promptId:i.promptId,...c}).catch(()=>{}),Lf(o,s,i,c),{ok:!0,promptId:i.promptId,sent:c.count}}async function pD(e,t){if(!t)return null;let n=await L(e).catch(()=>[]);return Vd(Zn(n),{leadBoxId:t.name,provider:t.agent,isAnswered:r=>n.some(o=>o.type==="prompt.answered"&&o.payload?.promptId===r)})}async function bm(e,{promptId:t,questionIndex:n}={}){let r=re(await z(),e);if(!r)throw new Error(`track "${e}" not found`);let o=r.boxes.find(l=>l.name===r.leadBox);if(!o)throw new Error(`track "${e}" has no lead box`);if(!await se(r.leadBox))throw new Error(`lead box "${r.leadBox}" is not running`);let a=await Sf(o);if(!a)throw new Error("no pending prompt to navigate");if(a.provider!=="claude")throw new Error("prompt navigation not supported for this provider");if(a.review)throw new Error("cannot navigate on the review screen \u2014 answer or cancel");let i=a.questionTotal??1;if(i<2)throw new Error("not a multi-question prompt");if(!Number.isInteger(n)||n<0||n>=i)throw new Error("questionIndex out of range");if(t&&t!==a.promptId)throw new Error("prompt changed since it was shown \u2014 reload and try again");let c=Vb(a,n);return c.length?(await Ie(r.leadBox,c,{kind:"navigate-prompt"}),await X({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 jl(e){let t=si.get(e);return t||(t={items:[],timer:null,flushing:!1,idleSince:null},si.set(e,t)),t}function so(e){return(si.get(e)?.items??[]).map(t=>({...t}))}function mi(e){let t=si.get(e);if(!t)return[];let n=t.items.splice(0);return t.idleSince=null,t.timer&&(clearInterval(t.timer),t.timer=null),n}async function km(e){let t=mi(e),n=t.filter(o=>o.text&&!o.kind).map(o=>o.text),r=null;if(n.length){let o=re(await z(),e);if(o)return r=ks(o,n),await Y(),{removed:t,restored:r,draftRev:o.draftRev||0}}return{removed:t,restored:r,draftRev:null}}function xm(e){let t=jl(e);t.timer||(t.timer=setInterval(()=>hD(e).catch(()=>{}),mD))}async function hD(e){let t=si.get(e);if(!(!t||t.flushing)){if(!t.items.length){t.timer&&(clearInterval(t.timer),t.timer=null);return}t.flushing=!0;try{let n=re(await z(),e);if(!n||n.archivedAt){mi(e);return}let r=Es(e);if(r&&!r.finishedAt&&r.step!=="done"&&!r.error){ro(t,!1);return}let o=await se(n.leadBox),s=n.boxes.find(c=>c.name===n.leadBox);if(o&&await Mm(o)&&(o=await ui(n,s,"queue")?await se(n.leadBox):null,await Y()),!o){ro(t,!1);return}if(zr(s?.agent)){ro(t,!1);return}let a=await Te(n.leadBox,{lines:je}).catch(()=>"");if(_c(s?.agent,a)){ro(t,!1);return}if(Gr(s?.agent,a)){let c=await pn(n.leadBox).catch(()=>a);if(or(s,c)){ro(t,!1);return}}if(!ro(t,!0))return;let i=t.items.shift();t.idleSince=null;try{await dm(n,s,o,i.text,i.kind??null,i.attachments??null)}catch(c){if(c?.code!=="cli-not-running")throw c;t.items.unshift(i),await ui(n,s,"queue-gate")}await Y()}finally{t.flushing=!1}}}async function YS(e,t,n,r){let o=zr(t?.agent);if(!o)return;if(!r&&typeof n=="string"&&n.trim()&&(ks(e,[n]),await Y()),fk(e.id,o))try{await _(e,{type:"usage.cap.hit",actor:"system",provider:t?.agent??null,boxId:e.leadBox,payload:{...o,blockedKind:r??null}})}catch{}let s=new Error(`${t?.agent??"the lead provider"} is paused \u2014 its ${o.window} spend limit is reached ($${o.spentUsd.toFixed(2)} of $${o.limitUsd.toFixed(2)})`);throw s.usageCap=o,s}async function wD(e,t){let n=await Te(e.leadBox,{lines:je}).catch(()=>"");if(!Gr(t?.agent,n))return!1;let r=await pn(e.leadBox).catch(()=>n);return!!or(t,r)}async function dm(e,t,n,r,o=null,s=null){await YS(e,t,r,o);let a=ai.get(e.id)||0,i=r,c=!1,l=e.pendingHandoffHydrate||null;e.pendingHandoffHydrate&&(i=GS(r,e.pendingHandoffHydrate.artifact||oo),delete e.pendingHandoffHydrate,c=!0);let u=Array.isArray(s)?s.filter(d=>d&&d.rel):[];if(u.length){let d=RS(u.map(p=>p.rel));i=i.trim()?`${i.trim()}
162
165
 
163
- ${d}`:d}let f=he(e,"said",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,text:r,...o?{kind:o}:{},...u.length?{attachments:u}:{}});o||ws(e,null);try{if(await Xn({cwd:n.cwd,sessionId:n.sessionId,sessionName:e.leadBox,agent:n.agent,agentCmd:ci(n.agent),bailOnDialog:!0}),(ti.get(e.id)||0)!==a){!o&&r.trim()&&(gs(e,[r]),await X());let d=new Error("delivery stopped \u2014 the message was handed back as the draft");throw d.interrupted=!0,d}if(await QP(e,t)){let d=Nl(e.id),p={id:ks(),text:r,ts:Date.now(),...o?{kind:o}:{},...u.length?{attachments:u}:{}};d.items.unshift(p),wm(e.id);let m=new Error("lead is blocked on a prompt \u2014 message queued");throw m.requeued={id:p.id,position:d.items.length},m}await Fe(e.leadBox,i,{...Gt(t?.agent,i),kind:c?"lead-handoff-first-prompt":"say"})}catch(d){if(l&&!e.pendingHandoffHydrate&&(e.pendingHandoffHydrate=l),he(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:f.at,text:r,...d?.interrupted?{reason:"interrupted"}:{},...d?.requeued?{reason:"requeued"}:{}}),d?.requeued)return{queued:!0,...d.requeued};throw d}await hD(e,t,i)||(await GS(e.leadBox,t?.agent,i.length+8,i).catch(()=>{}),he(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:f.at,text:r,reason:"unsubmitted"}),o||gs(e,[r])),c&&await Y({flow:"lead-handoff",phase:"first-prompt",trackId:e.id,sessionName:e.leadBox,agent:t?.agent,userTextLen:r.length})}function gm(e,{actions:t}={}){Nl(e).items.push({id:ks(),text:Dk(t),ts:Date.now(),kind:"ship-notify"}),wm(e)}async function It(e,t,{kind:n=null,attachments:r=null}={}){let o=Array.isArray(r)?r.filter(p=>p&&typeof p.rel=="string"):[];if((typeof t!="string"||!Uo(t))&&!o.length)throw new Error("text (string) or an attachment required");let s=re(await z(),e);if(!s)throw new Error(`track "${e}" not found`);if(s.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it before driving it`);Bm(s);let a=s.boxes.find(p=>p.name===s.leadBox),i=Uo(t);await qS(s,a,i,n),di(e,"say");let c=await se(s.leadBox);if(c&&await Im(c)?await si(s,a,"say")?(await X(),c=await se(s.leadBox)):c=null:!c&&await pi(s)&&(await X(),c=await se(s.leadBox)),!c)throw new Error(`lead box "${s.leadBox}" is not running`);let l=Nl(e),u=await Ae(s.leadBox,{lines:Le}).catch(()=>""),f=l.items.length>0||Sc(a?.agent,u);if(!f&&Vr(a?.agent,u)){let p=await fn(s.leadBox).catch(()=>u);f=!!or(a,p)}if(f){let p={id:ks(),text:i,ts:Date.now(),...n?{kind:n}:{},...o.length?{attachments:o}:{}};return l.items.push(p),wm(e),n||ws(s,null),await X(),{ok:!0,leadBox:s.leadBox,queued:!0,id:p.id,position:l.items.length}}let d;try{d=await am(s,a,c,i,n,o)}catch(p){if(p?.code!=="cli-not-running"||!await si(s,a,"say-gate")||(await X(),c=await se(s.leadBox),!c))throw p;d=await am(s,a,c,i,n,o)}return await X(),d?.queued?{ok:!0,leadBox:s.leadBox,queued:!0,id:d.id,position:d.position}:{ok:!0,leadBox:s.leadBox}}async function ym(e,{hint:t}={}){let n=re(await z(),e);if(!n)throw new Error(`track "${e}" not found`);if(n.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it first`);let r=bp(n.id);if(r&&!r.finishedAt)throw new Error("a view is already being spun up for this Track");let o=n.boxes.find(i=>i.name===n.leadBox),s=String(t||"").trim()?String(t).trim().slice(0,40):"preview";dx(n.id,{name:s,box:n.leadBox});let a=String(t||"").trim()?`${OS}
166
+ ${d}`:d}let f=he(e,"said",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,text:r,...o?{kind:o}:{},...u.length?{attachments:u}:{}});o||bs(e,null);try{if(await Yn({cwd:n.cwd,sessionId:n.sessionId,sessionName:e.leadBox,agent:n.agent,agentCmd:Ts(n.agent),bailOnDialog:!0}),(ai.get(e.id)||0)!==a){!o&&r.trim()&&(ks(e,[r]),await Y());let d=new Error("delivery stopped \u2014 the message was handed back as the draft");throw d.interrupted=!0,d}if(await wD(e,t)){let d=jl(e.id),p={id:vs(),text:r,ts:Date.now(),...o?{kind:o}:{},...u.length?{attachments:u}:{}};d.items.unshift(p),xm(e.id);let m=new Error("lead is blocked on a prompt \u2014 message queued");throw m.requeued={id:p.id,position:d.items.length},m}await Le(e.leadBox,i,{...zt(t?.agent,i),kind:c?"lead-handoff-first-prompt":"say"})}catch(d){if(l&&!e.pendingHandoffHydrate&&(e.pendingHandoffHydrate=l),he(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:f.at,text:r,...d?.interrupted?{reason:"interrupted"}:{},...d?.requeued?{reason:"requeued"}:{}}),d?.requeued)return{queued:!0,...d.requeued};throw d}await $D(e,t,i)||(await QS(e.leadBox,t?.agent,i.length+8,i).catch(()=>{}),he(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:f.at,text:r,reason:"unsubmitted"}),o||ks(e,[r])),c&&await X({flow:"lead-handoff",phase:"first-prompt",trackId:e.id,sessionName:e.leadBox,agent:t?.agent,userTextLen:r.length})}function Sm(e,{actions:t}={}){jl(e).items.push({id:vs(),text:Wk(t),ts:Date.now(),kind:"ship-notify"}),xm(e)}async function It(e,t,{kind:n=null,attachments:r=null}={}){let o=Array.isArray(r)?r.filter(p=>p&&typeof p.rel=="string"):[];if((typeof t!="string"||!qo(t))&&!o.length)throw new Error("text (string) or an attachment required");let s=re(await z(),e);if(!s)throw new Error(`track "${e}" not found`);if(s.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it before driving it`);Hm(s);let a=s.boxes.find(p=>p.name===s.leadBox),i=qo(t);await YS(s,a,i,n),hi(e,"say");let c=await se(s.leadBox);if(c&&await Mm(c)?await ui(s,a,"say")?(await Y(),c=await se(s.leadBox)):c=null:!c&&await gi(s)&&(await Y(),c=await se(s.leadBox)),!c)throw new Error(`lead box "${s.leadBox}" is not running`);let l=jl(e),u=await Te(s.leadBox,{lines:je}).catch(()=>""),f=l.items.length>0||_c(a?.agent,u);if(!f&&Gr(a?.agent,u)){let p=await pn(s.leadBox).catch(()=>u);f=!!or(a,p)}if(f){let p={id:vs(),text:i,ts:Date.now(),...n?{kind:n}:{},...o.length?{attachments:o}:{}};return l.items.push(p),xm(e),n||bs(s,null),await Y(),{ok:!0,leadBox:s.leadBox,queued:!0,id:p.id,position:l.items.length}}let d;try{d=await dm(s,a,c,i,n,o)}catch(p){if(p?.code!=="cli-not-running"||!await ui(s,a,"say-gate")||(await Y(),c=await se(s.leadBox),!c))throw p;d=await dm(s,a,c,i,n,o)}return await Y(),d?.queued?{ok:!0,leadBox:s.leadBox,queued:!0,id:d.id,position:d.position}:{ok:!0,leadBox:s.leadBox}}async function vm(e,{hint:t}={}){let n=re(await z(),e);if(!n)throw new Error(`track "${e}" not found`);if(n.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it first`);let r=Ep(n.id);if(r&&!r.finishedAt)throw new Error("a view is already being spun up for this Track");let o=n.boxes.find(i=>i.name===n.leadBox),s=String(t||"").trim()?String(t).trim().slice(0,40):"preview";y0(n.id,{name:s,box:n.leadBox});let a=String(t||"").trim()?`${jS}
164
167
 
165
- What to preview: ${String(t).trim()}`:OS;try{await It(e,a,{kind:"spin-up-view"})}catch(i){throw wl(n.id,{error:"drive-failed"}),i}return{ok:!0,running:!0}}async function Pl(e){let t=re(await z(),e);if(!t)throw new Error(`track "${e}" not found`);if(t.archivedAt)throw new Error(`track "${e}" is archived`);ti.set(e,(ti.get(e)||0)+1);let n=ui(e),r=n.filter(i=>i.text&&!i.kind).map(i=>i.text),o=hs.get(e);if(o&&!o.canceled){o.clicks++;let i=null;return r.length&&(i=gs(t,r),await X()),{ok:!0,interrupted:!0,stopped:!1,stopping:!0,dropped:n.length,restored:i,draftRev:t.draftRev||0}}let s=sD(e,{droppedCount:n.length,droppedTexts:r});await Promise.race([s.settled,gr(eD)]);let a=re(await z(),e)||t;return{ok:!0,interrupted:s.result!=="no-session",stopped:s.result==="stopped"||s.result==="stopped-late",stopping:!s.result,dropped:n.length,restored:s.restored,draftRev:a.draftRev||0}}function KS(e){let t=hs.get(e);return!!t&&!t.canceled}function di(e,t){let n=hs.get(e);n&&!n.canceled&&(n.canceled=!0,n.cancelReason=t||null)}function bm(e){di(e,"track-ended"),ti.delete(e),ui(e)}function sD(e,{droppedCount:t,droppedTexts:n}){let r={startedAt:Date.now(),clicks:1,escSends:0,bgSends:0,queuedTexts:[...n],canceled:!1,cancelReason:null,result:null,restored:null},o;return r.settled=new Promise(s=>{o=s}),hs.set(e,r),(async()=>{let s=re(await z(),e),a=s?.boxes.find(g=>g.name===s.leadBox),i=s?await se(s.leadBox):null,c=!1,l=!1;if(i){e:for(let g=0;g<tD&&!r.canceled;g++){await $e(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.escSends++;for(let x of nD){await gr(x);let k=await Ae(s.leadBox,{lines:Le}).catch(()=>"");if(!pa(a?.agent,k)){c=!0;break e}}}if(!c){l=!0;for(let g=0;g<oD&&!r.canceled&&(await gr(rD),!r.canceled);g++){let x=await Ae(s.leadBox,{lines:Le}).catch(()=>"");if(!pa(a?.agent,x)){c=!0;break}await $e(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.bgSends++}}}let u=re(await z(),e)||s,f=u?.boxes.find(g=>g.name===u.leadBox)||a,d=null,p=null;u&&f&&i&&c&&!r.canceled&&(d=await lD(u,f).catch(()=>null),d||(p=await fD(u,f).catch(()=>null)));let m=u&&i&&!r.canceled?await iD(u).catch(()=>null):null,h=[d||p,...r.queuedTexts].filter(Boolean);u&&h.length&&(r.restored=gs(u,h),await X()),r.result=i?r.canceled?"canceled":c?l?"stopped-late":"stopped":"gave-up":"no-session",await aD(u||s,f,{ts:r.startedAt,result:r.result,dropped:t,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!d,lostRestored:!!p,queuedRestored:r.queuedTexts.length,shipDismissed:!!m,durationMs:Date.now()-r.startedAt,...r.cancelReason?{cancelReason:r.cancelReason}:{}}),await Y({flow:"interrupt",phase:r.result==="gave-up"?"failed":"done",trackId:e,sessionName:u?.leadBox,agent:f?.agent,result:r.result,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!d,lostRestored:!!p,queuedRestored:r.queuedTexts.length,shipDismissed:!!m}).catch(()=>{})})().catch(()=>{}).finally(()=>{r.result||(r.result=r.canceled?"canceled":"gave-up"),hs.get(e)===r&&hs.delete(e),o()}),r}async function aD(e,t,n){await _(e,{type:"turn.interrupted",actor:"user",source:"orchestrator",boxId:e.leadBox,provider:t?.agent||null,payload:n}).catch(()=>{})}async function iD(e){let t=kl(await L(e));if(!t?.offerId)return null;let n=t.offerType==="exists";return await _(e,{type:n?"pr.exists.answered":"pr.offer.answered",actor:"user",source:"orchestrator",boxId:t.box,payload:{ts:Date.now(),offerId:t.offerId,...n?{choice:"dismiss"}:{action:"dismiss",actions:null},reason:"interrupt"}}),t.offerId}async function lD(e,t){if(t?.agent!=="claude")return null;let n=[...e.events||[]].reverse().find(r=>r.type==="said"&&r.text);if(!n)return null;for(let r of cD){await gr(r);let o=await Ae(e.leadBox,{lines:Le}).catch(()=>""),s=ya(t.agent,o);if(s&&_c(n.text,s))return await GS(e.leadBox,t.agent,n.text.length+8),he(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:n.at,text:n.text}),n.text}return null}async function fD(e,t){if(t?.agent!=="claude")return null;let n=e.events||[],r=[...n].reverse().find(s=>s.type==="said"&&s.text);if(!r||r.kind||Date.now()-r.at>uD||n.some(s=>s.type==="unsaid"&&s.saidTs===r.at)||!Oe(r.text))return null;for(let s of dD){await gr(s);let a;try{a=await lf(t,{})}catch{return null}if(cy(a,r))return null;let i=await Ae(e.leadBox,{lines:Le}).catch(()=>"");if(ya(t.agent,i))return null}return he(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:r.at,text:r.text,reason:"lost"}),r.text}async function hD(e,t,n){if(!mD.has(t?.agent))return!0;for(let r=0;r<=Zp;r++){let o=!1;for(let s of pD){await gr(s);let a=await Ae(e.leadBox,{lines:Le}).catch(()=>""),i=ly(t.agent,n,a,{busy:pa(t.agent,a)});if(i==="stuck"){o=!0;break}if(i==="submitted")return!0}if(!o)return!0;r<Zp&&(await $e(e.leadBox,["Enter"],{kind:"submit-retry"}),Y({flow:"say",phase:"submit-retry",trackId:e.id,sessionName:e.leadBox,agent:t.agent,attempt:r+1,textHead:n.slice(0,120)}).catch(()=>{}))}return Y({flow:"say",phase:"submit-failed",trackId:e.id,sessionName:e.leadBox,agent:t.agent,retries:Zp,textHead:n.slice(0,120)}).catch(()=>{}),!1}async function GS(e,t,n,r=null){for(let o=0;o<3;o++){await $o(e,n,{kind:"unsend-wipe"}).catch(()=>{}),await gr(200);let s=await Ae(e,{lines:Le}).catch(()=>""),a=ya(t,s);if(!a||r&&!_c(r,a)&&!(t==="codex"&&Od(r,a)))return!0;n=a.length+8}return!1}function ws(e,t,{source:n}={}){e.draftRev=(e.draftRev||0)+1;let r=typeof t=="string"?t:"";return r.trim()?e.draft={text:r,updatedAt:Date.now(),...n?{source:n}:{}}:delete e.draft,e.draft||null}function gs(e,t){let n=[],r=o=>n.some(s=>Oe(s).includes(Oe(o)));for(let o of[e.draft?.text,...t])o&&o.trim()&&!r(o)&&n.push(o);return n.length?ws(e,n.join(`
168
+ What to preview: ${String(t).trim()}`:jS;try{await It(e,a,{kind:"spin-up-view"})}catch(i){throw kl(n.id,{error:"drive-failed"}),i}return{ok:!0,running:!0}}async function Ll(e){let t=re(await z(),e);if(!t)throw new Error(`track "${e}" not found`);if(t.archivedAt)throw new Error(`track "${e}" is archived`);ai.set(e,(ai.get(e)||0)+1);let n=mi(e),r=n.filter(i=>i.text&&!i.kind).map(i=>i.text),o=ys.get(e);if(o&&!o.canceled){o.clicks++;let i=null;return r.length&&(i=ks(t,r),await Y()),{ok:!0,interrupted:!0,stopped:!1,stopping:!0,dropped:n.length,restored:i,draftRev:t.draftRev||0}}let s=SD(e,{droppedCount:n.length,droppedTexts:r});await Promise.race([s.settled,ao(gD)]);let a=re(await z(),e)||t;return{ok:!0,interrupted:s.result!=="no-session",stopped:s.result==="stopped"||s.result==="stopped-late",stopping:!s.result,dropped:n.length,restored:s.restored,draftRev:a.draftRev||0}}function ZS(e){let t=ys.get(e);return!!t&&!t.canceled}function hi(e,t){let n=ys.get(e);n&&!n.canceled&&(n.canceled=!0,n.cancelReason=t||null)}function Tm(e){hi(e,"track-ended"),ai.delete(e),mi(e)}function SD(e,{droppedCount:t,droppedTexts:n}){let r={startedAt:Date.now(),clicks:1,escSends:0,bgSends:0,queuedTexts:[...n],canceled:!1,cancelReason:null,result:null,restored:null},o;return r.settled=new Promise(s=>{o=s}),ys.set(e,r),(async()=>{let s=re(await z(),e),a=s?.boxes.find(g=>g.name===s.leadBox),i=s?await se(s.leadBox):null,c=!1,l=!1;if(i){e:for(let g=0;g<yD&&!r.canceled;g++){await Ie(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.escSends++;for(let x of bD){await ao(x);let k=await Te(s.leadBox,{lines:je}).catch(()=>"");if(!Bo(a?.agent,k)){c=!0;break e}}}if(!c){l=!0;for(let g=0;g<xD&&!r.canceled&&(await ao(kD),!r.canceled);g++){let x=await Te(s.leadBox,{lines:je}).catch(()=>"");if(!Bo(a?.agent,x)){c=!0;break}await Ie(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.bgSends++}}}let u=re(await z(),e)||s,f=u?.boxes.find(g=>g.name===u.leadBox)||a,d=null,p=null;u&&f&&i&&c&&!r.canceled&&(d=await AD(u,f).catch(()=>null),d||(p=await RD(u,f).catch(()=>null)));let m=u&&i&&!r.canceled?await TD(u).catch(()=>null):null,h=[d||p,...r.queuedTexts].filter(Boolean);u&&h.length&&(r.restored=ks(u,h),await Y()),r.result=i?r.canceled?"canceled":c?l?"stopped-late":"stopped":"gave-up":"no-session",await vD(u||s,f,{ts:r.startedAt,result:r.result,dropped:t,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!d,lostRestored:!!p,queuedRestored:r.queuedTexts.length,shipDismissed:!!m,durationMs:Date.now()-r.startedAt,...r.cancelReason?{cancelReason:r.cancelReason}:{}}),await X({flow:"interrupt",phase:r.result==="gave-up"?"failed":"done",trackId:e,sessionName:u?.leadBox,agent:f?.agent,result:r.result,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!d,lostRestored:!!p,queuedRestored:r.queuedTexts.length,shipDismissed:!!m}).catch(()=>{})})().catch(()=>{}).finally(()=>{r.result||(r.result=r.canceled?"canceled":"gave-up"),ys.get(e)===r&&ys.delete(e),o()}),r}async function vD(e,t,n){await _(e,{type:"turn.interrupted",actor:"user",source:"orchestrator",boxId:e.leadBox,provider:t?.agent||null,payload:n}).catch(()=>{})}async function TD(e){let t=Tl(await L(e));if(!t?.offerId)return null;let n=t.offerType==="exists";return await _(e,{type:n?"pr.exists.answered":"pr.offer.answered",actor:"user",source:"orchestrator",boxId:t.box,payload:{ts:Date.now(),offerId:t.offerId,...n?{choice:"dismiss"}:{action:"dismiss",actions:null},reason:"interrupt"}}),t.offerId}async function AD(e,t){if(t?.agent!=="claude")return null;let n=[...e.events||[]].reverse().find(r=>r.type==="said"&&r.text);if(!n)return null;for(let r of ED){await ao(r);let o=await Te(e.leadBox,{lines:je}).catch(()=>""),s=ba(t.agent,o);if(s&&Ic(n.text,s))return await QS(e.leadBox,t.agent,n.text.length+8),he(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:n.at,text:n.text}),n.text}return null}async function RD(e,t){if(t?.agent!=="claude")return null;let n=e.events||[],r=[...n].reverse().find(s=>s.type==="said"&&s.text);if(!r||r.kind||Date.now()-r.at>_D||n.some(s=>s.type==="unsaid"&&s.saidTs===r.at)||!Oe(r.text))return null;for(let s of ID){await ao(s);let a;try{a=await hf(t,{})}catch{return null}if(sy(a,r))return null;let i=await Te(e.leadBox,{lines:je}).catch(()=>"");if(ba(t.agent,i))return null}return he(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:r.at,text:r.text,reason:"lost"}),r.text}async function $D(e,t,n){return xa({sessionName:e.leadBox,agent:t?.agent,agentCmd:Ts(t?.agent),text:n,trackId:e.id,flow:"say"})}async function QS(e,t,n,r=null){for(let o=0;o<3;o++){await $o(e,n,{kind:"unsend-wipe"}).catch(()=>{}),await ao(200);let s=await Te(e,{lines:je}).catch(()=>""),a=ba(t,s);if(!a||r&&!Ic(r,a)&&!(t==="codex"&&Pd(r,a)))return!0;n=a.length+8}return!1}function bs(e,t,{source:n}={}){e.draftRev=(e.draftRev||0)+1;let r=typeof t=="string"?t:"";return r.trim()?e.draft={text:r,updatedAt:Date.now(),...n?{source:n}:{}}:delete e.draft,e.draft||null}function ks(e,t){let n=[],r=o=>n.some(s=>Oe(s).includes(Oe(o)));for(let o of[e.draft?.text,...t])o&&o.trim()&&!r(o)&&n.push(o);return n.length?bs(e,n.join(`
166
169
 
167
- `),{source:"restore"})?.text??null:null}function gD(e,t){let n=Oe(t);if(!n)return!1;if(ao(e.id).some(o=>Oe(o.text)===n))return!0;let r=e.events||[];for(let o=r.length-1;o>=0;o--){let s=r[o];if(typeof s.at=="number"&&Date.now()-s.at>wD)break;if(!(s.type!=="said"||!s.text||Oe(s.text)!==n))return!r.some(a=>a.type==="unsaid"&&a.saidTs===s.at)}return!1}async function km(e,t,{rev:n=null}={}){if(typeof t!="string")throw new Error("text (string) required");let r=re(await z(),e);if(!r)throw new Error(`track "${e}" not found`);let o=t,s=Uo(t);if(typeof n=="number"&&n<(r.draftRev||0)&&s&&gD(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;Oe(o).includes(Oe(i))?ws(r,o):ws(r,`${i}
170
+ `),{source:"restore"})?.text??null:null}function CD(e,t){let n=Oe(t);if(!n)return!1;if(so(e.id).some(o=>Oe(o.text)===n))return!0;let r=e.events||[];for(let o=r.length-1;o>=0;o--){let s=r[o];if(typeof s.at=="number"&&Date.now()-s.at>OD)break;if(!(s.type!=="said"||!s.text||Oe(s.text)!==n))return!r.some(a=>a.type==="unsaid"&&a.saidTs===s.at)}return!1}async function Em(e,t,{rev:n=null}={}){if(typeof t!="string")throw new Error("text (string) required");let r=re(await z(),e);if(!r)throw new Error(`track "${e}" not found`);let o=t,s=qo(t);if(typeof n=="number"&&n<(r.draftRev||0)&&s&&CD(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;Oe(o).includes(Oe(i))?bs(r,o):bs(r,`${i}
168
171
 
169
- ${o}`,{source:"restore"})}else ws(r,o);return await X(),{ok:!0,draft:r.draft||null,rev:r.draftRev||0}}async function xm(e,t){if(typeof t!="string"||!t.trim())throw new Error("model (string) required");let n=t.trim(),r=re(await z(),e);if(!r)throw new Error(`track "${e}" not found`);let o=await se(r.leadBox);if(!o)throw new Error(`lead box "${r.leadBox}" is not running`);let a=r.boxes.find(f=>f.name===r.leadBox)?.agent||o.agent||"claude",i=wk(a,n),l=[...r.events||[]].reverse().find(f=>f.type==="model-change")?.to??null;l||(l=(await aa(o.cwd,o.sessionId,{fallbackNewest:!1}).catch(()=>null))?.model??null),await Xn({cwd:o.cwd,sessionId:o.sessionId,sessionName:r.leadBox,agent:o.agent,agentCmd:ci(o.agent)});let u=await gk(a,r.leadBox,i);return he(r,"model-change",{to:n,from:l,box:r.leadBox,agent:a,verified:!!u.verified}),await X(),{ok:!0,requested:n,leadBox:r.leadBox,...u}}async function VS(e){for(let t of e){if(!t||!await Ho(t))continue;let n=await Vb(t).catch(()=>null);if(!n)continue;if((await W.stat(G.join(n,".git")).catch(()=>null))?.isDirectory())return n}return null}function gt(e){let t=e;return t?t.kind==="multi"?Array.isArray(t.repos)?t.repos.filter(Boolean):[]:t.base?[{name:G.basename(t.base),dir:t.dir??null,base:t.base,baseRef:t.baseRef??null,repo:t.repo??null}]:[]:[]}async function as(e){let t=[];for(let n of gt(e?.workspace)){if(!n?.dir)continue;let r=await Ea(n.dir,{ignorePlumbing:!0}).catch(()=>!1),o=await Aa(n.dir,n.baseRef).catch(()=>0);(r||o>0)&&t.push({...n,dirty:r,ahead:o})}return t}async function zS(e){let t=e;typeof t=="string"&&!G.isAbsolute(t)&&/^[^/\s]+\/[^/\s]+$/.test(t)&&(t=await bo(t)??await Vi(t));let n=await VS([t]);if(!n)throw new Error(`tagged repo "${e}" is not a usable base (need a primary checkout or a synced owner/name)`);return n}async function yD(e,t,n,r){let o=`track/${Um(t)}-${e}`,s=[];try{await W.mkdir(n,{recursive:!0});let a=new Set([".bostrat"]);for(let i of r){let c=await zS(i);if(s.some(p=>p.base===c))throw new Error(`repo tagged twice: ${i}`);let l=await me(c).catch(()=>null),u=G.basename(c);a.has(u)&&l&&(u=l.replace("/","-"));for(let p=2;a.has(u);p++)u=`${G.basename(c)}-${p}`;a.add(u);let f=G.join(n,u),d=await Ko(c);await qo(c,f,o,d),s.push({name:u,dir:f,base:c,baseRef:d,repo:l})}return await fi(n,s,o),{dir:n,kind:"multi",branch:o,repos:s}}catch(a){for(let i of s)await pt(i.base,i.dir).catch(()=>{});throw await W.rm(n,{recursive:!0,force:!0}).catch(()=>{}),a}}async function Sm(e,t){let n=await z(),r=re(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error("track is archived \u2014 unarchive it first");let o=r.workspace;if(o?.kind!=="multi")throw new Error("live re-tagging needs a multi-repo Track \u2014 a single-repo Track's workspace IS its repo checkout; create the Track with multiple repos tagged instead");let s=await zS(typeof t=="string"?t.trim():t);if((o.repos??[]).some(d=>d?.base===s))throw new Error(`repo already tagged: ${t}`);let a=await me(s).catch(()=>null),i=new Set([".bostrat",...(o.repos??[]).map(d=>d?.name).filter(Boolean)]),c=G.basename(s);i.has(c)&&a&&(c=a.replace("/","-"));for(let d=2;i.has(c);d++)c=`${G.basename(s)}-${d}`;let l=G.join(o.dir,c),u=await Ko(s);await zb(s,o.branch)?await jc(s,l,o.branch):await qo(s,l,o.branch,u);let f={name:c,dir:l,base:s,baseRef:u,repo:a};return o.repos=[...(o.repos??[]).filter(Boolean),f],await fi(o.dir,o.repos,o.branch),he(r,"retagged",{action:"add",repo:a??s,name:c,workspace:JS(o)}),await X(),f}async function vm(e,t){let n=await z(),r=re(n,e);if(!r)throw new Error(`track "${e}" not found`);let o=r.workspace;if(o?.kind!=="multi")throw new Error("live re-tagging needs a multi-repo Track");let s=(o.repos??[]).find(c=>c&&(c.name===t||c.repo===t||c.base===t));if(!s)throw new Error(`repo "${t}" is not tagged on this Track`);if((o.repos??[]).filter(Boolean).length<=1)throw new Error("can't untag the last repo \u2014 archive or delete the Track instead");for(let c of wt.values())if(c.trackId===e&&!c.finishedAt)throw new Error("a subtask is still running on this Track \u2014 wait for it to merge back before untagging");let a=await Ea(s.dir,{ignorePlumbing:!0}).catch(()=>!1),i=await Aa(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 pt(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 fi(o.dir,o.repos,o.branch),he(r,"retagged",{action:"remove",repo:s.repo??s.base,name:s.name,workspace:JS(o)}),await X(),{removed:s.name}}async function bD(e,t,{repo:n,repos:r,cwd:o}={}){await W.mkdir(Za,{recursive:!0});let s=G.join(Za,e),a=Array.isArray(r)?r.map(c=>typeof c=="string"?c.trim():"").filter(Boolean):[];if(a.length>=2)return yD(e,t,s,a);a.length===1&&!n&&(n=a[0]),typeof n=="string"&&!G.isAbsolute(n)&&/^[^/\s]+\/[^/\s]+$/.test(n)&&(n=await bo(n)??await Vi(n));let i=await VS([n,o,BP]);if(i){let c=`track/${Um(t)}-${e}`;try{let l=await Ko(i);await qo(i,s,c,l),await ri(s);let u=await me(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 vf(s),await ri(s),{dir:s,base:null,branch:null,kind:"repo"}}async function ri(e){try{await W.writeFile(G.join(e,"AGENTS.md"),Xa,{flag:"wx"})}catch{return}await vD(e,["/AGENTS.md"])}function SD(e,t){let n=e.map(r=>`- \`${r.name}/\`${r.repo?` \u2014 github.com/${r.repo}`:""}${r.baseRef?` (forked from ${r.baseRef})`:""}`).join(`
170
- `);return`${xD}
172
+ ${o}`,{source:"restore"})}else bs(r,o);return await Y(),{ok:!0,draft:r.draft||null,rev:r.draftRev||0}}async function Am(e,t){if(typeof t!="string"||!t.trim())throw new Error("model (string) required");let n=t.trim(),r=re(await z(),e);if(!r)throw new Error(`track "${e}" not found`);let o=await se(r.leadBox);if(!o)throw new Error(`lead box "${r.leadBox}" is not running`);let a=r.boxes.find(f=>f.name===r.leadBox)?.agent||o.agent||"claude",i=vk(a,n),l=[...r.events||[]].reverse().find(f=>f.type==="model-change")?.to??null;l||(l=(await ua(o.cwd,o.sessionId,{fallbackNewest:!1}).catch(()=>null))?.model??null),await Yn({cwd:o.cwd,sessionId:o.sessionId,sessionName:r.leadBox,agent:o.agent,agentCmd:Ts(o.agent)});let u=await Tk(a,r.leadBox,i);return he(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 ev(e){for(let t of e){if(!t||!await Ko(t))continue;let n=await ek(t).catch(()=>null);if(!n)continue;if((await W.stat(G.join(n,".git")).catch(()=>null))?.isDirectory())return n}return null}function gt(e){let t=e;return t?t.kind==="multi"?Array.isArray(t.repos)?t.repos.filter(Boolean):[]:t.base?[{name:G.basename(t.base),dir:t.dir??null,base:t.base,baseRef:t.baseRef??null,repo:t.repo??null}]:[]:[]}async function ls(e){let t=[];for(let n of gt(e?.workspace)){if(!n?.dir)continue;let r=await $a(n.dir,{ignorePlumbing:!0}).catch(()=>!1),o=await Oa(n.dir,n.baseRef).catch(()=>0);(r||o>0)&&t.push({...n,dirty:r,ahead:o})}return t}async function tv(e){let t=e;typeof t=="string"&&!G.isAbsolute(t)&&/^[^/\s]+\/[^/\s]+$/.test(t)&&(t=await bo(t)??await Yi(t));let n=await ev([t]);if(!n)throw new Error(`tagged repo "${e}" is not a usable base (need a primary checkout or a synced owner/name)`);return n}async function MD(e,t,n,r){let o=`track/${Gm(t)}-${e}`,s=[];try{await W.mkdir(n,{recursive:!0});let a=new Set([".bostrat"]);for(let i of r){let c=await tv(i);if(s.some(p=>p.base===c))throw new Error(`repo tagged twice: ${i}`);let l=await me(c).catch(()=>null),u=G.basename(c);a.has(u)&&l&&(u=l.replace("/","-"));for(let p=2;a.has(u);p++)u=`${G.basename(c)}-${p}`;a.add(u);let f=G.join(n,u),d=await zo(c);await Vo(c,f,o,d),s.push({name:u,dir:f,base:c,baseRef:d,repo:l})}return await wi(n,s,o),{dir:n,kind:"multi",branch:o,repos:s}}catch(a){for(let i of s)await pt(i.base,i.dir).catch(()=>{});throw await W.rm(n,{recursive:!0,force:!0}).catch(()=>{}),a}}async function _m(e,t){let n=await z(),r=re(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error("track is archived \u2014 unarchive it first");let o=r.workspace;if(o?.kind!=="multi")throw new Error("live re-tagging needs a multi-repo Track \u2014 a single-repo Track's workspace IS its repo checkout; create the Track with multiple repos tagged instead");let s=await tv(typeof t=="string"?t.trim():t);if((o.repos??[]).some(d=>d?.base===s))throw new Error(`repo already tagged: ${t}`);let a=await me(s).catch(()=>null),i=new Set([".bostrat",...(o.repos??[]).map(d=>d?.name).filter(Boolean)]),c=G.basename(s);i.has(c)&&a&&(c=a.replace("/","-"));for(let d=2;i.has(c);d++)c=`${G.basename(s)}-${d}`;let l=G.join(o.dir,c),u=await zo(s);await tk(s,o.branch)?await Hc(s,l,o.branch):await Vo(s,l,o.branch,u);let f={name:c,dir:l,base:s,baseRef:u,repo:a};return o.repos=[...(o.repos??[]).filter(Boolean),f],await wi(o.dir,o.repos,o.branch),he(r,"retagged",{action:"add",repo:a??s,name:c,workspace:nv(o)}),await Y(),f}async function Im(e,t){let n=await z(),r=re(n,e);if(!r)throw new Error(`track "${e}" not found`);let o=r.workspace;if(o?.kind!=="multi")throw new Error("live re-tagging needs a multi-repo Track");let s=(o.repos??[]).find(c=>c&&(c.name===t||c.repo===t||c.base===t));if(!s)throw new Error(`repo "${t}" is not tagged on this Track`);if((o.repos??[]).filter(Boolean).length<=1)throw new Error("can't untag the last repo \u2014 archive or delete the Track instead");for(let c of wt.values())if(c.trackId===e&&!c.finishedAt)throw new Error("a subtask is still running on this Track \u2014 wait for it to merge back before untagging");let a=await $a(s.dir,{ignorePlumbing:!0}).catch(()=>!1),i=await Oa(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 pt(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 wi(o.dir,o.repos,o.branch),he(r,"retagged",{action:"remove",repo:s.repo??s.base,name:s.name,workspace:nv(o)}),await Y(),{removed:s.name}}async function ND(e,t,{repo:n,repos:r,cwd:o}={}){await W.mkdir(ri,{recursive:!0});let s=G.join(ri,e),a=Array.isArray(r)?r.map(c=>typeof c=="string"?c.trim():"").filter(Boolean):[];if(a.length>=2)return MD(e,t,s,a);a.length===1&&!n&&(n=a[0]),typeof n=="string"&&!G.isAbsolute(n)&&/^[^/\s]+\/[^/\s]+$/.test(n)&&(n=await bo(n)??await Yi(n));let i=await ev([n,o,eD]);if(i){let c=`track/${Gm(t)}-${e}`;try{let l=await zo(i);await Vo(i,s,c,l),await ci(s);let u=await me(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 Rf(s),await ci(s),{dir:s,base:null,branch:null,kind:"repo"}}async function ci(e){try{await W.writeFile(G.join(e,"AGENTS.md"),ni,{flag:"wx"})}catch{return}await jD(e,["/AGENTS.md"])}function BD(e,t){let n=e.map(r=>`- \`${r.name}/\`${r.repo?` \u2014 github.com/${r.repo}`:""}${r.baseRef?` (forked from ${r.baseRef})`:""}`).join(`
173
+ `);return`${DD}
171
174
 
172
175
  This directory is NOT a git repo. It is a bostrat Track workspace holding one
173
176
  git worktree per tagged repo, ALL on the same branch \`${t}\`:
@@ -179,20 +182,20 @@ push / open PRs) in each repo separately, always on that shared branch. Work
179
182
  only needs to land in the repos it actually touches \u2014 an untouched repo's
180
183
  branch simply stays at its fork point and never gets pushed. When asked to run
181
184
  or preview an app, run it from that app's own repo directory.
182
- `}async function fi(e,t,n){let r=SD(t,n);for(let o of["CLAUDE.md","AGENTS.md"])await W.writeFile(G.join(e,o),r).catch(()=>{})}async function XS(e){let{stdout:t}=await PS("git",["-C",e,"rev-parse","--git-path","info/exclude"]);return G.resolve(e,t.trim())}async function vD(e,t){try{let n=await XS(e);await W.mkdir(G.dirname(n),{recursive:!0});let r=await W.readFile(n,"utf8").catch(()=>""),o=t.filter(s=>!r.split(`
185
+ `}async function wi(e,t,n){let r=BD(t,n);for(let o of["CLAUDE.md","AGENTS.md"])await W.writeFile(G.join(e,o),r).catch(()=>{})}async function ov(e){let{stdout:t}=await HS("git",["-C",e,"rev-parse","--git-path","info/exclude"]);return G.resolve(e,t.trim())}async function jD(e,t){try{let n=await ov(e);await W.mkdir(G.dirname(n),{recursive:!0});let r=await W.readFile(n,"utf8").catch(()=>""),o=t.filter(s=>!r.split(`
183
186
  `).includes(s));o.length&&await W.appendFile(n,(r.endsWith(`
184
187
  `)||!r?"":`
185
188
  `)+o.join(`
186
189
  `)+`
187
- `)}catch{}}async function TD(e,t){try{let n=await XS(e),r=await W.readFile(n,"utf8"),o=r.split(`
190
+ `)}catch{}}async function LD(e,t){try{let n=await ov(e),r=await W.readFile(n,"utf8"),o=r.split(`
188
191
  `).filter(s=>s!==t);o.length!==r.split(`
189
192
  `).length&&await W.writeFile(n,o.join(`
190
- `))}catch{}}async function Tm(){let e={refreshed:0,removed:0,codexGlobal:null};try{await W.mkdir(rn,{recursive:!0}),await W.writeFile(G.join(rn,"CLAUDE.md"),kD).catch(()=>{}),await W.writeFile(G.join(rn,"AGENTS.md"),Xa).catch(()=>{});let t=process.env.CODEX_HOME||G.join(process.env.HOME||"/tmp",".codex");if((await W.stat(t).catch(()=>null))?.isDirectory()){let r=G.join(t,"AGENTS.md"),o=await W.readFile(r,"utf8").catch(()=>null);o===null?(await W.writeFile(r,em,{flag:"wx"}).catch(()=>{}),e.codexGlobal="created"):Qp(o)&&o!==em&&(await W.writeFile(r,em).catch(()=>{}),e.codexGlobal="refreshed")}for(let r of[Za,bs]){let o=await W.readdir(r,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(!s.isDirectory())continue;let a=G.join(r,s.name),i=G.join(a,"AGENTS.md"),c=await W.readFile(i,"utf8").catch(()=>null);c!==null&&Qp(c)&&c!==Xa&&(await W.writeFile(i,Xa).catch(()=>{}),e.refreshed++);let l=G.join(a,"CLAUDE.md"),u=await W.readFile(l,"utf8").catch(()=>null);u!==null&&Qp(u)&&(await W.rm(l,{force:!0}).catch(()=>{}),await TD(a,"/CLAUDE.md"),e.removed++)}}}catch{}return e}async function ZS(e){let t=e.workspace;if(!(!t||!t.dir))try{if(t.kind==="multi"){for(let n of gt(t))n.base&&n.dir&&await pt(n.base,n.dir).catch(()=>{});await W.rm(t.dir,{recursive:!0,force:!0})}else t.kind==="worktree"&&t.base?await pt(t.base,t.dir):await W.rm(t.dir,{recursive:!0,force:!0})}catch{}}async function Dl({name:e,cwd:t,repo:n,repos:r,agent:o="claude",skipPermissions:s=!0}){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");let a=await li(o,s),i=await z(),c=ks().slice(0,8),l=await bD(c,e,{repo:n,repos:r,cwd:t}),u=new Set(i.tracks.flatMap(m=>(m.boxes||[]).map(h=>h.name))),f=`${e.trim()} lead`;u.has(fc(f))&&(f=`${e.trim().slice(0,50).trim()} ${c} lead`);let d=await zn(f,l.dir,{agentCmd:a,agent:o,freshWorkspace:!0});ma({cwd:d.cwd,sessionName:d.name,agent:o,agentCmd:a});let p={id:c,name:e.trim(),cwd:d.cwd,workspace:l,leadBox:d.name,boxes:[Mm(d,"lead","live")],events:[],createdAt:Date.now()};return he(p,"opened",{agent:o,box:d.name,skipPermissions:s,name:p.name,cwd:p.cwd,workspace:{base:l.base??null,branch:l.branch,kind:l.kind,...l.baseRef?{baseRef:l.baseRef}:{},...l.repo?{repo:l.repo}:{},...l.repos?{repos:l.repos.map(({name:m,base:h,baseRef:g,repo:x})=>({name:m,base:h,baseRef:g,repo:x}))}:{}}}),i.tracks.push(p),await X(),_t(p)}async function Em({provider:e="claude",fresh:t=!1}={}){if(!ED.has(e))throw new Error(`unknown setup provider "${e}" (claude | codex | cursor)`);let r=(await z()).tracks.find(u=>u.kind==="setup"&&u.setup?.provider===e&&!u.archivedAt);if(r){if(!t){let u=await _t(r);if(u.boxes.find(d=>d.name===u.leadBox)?.state==="live")return u}await io(r.id).catch(()=>{})}let o=(await li(e,!1)).replace(/\s+--(?:dangerously-skip-permissions|dangerously-bypass-approvals-and-sandbox)\b/g,""),s=ks().slice(0,8),a=G.join(rn,"setup",s);await W.mkdir(a,{recursive:!0});let i=await zn(`Connect ${e} ${s}`,a,{agentCmd:o,agent:e,firstRun:!0});e==="codex"&&ma({cwd:i.cwd,sessionName:i.name,agent:e,agentCmd:o});let c={id:s,name:`Connect ${e}`,kind:"setup",setup:{provider:e,startedAt:Date.now(),connectedAt:null},cwd:i.cwd,workspace:{dir:a,base:null,branch:null,kind:"scratch"},leadBox:i.name,boxes:[Mm(i,"lead","live")],events:[],createdAt:Date.now()};return he(c,"opened",{agent:e,box:i.name,skipPermissions:!1,trackKind:"setup",name:c.name,cwd:c.cwd,workspace:{base:null,branch:null,kind:"scratch"}}),(await z()).tracks.push(c),await X(),_t(c)}async function Am(e,t,n){await Gu(t.cwd).catch(()=>{}),await yx(e).catch(()=>{});let r=ys.get(e);r&&!r.finishedAt&&(r.error=n,r.finishedAt=Date.now()),ys.delete(e),t.handoff&&!t.handoff.finishedAt&&(t.handoff.step="error",t.handoff.error=n,t.handoff.finishedAt=Date.now());for(let a of co(e))a.finishedAt||(a.canceled=!0,a.finishedAt=Date.now()),await qm(a).catch(()=>{}),wt.delete(a.id);for(let a of Object.values(t.subtasks||{}))a.finishedAt||(a.step="error",a.error=n,a.canceled=!0,a.finishedAt=Date.now());let o=await z(),s=new Set((o.tracks||[]).filter(a=>a.id!==e&&!a.archivedAt).flatMap(a=>(a.boxes||[]).map(i=>i.name)));for(let a of t.boxes)s.has(a.name)||await Ct(a.name).catch(()=>{})}async function _m(e,{cascadeMocks:t=!0,cascadeRunbooks:n=!1}={}){let r=await z(),o=r.tracks.findIndex(a=>a.id===e);if(o===-1)throw new Error(`track "${e}" not found`);let s=r.tracks[o];return t||await Fx(s),bm(e),await Am(e,s,"track deleted"),n?await gS(e).catch(()=>{}):await wS(e).catch(()=>{}),await kk(),await ZS(s),t&&await Ux(e).catch(()=>{}),t?await oS(e).catch(()=>{}):await rS(s).catch(()=>{}),he(s,"track-deleted",{name:s.name,boxes:s.boxes.length,ageMs:s.createdAt?Date.now()-s.createdAt:null}),r.tracks.splice(o,1),await X(),{ok:!0,id:e,name:s.name,boxes:s.boxes.length}}async function io(e){let t=await z(),n=re(t,e);if(!n)throw new Error(`track "${e}" not found`);if(n.archivedAt)throw new Error(`track "${e}" is already archived`);return n.archivedAt=Date.now(),bm(e),he(n,"archived",{boxes:n.boxes.length}),await X(),n.kind==="setup"?(await QS(e),_t(n)):(oi.add(e),ID(e).catch(()=>{}).finally(()=>oi.delete(e)),{...await _t(n),archiving:!0})}async function ID(e){try{await RD(e)}catch{}await QS(e).catch(()=>{})}async function QS(e){let t=await z(),n=re(t,e);if(!(!n||!n.archivedAt)){await Am(e,n,"track archived");for(let r of n.boxes)Mn.has(r.state)||(r.state="stopped");await X()}}async function RD(e){let t=await z(),n=re(t,e);if(!n||!n.archivedAt)return;let r=null,o=[],s="derived",a=(n.events||[]).some(l=>l.type==="said"),i=n.leadBox?await se(n.leadBox).catch(()=>null):null;if(i?.cwd&&a)try{({text:r,items:o}=await Ky(n.leadBox,i.cwd,{timeoutMs:_D})),s="lead-cli"}catch{}if(r||(r=sb(n,await L(n).catch(()=>[]))),!r)return;let c={text:r,source:s,at:Date.now()};o.length&&(c.items=o),n.beat=c,await _(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 X()}async function kn(e,t){let n=await qe(e,t).catch(()=>null);if(!n?.archiveOnMerge||!n.trackId)return!1;let r=await ev(n);if(r.length){for(let o of r)await Yr(o.repo,o.number,!0).catch(()=>{});return!1}try{return await io(n.trackId),!0}catch(o){if(/already archived/i.test(String(o?.message||o)))return!1;throw o}}async function ev(e){return(await Xr().catch(()=>[])).filter(n=>n.trackId===e.trackId&&n.state!=="merged"&&n.state!=="closed"&&n.state!=="lost"&&!(n.repo===e.repo&&n.number===e.number))}async function xn(e,t){return Bl(e,t,"merged")}async function Bl(e,t,n="merged"){let r=await qe(e,t).catch(()=>null);if(!r?.notifyOnMerge||r.archiveOnMerge||!r.trackId)return!1;let o={repo:r.repo??null,number:r.number,title:r.title??null,url:r.url??null,headRef:r.headRef??null,outcome:n},s=await ev(r);if(s.length){let i=[...r.notifyPending||[],o];for(let c of s)await Gk(c.repo,c.number,i).catch(()=>{});return!1}let a=[...r.notifyPending||[],o];try{return await It(r.trackId,tv(a),{kind:"merge-notify"}),!0}catch{return!1}}function tv(e){let t=i=>`${i.repo?`${i.repo}`:""}#${i.number}${i.title?` "${i.title}"`:""}${i.url?` (${i.url})`:""}`;if(e.length===1){let i=e[0],c=`#${i.number}${i.title?` "${i.title}"`:""}`;return i.outcome!=="merged"?`PR ${c}${i.url?` (${i.url})`:""}${i.headRef?` \u2014 branch ${i.headRef} \u2014`:""} was ${CS[i.outcome]??i.outcome}. This is an automated notification: the work did NOT land \u2014 check whether it still needs to ship another way. If not, say so briefly.`:`PR ${c}${i.url?` (${i.url})`:""}${i.headRef?` \u2014 branch ${i.headRef} \u2014`:""} has merged. This is an automated merge notification: pick up whatever follow-up work this merge unblocks (dependent tasks, cleanup, next steps that were waiting on it). If nothing needs doing, say so briefly.`}let n=e.filter(i=>i.outcome==="merged"),r=e.filter(i=>i.outcome!=="merged"),o=r.length?`${n.length} of the ${e.length} PRs on this Track merged; ${r.length} did not land:`:`All ${e.length} PRs on this Track have merged:`,s=e.map(i=>`- ${t(i)} \u2014 ${CS[i.outcome]??i.outcome}`).join(`
193
+ `))}catch{}}async function Rm(){let e={refreshed:0,removed:0,codexGlobal:null};try{await W.mkdir(sn,{recursive:!0}),await W.writeFile(G.join(sn,"CLAUDE.md"),PD).catch(()=>{}),await W.writeFile(G.join(sn,"AGENTS.md"),ni).catch(()=>{});let t=process.env.CODEX_HOME||G.join(process.env.HOME||"/tmp",".codex");if((await W.stat(t).catch(()=>null))?.isDirectory()){let r=G.join(t,"AGENTS.md"),o=await W.readFile(r,"utf8").catch(()=>null);o===null?(await W.writeFile(r,sm,{flag:"wx"}).catch(()=>{}),e.codexGlobal="created"):om(o)&&o!==sm&&(await W.writeFile(r,sm).catch(()=>{}),e.codexGlobal="refreshed")}for(let r of[ri,Ss]){let o=await W.readdir(r,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(!s.isDirectory())continue;let a=G.join(r,s.name),i=G.join(a,"AGENTS.md"),c=await W.readFile(i,"utf8").catch(()=>null);c!==null&&om(c)&&c!==ni&&(await W.writeFile(i,ni).catch(()=>{}),e.refreshed++);let l=G.join(a,"CLAUDE.md"),u=await W.readFile(l,"utf8").catch(()=>null);u!==null&&om(u)&&(await W.rm(l,{force:!0}).catch(()=>{}),await LD(a,"/CLAUDE.md"),e.removed++)}}}catch{}return e}async function sv(e){let t=e.workspace;if(!(!t||!t.dir))try{if(t.kind==="multi"){for(let n of gt(t))n.base&&n.dir&&await pt(n.base,n.dir).catch(()=>{});await W.rm(t.dir,{recursive:!0,force:!0})}else t.kind==="worktree"&&t.base?await pt(t.base,t.dir):await W.rm(t.dir,{recursive:!0,force:!0})}catch{}}async function Fl({name:e,cwd:t,repo:n,repos:r,agent:o="claude",skipPermissions:s=!0}){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");let a=await pi(o,s),i=await z(),c=vs().slice(0,8),l=await ND(c,e,{repo:n,repos:r,cwd:t}),u=new Set(i.tracks.flatMap(m=>(m.boxes||[]).map(h=>h.name))),f=`${e.trim()} lead`;u.has(wc(f))&&(f=`${e.trim().slice(0,50).trim()} ${c} lead`);let d=await Jn(f,l.dir,{agentCmd:a,agent:o,freshWorkspace:!0});wa({cwd:d.cwd,sessionName:d.name,agent:o,agentCmd:a});let p={id:c,name:e.trim(),cwd:d.cwd,workspace:l,leadBox:d.name,boxes:[jm(d,"lead","live")],events:[],createdAt:Date.now()};return he(p,"opened",{agent:o,box:d.name,skipPermissions:s,name:p.name,cwd:p.cwd,workspace:{base:l.base??null,branch:l.branch,kind:l.kind,...l.baseRef?{baseRef:l.baseRef}:{},...l.repo?{repo:l.repo}:{},...l.repos?{repos:l.repos.map(({name:m,base:h,baseRef:g,repo:x})=>({name:m,base:h,baseRef:g,repo:x}))}:{}}}),i.tracks.push(p),await Y(),_t(p)}async function $m({provider:e="claude",fresh:t=!1}={}){if(!FD.has(e))throw new Error(`unknown setup provider "${e}" (claude | codex | cursor)`);let r=(await z()).tracks.find(u=>u.kind==="setup"&&u.setup?.provider===e&&!u.archivedAt);if(r){if(!t){let u=await _t(r);if(u.boxes.find(d=>d.name===u.leadBox)?.state==="live")return u}await io(r.id).catch(()=>{})}let o=(await pi(e,!1)).replace(/\s+--(?:dangerously-skip-permissions|dangerously-bypass-approvals-and-sandbox)\b/g,""),s=vs().slice(0,8),a=G.join(sn,"setup",s);await W.mkdir(a,{recursive:!0});let i=await Jn(`Connect ${e} ${s}`,a,{agentCmd:o,agent:e,firstRun:!0});e==="codex"&&wa({cwd:i.cwd,sessionName:i.name,agent:e,agentCmd:o});let c={id:s,name:`Connect ${e}`,kind:"setup",setup:{provider:e,startedAt:Date.now(),connectedAt:null},cwd:i.cwd,workspace:{dir:a,base:null,branch:null,kind:"scratch"},leadBox:i.name,boxes:[jm(i,"lead","live")],events:[],createdAt:Date.now()};return he(c,"opened",{agent:e,box:i.name,skipPermissions:!1,trackKind:"setup",name:c.name,cwd:c.cwd,workspace:{base:null,branch:null,kind:"scratch"}}),(await z()).tracks.push(c),await Y(),_t(c)}async function Om(e,t,n){await Xu(t.cwd).catch(()=>{}),await E0(e).catch(()=>{});let r=xs.get(e);r&&!r.finishedAt&&(r.error=n,r.finishedAt=Date.now()),xs.delete(e),t.handoff&&!t.handoff.finishedAt&&(t.handoff.step="error",t.handoff.error=n,t.handoff.finishedAt=Date.now());for(let a of co(e))a.finishedAt||(a.canceled=!0,a.finishedAt=Date.now()),await Jm(a).catch(()=>{}),wt.delete(a.id);for(let a of Object.values(t.subtasks||{}))a.finishedAt||(a.step="error",a.error=n,a.canceled=!0,a.finishedAt=Date.now());let o=await z(),s=new Set((o.tracks||[]).filter(a=>a.id!==e&&!a.archivedAt).flatMap(a=>(a.boxes||[]).map(i=>i.name)));for(let a of t.boxes)s.has(a.name)||await Ct(a.name).catch(()=>{})}async function Cm(e,{cascadeMocks:t=!0,cascadeRunbooks:n=!1}={}){let r=await z(),o=r.tracks.findIndex(a=>a.id===e);if(o===-1)throw new Error(`track "${e}" not found`);let s=r.tracks[o];return t||await V0(s),Tm(e),await Om(e,s,"track deleted"),n?await TS(e).catch(()=>{}):await vS(e).catch(()=>{}),await _k(),await sv(s),t&&await z0(e).catch(()=>{}),t?await dS(e).catch(()=>{}):await uS(s).catch(()=>{}),he(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:e,name:s.name,boxes:s.boxes.length}}async function io(e){let t=await z(),n=re(t,e);if(!n)throw new Error(`track "${e}" not found`);if(n.archivedAt)throw new Error(`track "${e}" is already archived`);return n.archivedAt=Date.now(),Tm(e),he(n,"archived",{boxes:n.boxes.length}),await Y(),n.kind==="setup"?(await av(e),_t(n)):(li.add(e),WD(e).catch(()=>{}).finally(()=>li.delete(e)),{...await _t(n),archiving:!0})}async function WD(e){try{await qD(e)}catch{}await av(e).catch(()=>{})}async function av(e){let t=await z(),n=re(t,e);if(!(!n||!n.archivedAt)){await Om(e,n,"track archived");for(let r of n.boxes)Nn.has(r.state)||(r.state="stopped");await Y()}}async function qD(e){let t=await z(),n=re(t,e);if(!n||!n.archivedAt)return;let r=null,o=[],s="derived",a=(n.events||[]).some(l=>l.type==="said"),i=n.leadBox?await se(n.leadBox).catch(()=>null):null;if(i?.cwd&&a)try{({text:r,items:o}=await Zy(n.leadBox,i.cwd,{timeoutMs:HD})),s="lead-cli"}catch{}if(r||(r=fb(n,await L(n).catch(()=>[]))),!r)return;let c={text:r,source:s,at:Date.now()};o.length&&(c.items=o),n.beat=c,await _(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 xn(e,t){let n=await qe(e,t).catch(()=>null);if(!n?.archiveOnMerge||!n.trackId)return!1;let r=await iv(n);if(r.length){for(let o of r)await Jr(o.repo,o.number,!0).catch(()=>{});return!1}try{return await io(n.trackId),!0}catch(o){if(/already archived/i.test(String(o?.message||o)))return!1;throw o}}async function iv(e){return(await Xr().catch(()=>[])).filter(n=>n.trackId===e.trackId&&n.state!=="merged"&&n.state!=="closed"&&n.state!=="lost"&&!(n.repo===e.repo&&n.number===e.number))}async function Sn(e,t){return Ul(e,t,"merged")}async function Ul(e,t,n="merged"){let r=await qe(e,t).catch(()=>null);if(!r?.notifyOnMerge||r.archiveOnMerge||!r.trackId)return!1;let o={repo:r.repo??null,number:r.number,title:r.title??null,url:r.url??null,headRef:r.headRef??null,outcome:n},s=await iv(r);if(s.length){let i=[...r.notifyPending||[],o];for(let c of s)await Qk(c.repo,c.number,i).catch(()=>{});return!1}let a=[...r.notifyPending||[],o];try{return await It(r.trackId,cv(a),{kind:"merge-notify"}),!0}catch{return!1}}function cv(e){let t=i=>`${i.repo?`${i.repo}`:""}#${i.number}${i.title?` "${i.title}"`:""}${i.url?` (${i.url})`:""}`;if(e.length===1){let i=e[0],c=`#${i.number}${i.title?` "${i.title}"`:""}`;return i.outcome!=="merged"?`PR ${c}${i.url?` (${i.url})`:""}${i.headRef?` \u2014 branch ${i.headRef} \u2014`:""} was ${LS[i.outcome]??i.outcome}. This is an automated notification: the work did NOT land \u2014 check whether it still needs to ship another way. If not, say so briefly.`:`PR ${c}${i.url?` (${i.url})`:""}${i.headRef?` \u2014 branch ${i.headRef} \u2014`:""} has merged. This is an automated merge notification: pick up whatever follow-up work this merge unblocks (dependent tasks, cleanup, next steps that were waiting on it). If nothing needs doing, say so briefly.`}let n=e.filter(i=>i.outcome==="merged"),r=e.filter(i=>i.outcome!=="merged"),o=r.length?`${n.length} of the ${e.length} PRs on this Track merged; ${r.length} did not land:`:`All ${e.length} PRs on this Track have merged:`,s=e.map(i=>`- ${t(i)} \u2014 ${LS[i.outcome]??i.outcome}`).join(`
191
194
  `),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}
192
195
  ${s}
193
- ${a}`}async function Im(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<oa()?!1:dn(e.name)}async function si(e,t,n){return!t||e.archivedAt||Mn.has(t.state)?!1:(await Y({flow:"rehydrate",phase:"resume-dead-cli",trackId:e.id,sessionName:t.name,agent:t.agent,via:n}).catch(()=>{}),console.warn(`[track] ${t.name}: CLI is not running (bare shell) \u2014 relaunching (${n})`),await Ct(t.name).catch(()=>{}),t.state="stopped",pi(e))}async function pi(e){let t=e.boxes.find(o=>o.name===e.leadBox);if(!t)return!1;let n=tm.get(t.name);if(n)return n;let r=$D(e,t).finally(()=>tm.delete(t.name));return tm.set(t.name,r),r}async function $D(e,t){if(e.archivedAt||e.transferredTo||Mn.has(t.state)||await se(t.name))return!1;let n=um(t.agent,t.sessionId,{cwd:t.cwd,peerName:t.name}),r=await dc(n);if(r===_o)return he(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:`agent "${t.agent}" is not installed on this box`}),!1;r===Io&&console.warn(`[track] ${t.name}: could not confirm "${t.agent}" on PATH \u2014 relaunching anyway (launch verifier will catch a real miss)`);try{let o=await zn(t.name,t.cwd,{agentCmd:n,agent:t.agent,resumeSessionId:t.sessionId,pinned:t.pinned===!0});return t.hookTokenHash=js(o.hookToken),ma({cwd:t.cwd,sessionName:t.name,agent:t.agent,agentCmd:n}),t.state="live",he(e,"rehydrated",{box:t.name,agent:t.agent}),!0}catch(o){return he(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:String(o?.message||o)}),!1}}async function Rm(e){let t=await z(),n=re(t,e);if(!n)throw new Error(`track "${e}" not found`);if(!n.archivedAt)throw new Error(`track "${e}" is not archived`);return delete n.archivedAt,oi.delete(e),he(n,"unarchived",{}),await pi(n),await X(),_t(n)}async function $m(e,t){let n=typeof t=="string"?t.trim():"";if(!n)throw new Error("name (non-empty string) required");if(n.length>im)throw new Error(`name too long (max ${im} chars)`);let r=await z(),o=re(r,e);if(!o)throw new Error(`track "${e}" not found`);if(String(o.name||"").startsWith("\u21BB"))throw new Error("loop run Tracks are named by their loop \u2014 rename the loop on the Loops tab");if(n===o.name)return _t(o);let s=o.name;return o.name=n,he(o,"renamed",{from:s,to:n}),await X(),_t(o)}async function Om(){let e=await z(),t=new Set((await Ot()).map(s=>s.name)),n=new Set((e.tracks||[]).filter(s=>!s.archivedAt).flatMap(s=>(s.boxes||[]).map(a=>a.name))),r=0,o=!1;for(let s of e.tracks||[])if(s.archivedAt)for(let a of s.boxes)t.has(a.name)&&!n.has(a.name)&&(await Ct(a.name).catch(()=>{}),he(s,"orphan-reaped",{box:a.name,agent:a.agent}),r++,o=!0),!Mn.has(a.state)&&a.state!=="stopped"&&(a.state="stopped",o=!0);return o&&await X(),r}async function jl(e){let t=await z(),n=re(t,e);if(!n)throw new Error(`track "${e}" not found`);if(n.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it before restarting the lead`);Bm(n);let r=n.boxes.find(a=>a.name===n.leadBox);if(!r)throw new Error(`track "${e}" has no lead box`);if(Mn.has(r.state))throw new Error("lead box is terminal \u2014 nothing to restart");if(await se(n.leadBox)){let a=await Ae(n.leadBox,{lines:Le}).catch(()=>"");if(Sc(r.agent,a))throw new Error("lead is mid-turn \u2014 retry when it goes idle");await Ct(n.leadBox),r.state="stopped"}let s=await pi(n);if(await X(),!s)throw new Error("rehydrate failed \u2014 see the track's rehydrate-failed event");return _t(n)}async function Cm(e,t,n){let r=await ne(e);if(!r)throw new Error(`track "${e}" not found`);if(!t)throw new Error("unknown offer");let o=await L(r).catch(()=>[]);if(!o.some(i=>i.type==="box.fullscreen.detected"&&i.payload?.offerId===t))throw new Error("unknown offer");if(o.some(i=>i.type==="box.fullscreen.answered"&&i.payload?.offerId===t))throw new Error("offer already answered");return n&&await jl(e),await _(r,{type:"box.fullscreen.answered",actor:"user",source:"orchestrator",boxId:r.leadBox,payload:{ts:Date.now(),offerId:t,action:n?"restarted":"dismiss"}}).catch(()=>{}),{ok:!0,action:n?"restarted":"dismiss"}}function Ll(e){return(!Array.isArray(e.epochs)||e.epochs.length===0)&&(e.epochs=[{agent:e.agent??null,sessionId:e.sessionId??null,pinned:e.pinned===!0,startedAt:e.createdAt??null,endedAt:null}]),e.epochs}async function Rl(e,t){let n=await z(),r=re(n,e);r&&(r.handoff={...r.handoff||{},...t},await X())}function nv(e,t=Date.now()){let n=e?.handoff;if(!n||n.finishedAt)return null;let r=n.step,o=!!n.toBox&&n.toBox===n.fromBox,s=e.boxes?.find?.(i=>i.name===e.leadBox)||null;return(o?e.leadBox===n.fromBox&&!!n.startedAt&&Array.isArray(s?.epochs)&&s.epochs.some(i=>i.startedAt!=null&&i.startedAt>=n.startedAt):!!n.toBox&&e.leadBox===n.toBox)?{...n,step:"done",finishedAt:t,recovered:`committed before restart (was "${r}")`}:{...n,step:"error",finishedAt:t,error:`interrupted by an agent restart during "${r}"; lead "${e.leadBox}" retained \u2014 retry the handoff`,recovered:"rolled-back"}}async function Nm(){let e=await z(),t=!1;for(let n of e.tracks||[]){let r=n.handoff,o=nv(n);if(!o)continue;t=!0;let s=!!r.toBox&&r.toBox===r.fromBox;if(s&&o.step==="error"){let c=await se(r.fromBox).catch(()=>null),l=n.boxes.find(u=>u.name===r.fromBox);if(c&&l&&c.agent===r.toAgent&&r.toAgent!==l.agent){let u=Date.now(),f=Ll(l),d=f[f.length-1],p=d.agent,m=d.sessionId??null;d.endedAt=u,r.reason&&(d.endReason=r.reason);let h=c.agent==="claude"&&!!c.sessionId;f.push({agent:r.toAgent,sessionId:c.sessionId||null,pinned:h,startedAt:u,endedAt:null}),l.agent=r.toAgent,l.sessionId=c.sessionId||null,l.pinned=h,l.state="live",n.pendingHandoffHydrate={artifact:so,at:u},he(n,"lead-handoff",{from:r.fromBox,to:r.fromBox,fromAgent:p,toAgent:r.toAgent,fromSessionId:m,toSessionId:c.sessionId||null,epoch:f.length-1,singleBox:!0,skipPermissions:r.skipPermissions,reason:r.reason??null,handoffStartedAt:r.startedAt,recovered:!0}),n.handoff={...r,step:"done",finishedAt:u,recovered:"swap adopted from live tmux tags after restart"},await Y({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 Y({flow:"lead-handoff",phase:"reconciled",trackId:n.id,outcome:o.step,recovered:o.recovered,fromBox:o.fromBox,toBox:o.toBox}).catch(()=>{}),i&&await Ct(i).catch(()=>{}),a&&await Ct(a).catch(()=>{})}return t&&await X(),t}async function Fl(e,t,n=!0,r=null){let o=ys.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is already running for this Track");let s=re(await z(),e);if(!s)throw new Error(`track "${e}" not found`);di(e,"handoff");let a=await li(t,n),i=Jr(t);if(i){let u=new Error(`can't hand off to ${t} \u2014 its ${i.window} spend limit is reached ($${i.spentUsd.toFixed(2)} of $${i.limitUsd.toFixed(2)})`);throw u.usageCap=i,u}let c=await se(s.leadBox);if(!c)throw new Error(`lead box "${s.leadBox}" is not running`);let l={trackId:e,step:"checkpoint",fromBox:s.leadBox,toAgent:t,skipPermissions:n,reason:FS(r),toBox:s.leadBox,startedAt:Date.now(),finishedAt:null,error:null};return ys.set(e,l),await Rl(e,{step:l.step,fromBox:l.fromBox,toAgent:t,toBox:l.toBox,skipPermissions:n,startedAt:l.startedAt,finishedAt:null,error:null}),OD(l,s,c,a,t).catch(async u=>{l.error=u?.message||String(u),l.finishedAt=Date.now(),console.error(`[lead-handoff ${e}] FAILED at step "${l.step}": ${l.error}`),await Rl(e,{step:l.step,error:l.error,finishedAt:l.finishedAt}).catch(()=>{}),Y({flow:"lead-handoff",phase:"failed",trackId:e,step:l.step,error:l.error,fromBox:l.fromBox,toAgent:l.toAgent,toBox:l.toBox}).catch(()=>{})}),Y({flow:"lead-handoff",phase:"started",trackId:e,fromBox:l.fromBox,toAgent:t,cwd:c.cwd}).catch(()=>{}),l}async function OD(e,t,n,r,o){let s=async(M,N={})=>{e.step=M,console.log(`[lead-handoff ${e.trackId}] step \u2192 ${M}`),await Rl(e.trackId,{step:M,toBox:e.toBox}),await Y({flow:"lead-handoff",phase:M,trackId:e.trackId,fromBox:e.fromBox,toBox:e.toBox,toAgent:o,sessionName:N.sessionName,...N})};console.log(`[lead-handoff ${e.trackId}] ${e.fromBox}: ${n.agent} \u2192 ${o} IN PLACE`);let a=await z(),i=re(a,e.trackId)?.boxes.find(M=>M.name===e.fromBox)||null,c=i?.agent||n.agent,l=i?.sessionId??n.sessionId??null,u=i?.pinned===!0;if(await s("checkpoint",{sessionName:e.fromBox}),e.checkpoint="llm",Jr(c))e.checkpoint="skipped-capped";else try{await Gd(e.fromBox,{timeoutMs:jS})}catch(M){e.checkpoint="reconstructed",await Y({flow:"lead-handoff",phase:"checkpoint-fallback",trackId:e.trackId,fromBox:e.fromBox,error:M?.message||String(M)}).catch(()=>{})}e.checkpoint!=="llm"&&(e.statusArtifact=await Vd(e.trackId,n.cwd,{trackName:t.name||t.id}).catch(()=>null),await s("checkpoint-degraded",{sessionName:e.fromBox,checkpoint:e.checkpoint,statusArtifact:e.statusArtifact})),await s("swap",{cwd:n.cwd,agentCmd:r});let d=await Qd(e.fromBox,{agentCmd:r,agent:o});await s("hydrate",{sessionName:e.fromBox});let p=Jg(d.launchCmd);await Xn({cwd:n.cwd,sessionId:d.sessionId,sessionName:e.fromBox,agent:o,agentCmd:ci(o),launchEcho:p}).catch(M=>{if(M?.code!=="cli-not-running")throw M});let m=Id(await Ae(e.fromBox,{lines:Le}).catch(()=>""),p);if(!vc(o,m)){await s("rollback",{sessionName:e.fromBox,fromAgent:c});let M=um(c,l,{skipPermissions:e.skipPermissions,cwd:n.cwd,peerName:e.fromBox});await Qd(e.fromBox,{agentCmd:M,agent:c,resumeSessionId:l,pinned:u});let N=await z(),C=re(N,e.trackId);if(C){let T=C.boxes.find(j=>j.name===e.fromBox);T&&(T.state="live"),he(C,"lead-handoff-failed",{box:e.fromBox,fromAgent:c,toAgent:o,reason:e.reason,error:`incoming ${o} CLI never drew its composer`,rolledBack:!0,handoffStartedAt:e.startedAt}),await X()}throw new Error(`incoming ${o} CLI never drew its composer \u2014 rolled back to ${c} (--resume, context intact)`)}await s("commit");let h=await z(),g=re(h,e.trackId);if(!g)throw new Error(`track "${e.trackId}" not found during handoff commit \u2014 was it deleted or archived mid-flight?`);let x=g.boxes.find(M=>M.name===e.fromBox);if(!x)throw new Error(`lead box row "${e.fromBox}" missing during handoff commit`);let k=Date.now(),E=Ll(x),I=E[E.length-1];I.endedAt=k,e.reason&&(I.endReason=e.reason),E.push({agent:o,sessionId:d.sessionId,pinned:d.pinned,startedAt:k,endedAt:null}),x.agent=o,x.sessionId=d.sessionId,x.pinned=d.pinned,x.state="live",x.role="lead",g.pendingHandoffHydrate={artifact:e.statusArtifact||so,at:k},he(g,"lead-handoff",{from:e.fromBox,to:e.fromBox,fromAgent:c,toAgent:o,fromSessionId:l,toSessionId:d.sessionId,epoch:E.length-1,singleBox:!0,forced:d.forced||void 0,skipPermissions:e.skipPermissions,reason:e.reason,handoffStartedAt:e.startedAt,checkpoint:e.checkpoint}),await X(),await s("done",{sessionName:e.fromBox}),await Rl(e.trackId,{finishedAt:Date.now(),error:null}),e.finishedAt=Date.now()}async function Dm(e){let t=lm.get(e);if(t&&!t.finishedAt)throw new Error("a transfer is already running for this Track");let n=await z(),r=re(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error("track is archived \u2014 restore it before moving it");if(r.kind==="setup")throw new Error("setup boxes don't move");if(r.transferredTo)throw new Error(`track already transferred to ${r.transferredTo}`);let o=ys.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is running \u2014 retry when it settles");for(let a of wt.values())if(a.trackId===e&&!a.finishedAt)throw new Error("a subtask is still running on this Track \u2014 wait for it to merge back before moving");let s={trackId:e,step:"checkpoint",startedAt:Date.now(),finishedAt:null,error:null};return lm.set(e,s),CD(s,r).catch(a=>{s.error=a?.message||String(a),s.finishedAt=Date.now(),console.error(`[transfer-out ${e}] FAILED at step "${s.step}": ${s.error}`)}),s}async function CD(e,t){let n=t.boxes.find(u=>u.name===t.leadBox)||null,r=n?await se(n.name).catch(()=>null):null;if(e.checkpoint="llm",!r||n&&Jr(n.agent))e.checkpoint=r?"skipped-capped":"skipped-dead";else try{await Gd(t.leadBox,{timeoutMs:jS})}catch{e.checkpoint="reconstructed"}e.checkpoint!=="llm"&&await Vd(t.id,t.cwd,{trackName:t.name||t.id}).catch(()=>null),e.step="push";let o=t.workspace?.branch??null,s=[];if(o)for(let u of gt(t.workspace)){if(!u?.dir)continue;let f={name:u.name??null,repo:u.repo??null,baseSha:null,pushed:!1};try{await Cn(u.dir,["push","origin",o],cm);let{stdout:d}=await Cn(u.dir,["rev-parse","HEAD"]);f.baseSha=d.trim(),f.pushed=!0}catch(d){f.error=String(d?.message||d).split(`
194
- `)[0]}s.push(f)}e.step="wip";let a=await qp({id:t.id,cwd:t.cwd}),i=await z(),c=re(i,t.id),l=c?.boxes.find(u=>u.name===c.leadBox)||null;l&&Ll(l),await X(),e.result={name:c?.name??t.name,agent:l?.agent??null,leadBox:c?.leadBox??t.leadBox,createdAt:c?.createdAt??null,branch:o,repos:s.filter(u=>u.pushed).map(({name:u,repo:f,baseSha:d})=>({name:u,repo:f,baseSha:d})),unpushed:s.filter(u=>!u.pushed).map(({name:u,repo:f,error:d})=>({name:u,repo:f,error:d})),wip:a.pushed?{ref:a.ref,sha:a.sha}:null,checkpoint:e.checkpoint,epochs:l?.epochs??[],codeless:!o||!s.some(u=>u.pushed)},e.step="ready",e.finishedAt=Date.now()}function Bm(e){if(!e?.transferredTo)return;let t=new Error(`track "${e.id}" moved to node ${e.transferredTo} \u2014 drive it there`);throw t.transferredTo=e.transferredTo,t}async function Ul(e,{toNode:t,mode:n="transfer"}={}){if(!t||typeof t!="string")throw new Error("toNode required");let r=await z(),o=re(r,e);if(!o)throw new Error(`track "${e}" not found`);if(o.transferredTo)return{ok:!0,alreadyTransferred:o.transferredTo};bm(e),await Am(e,o,n==="recover"?"track recovered onto another node":"track transferred to another node");let s=Date.now();for(let i of o.boxes){Mn.has(i.state)||(i.state="stopped");let c=Array.isArray(i.epochs)?i.epochs[i.epochs.length-1]:null;c&&typeof c=="object"&&c.endedAt==null&&(c.endedAt=s,c.endReason==null&&(c.endReason=n==="recover"?"node-offline":"node-transfer"))}let a=await Kp({id:o.id,cwd:o.cwd});return o.transferredTo=t,o.transferredAt=s,he(o,"transferred-out",{toNode:t,mode:n,box:o.leadBox,...a.pushed?{rescueRef:a.ref,rescueSha:a.sha}:{}}),await X(),{ok:!0,toNode:t,rescue:a.pushed?{ref:a.ref,sha:a.sha}:null}}async function jm(e){let t=[];for(let n of Array.isArray(e)?e:[])if(!(!n?.id||!n?.toNode))try{let r=await Ul(n.id,{toNode:n.toNode,mode:n.mode==="recover"?"recover":"transfer"});t.push({id:n.id,...r})}catch(r){/not found/i.test(String(r?.message))||console.error(`[transfer] demote of ${n.id} failed: ${r?.message||r}`)}return t}async function MS(e,t,n){try{await jc(e,t,n)}catch{await Cn(e,["worktree","prune"]).catch(()=>{}),await jc(e,t,n)}return t}async function Lm(e={}){let{trackId:t,name:n,agent:r="claude",skipPermissions:o=!0,mode:s="transfer"}=e;if(!t||typeof t!="string"||!/^[0-9a-f]{8}$/.test(t))throw new Error("trackId (8-hex string) required");if(typeof n!="string"||!n.trim())throw new Error("name (string) required");if(s!=="transfer"&&s!=="recover")throw new Error(`unknown adopt mode "${s}"`);if(nm.has(t))throw new Error("an adopt is already running for this Track");nm.set(t,{startedAt:Date.now()});try{return await MD({...e,trackId:t,name:n,agent:r,skipPermissions:o,mode:s})}finally{nm.delete(t)}}async function MD({trackId:e,name:t,agent:n,skipPermissions:r,mode:o,fromNode:s=null,toNode:a=null,branch:i=null,repos:c=[],wip:l=null,brief:u=null,epochs:f=[],createdAt:d=null,leadBox:p=null,reason:m=null}){let h=await li(n,r),g=await z(),x=re(g,e);if(x&&!x.transferredTo)throw new Error(`track "${e}" is already hosted on this node`);x&&(await Kp({id:x.id,cwd:x.cwd}).catch(()=>{}),await ZS(x),g.tracks.splice(g.tracks.indexOf(x),1),await X()),await W.mkdir(Za,{recursive:!0});let k=G.join(Za,e);await W.rm(k,{recursive:!0,force:!0}).catch(()=>{});let E=null,I=!1,M=[];try{let N=[];if(i)for(let q of Array.isArray(c)?c:[]){let J=typeof q=="string"?q:q?.repo;if(!J||!/^[^/\s]+\/[^/\s]+$/.test(J))continue;let ee=await bo(J)??await Vi(J);await Cn(ee,["fetch","origin",`+refs/heads/${i}:refs/heads/${i}`],cm),N.push({slug:J,base:ee,name:typeof q=="object"?q?.name??null:null})}if(i&&N.length===1){let{base:q,slug:J}=N[0];await MS(q,k,i),M.push({base:q,dir:k}),await ri(k);let ee=await Ko(q);E={dir:k,base:q,branch:i,kind:"worktree",baseRef:ee,repo:J}}else if(i&&N.length>=2){await W.mkdir(k,{recursive:!0});let q=new Set([".bostrat"]),J=[];for(let ee of N){let Xe=ee.name||G.basename(ee.base);q.has(Xe)&&(Xe=ee.slug.replace("/","-"));for(let v=2;q.has(Xe);v++)Xe=`${G.basename(ee.base)}-${v}`;q.add(Xe);let y=G.join(k,Xe);await MS(ee.base,y,i),M.push({base:ee.base,dir:y});let w=await Ko(ee.base);J.push({name:Xe,dir:y,base:ee.base,baseRef:w,repo:ee.slug})}await fi(k,J,i),E={dir:k,kind:"multi",branch:i,repos:J}}else I=!0,await W.mkdir(k,{recursive:!0}),await vf(k),await ri(k),E={dir:k,base:null,branch:null,kind:"repo"};let C=!1,T=null;if(l?.sha&&E.kind==="worktree")try{await Cn(k,["fetch","origin",l.ref||Wp(e)],cm);let{stdout:q}=await Cn(k,["rev-parse","FETCH_HEAD^"]),{stdout:J}=await Cn(k,["rev-parse","HEAD"]);q.trim()===J.trim()?(await Cn(k,["read-tree","--reset","-u","FETCH_HEAD"]),await Cn(k,["reset","-q"]),C=!0):T="snapshot does not parent the fetched branch head"}catch(q){T=String(q?.message||q).split(`
195
- `)[0]}else l?.sha&&(T="wip snapshots cover single-repo worktrees only");await IS({id:e,cwd:k}).catch(()=>({restored:!1}));let j=G.join(k,so),Z=null;(await sc(k)).restored?Z="checkpoint":typeof u=="string"&&u.trim()&&(await W.mkdir(G.dirname(j),{recursive:!0}),await W.writeFile(j,u),Z="brief");let ie=new Set(g.tracks.flatMap(q=>(q.boxes||[]).map(J=>J.name))),D=null;p&&!ie.has(p)&&!await se(p).catch(()=>null)?D=p:(D=`${t.trim()} lead`,ie.has(fc(D))&&(D=`${t.trim().slice(0,50).trim()} ${e} lead`));let R=await zn(D,k,{agentCmd:h,agent:n});ma({cwd:R.cwd,sessionName:R.name,agent:n,agentCmd:h});let U=Date.now(),pe=Mm(R,"lead","live"),Se=(Array.isArray(f)?f:[]).filter(q=>q&&typeof q=="object").map(q=>({...q})),He=Se[Se.length-1];He&&He.endedAt==null&&(He.endedAt=U,He.endReason==null&&(He.endReason=o==="recover"?"node-offline":"node-transfer")),Se.push({agent:n,sessionId:R.sessionId??null,pinned:R.pinned===!0,startedAt:U,endedAt:null}),pe.epochs=Se;let le={id:e,name:t.trim(),cwd:R.cwd,workspace:E,leadBox:R.name,boxes:[pe],events:[],createdAt:Number.isFinite(d)?d:U,...Z?{pendingHandoffHydrate:{artifact:so,at:U}}:{}};return he(le,"transferred-in",{box:R.name,agent:n,fromNode:s,toNode:a,mode:o,reason:m,branch:E.branch??null,wip:C,epoch:Se.length-1,name:le.name,cwd:le.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:q,base:J,baseRef:ee,repo:Xe})=>({name:q,base:J,baseRef:ee,repo:Xe}))}:{}}}),g.tracks.push(le),await X(),{...await _t(le),adopt:{wipApplied:C,wipSkipped:T,codeless:I,artifactSource:Z}}}catch(N){for(let C of M)await pt(C.base,C.dir).catch(()=>{});throw await W.rm(k,{recursive:!0,force:!0}).catch(()=>{}),N}}async function rv(e,t,n){let r=await z(),o=re(r,e);o&&(o.subtasks=o.subtasks||{},o.subtasks[t]={...o.subtasks[t]||{},...n},await X())}async function ms(e,t){e.step=t,await mi(e)}function ov(e,t=Date.now()){if(!e||e.finishedAt)return null;let n=e.step;return["snapshot","spawn","working"].includes(n)?{...e,step:"error",finishedAt:t,error:`interrupted by an agent restart during "${n}"; no changes were applied to the lead \u2014 retry the delegation`,recovered:"rolled-back"}:{...e,step:"error",finishedAt:t,error:`interrupted by an agent restart during "${n}"; the lead's working tree may hold a PARTIAL merge \u2014 review git status. The subtask's work is preserved on branch ${e.branch}`,recovered:"partial-merge"}}function sv(e){return!!e&&!e.finishedAt&&!e.canceled&&e.step==="working"&&!!e.box&&!!e.dir&&!!e.base&&!!e.branch}async function BD(e,t,n){if(!sv(n)||wt.has(t)||!await se(n.box).catch(()=>null))return!1;try{await W.access(n.dir)}catch{return!1}let o=await se(e.leadBox).catch(()=>null);if(!o?.cwd)return!1;let s={...n,id:t,leadBox:e.leadBox,step:"working",canceled:!1,forceMerge:!1};return wt.set(t,s),iv(s,o).catch(a=>av(s,a)),!0}async function Fm(){let e=await z(),t=!1;for(let n of e.tracks||[]){for(let[r,o]of Object.entries(n.subtasks||{})){if(wt.has(r))continue;if(await BD(n,r,o)){t=!0,he(n,"subtask-resumed",{box:o.box,agent:o.agent,task:o.task,subtaskId:r,resumedStep:o.step}),await Y({flow:"subtask",phase:"resumed",trackId:n.id,subtaskId:r,box:o.box,branch:o.branch}).catch(()=>{});continue}let s=o.step,a=ov(o);if(!a)continue;t=!0,n.subtasks[r]=a;let i=n.boxes.find(c=>c.subtaskId===r);i&&!Mn.has(i.state)&&(i.state="canceled"),he(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 Y({flow:"subtask",phase:"reconciled",trackId:n.id,subtaskId:r,outcome:a.step,recovered:a.recovered,box:o.box,branch:o.branch}).catch(()=>{}),await NS(n,o.box,o.dir)}for(let r of n.boxes){if(r.role!=="subtask"||Mn.has(r.state)||wt.has(r.subtaskId)||n.subtasks?.[r.subtaskId])continue;t=!0,r.state="canceled";let o=r.subtaskId?G.join(bs,`${n.id}-${r.subtaskId}`):null;await Y({flow:"subtask",phase:"reaped-legacy-orphan",trackId:n.id,subtaskId:r.subtaskId,box:r.name}).catch(()=>{}),await NS(n,r.name,o)}}return t=await jD(e)||t,t&&await X(),t}async function NS(e,t,n){if(t&&await Ct(t).catch(()=>{}),!n)return;if(e.workspace?.kind==="multi"){for(let o of gt(e.workspace)){let s=G.join(n,o.name);await pt(o.base,s).then(()=>!0,()=>!1)||await pt(o.dir,s).catch(()=>{})}await W.rm(n,{recursive:!0,force:!0}).catch(()=>{});return}let r=await se(e.leadBox).catch(()=>null);r?.cwd&&await pt(r.cwd,n).catch(()=>{})}async function jD(e){let t;try{t=await W.readdir(bs)}catch{return!1}let n=new Set;for(let o of e.tracks||[]){for(let s of Object.keys(o.subtasks||{}))n.add(`${o.id}-${s}`);for(let s of o.boxes||[])s.subtaskId&&n.add(`${o.id}-${s.subtaskId}`)}for(let o of wt.values())o.dir&&n.add(G.basename(o.dir));let r=!1;for(let o of t){if(n.has(o))continue;let s=G.join(bs,o),a=(e.tracks||[]).find(i=>o.startsWith(`${i.id}-`));if(a?.workspace?.kind==="multi"){for(let i of gt(a.workspace))await pt(i.base,G.join(s,i.name)).catch(()=>{});await W.rm(s,{recursive:!0,force:!0}).catch(()=>{})}else{let i=a?await se(a.leadBox).catch(()=>null):null;i?.cwd?await pt(i.cwd,s).catch(()=>{}):await W.rm(s,{recursive:!0,force:!0}).catch(()=>{})}await Y({flow:"subtask",phase:"swept-orphan-worktree",dir:s}).catch(()=>{}),r=!0}return r}async function Hm(e,{agent:t,task:n,skipPermissions:r=!0,reason:o=null}={}){if(typeof n!="string"||!Uo(n))throw new Error("task (string) required");let s=await li(t,r),a=Jr(t);if(a){let p=new Error(`can't delegate to ${t} \u2014 its ${a.window} spend limit is reached ($${a.spentUsd.toFixed(2)} of $${a.limitUsd.toFixed(2)})`);throw p.usageCap=a,p}let i=re(await z(),e);if(!i)throw new Error(`track "${e}" not found`);let c=await se(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=gt(i.workspace);if(!p.length)throw new Error("this multi-repo Track has no tagged repos to delegate into");for(let m of p)if(!m?.dir||!await Ho(m.dir))throw new Error(`tagged checkout "${m?.name??"?"}" is missing from the lead workspace (${m?.dir??"no dir"})`);u=p.map(m=>({name:m.name,leadDir:m.dir,base:null}))}else if(!await Ho(c.cwd))throw new Error(`subtask delegation needs the lead's workspace to be a git repo (got ${c.cwd})`);let f=ks().slice(0,8),d={id:f,trackId:e,trackName:i.name,agent:t,task:Uo(n),skipPermissions:r,reason:FS(o),step:"snapshot",leadBox:i.leadBox,box:null,branch:`bostrat/${Um(i.name)}-${f}`,base:null,repos:u,dir:G.join(bs,`${e}-${f}`),stat:null,conflicts:[],applied:null,startedAt:Date.now(),finishedAt:null,error:null,canceled:!1,forceMerge:!1};return wt.set(f,d),await mi(d),LD(d,c,s).catch(p=>av(d,p)),d}async function av(e,t){e.failedStep=e.step,e.error=t instanceof ai?"canceled":t?.message||String(t),e.step=t instanceof ai?"canceled":"error",e.finishedAt=Date.now(),await qm(e).catch(()=>{}),await mi(e).catch(()=>{}),await WD(e).catch(()=>{})}function Wl(e){let t=wt.get(e);if(!t)throw new Error(`subtask "${e}" not found`);if(t.finishedAt)throw new Error("subtask already finished");return t.canceled=!0,t}function Wm(e){let t=wt.get(e);if(!t)throw new Error(`subtask "${e}" not found`);if(t.finishedAt)throw new Error("subtask already finished");if(t.step!=="working")throw new Error(`subtask is not waiting to merge (step: ${t.step})`);return t.forceMerge=!0,t}async function LD(e,t,n){if(await ms(e,"snapshot"),e.repos){for(let s of e.repos)s.base=await Wo(s.leadDir,`bostrat: snapshot for subtask ${e.id}`);await mi(e)}else e.base=await Wo(t.cwd,`bostrat: snapshot for subtask ${e.id}`);if(await ms(e,"spawn"),await W.mkdir(bs,{recursive:!0}),e.repos){await W.mkdir(e.dir,{recursive:!0});for(let a of e.repos)await qo(a.leadDir,G.join(e.dir,a.name),e.branch,a.base);let s=gt((re(await z(),e.trackId)||{}).workspace);await fi(e.dir,e.repos.map(a=>{let i=s.find(c=>c?.name===a.name);return{name:a.name,repo:i?.repo??null,baseRef:null}}),e.branch)}else await qo(t.cwd,e.dir,e.branch,e.base),await ri(e.dir);await FD(e,t);let r=e.trackName.slice(0,38).trim(),o=await zn(`${r} ${e.agent} sub ${e.id}`,e.dir,{agentCmd:n,agent:e.agent});e.box=o.name,await UD(e,o),await US(e.trackId,o.name,LP(e.task,!!e.repos),{kind:"subtask"}),await iv(e,t)}async function iv(e,t){await ms(e,"working");let n=G.join(e.dir,Il);if(await KD(n,e),e.canceled)throw new ai;if(await ms(e,"merge"),e.repos){let s={files:0,insertions:0,deletions:0},a=[],i=[],c=!0;for(let l of e.repos){let u=G.join(e.dir,l.name);await Sf(u,`bostrat: subtask ${e.id} result (auto-committed)`),l.stat=await Ef(l.leadDir,l.base,e.branch,ps),l.files=await Af(l.leadDir,l.base,e.branch,ps);let f=await _f(l.leadDir,l.base,e.branch,ps);l.applied=f.applied,l.conflicts=f.conflicts??[],s.files+=l.stat.files,s.insertions+=l.stat.insertions,s.deletions+=l.stat.deletions,a.push(...l.files.map(d=>G.join(l.name,d))),i.push(...l.conflicts.map(d=>d.startsWith("patch did not apply cleanly")?`${l.name}: ${d}`:G.join(l.name,d))),f.applied||(c=!1)}e.stat=s,e.files=a,e.conflicts=i,e.applied=c}else{await Sf(e.dir,`bostrat: subtask ${e.id} result (auto-committed)`),e.stat=await Ef(t.cwd,e.base,e.branch,ps),e.files=await Af(t.cwd,e.base,e.branch,ps);let s=await _f(t.cwd,e.base,e.branch,ps);e.applied=s.applied,e.conflicts=s.conflicts}await mi(e);let r=await qD(e,t,n);await ms(e,"resume"),await US(e.trackId,e.leadBox,FP(e.task,e.stat,e.conflicts,r),{kind:"subtask-resume"}),await ms(e,"reap"),await qm(e),e.step="done";let o=Date.now();await rv(e.trackId,e.id,{...Hl(e),finishedAt:o}),await HD(e,o),e.finishedAt=o}async function FD(e,t){let n=G.join(e.dir,G.dirname(Qa));await W.mkdir(n,{recursive:!0});let r="";try{r=await Mg(t.cwd,t.sessionId)}catch{}if(!r)try{r=await W.readFile(G.join(t.cwd,".bostrat/handoff/latest.md"),"utf8")}catch{r="_(no prior conversation digest available \u2014 rely on the working tree.)_"}let o=`# Lead context for subtask ${e.id}
196
+ ${a}`}async function Mm(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<ca()?!1:fn(e.name)}async function ui(e,t,n){return!t||e.archivedAt||Nn.has(t.state)?!1:(await X({flow:"rehydrate",phase:"resume-dead-cli",trackId:e.id,sessionName:t.name,agent:t.agent,via:n}).catch(()=>{}),console.warn(`[track] ${t.name}: CLI is not running (bare shell) \u2014 relaunching (${n})`),await Ct(t.name).catch(()=>{}),t.state="stopped",gi(e))}async function gi(e){let t=e.boxes.find(o=>o.name===e.leadBox);if(!t)return!1;let n=am.get(t.name);if(n)return n;let r=KD(e,t).finally(()=>am.delete(t.name));return am.set(t.name,r),r}async function KD(e,t){if(e.archivedAt||e.transferredTo||Nn.has(t.state)||await se(t.name))return!1;let n=hm(t.agent,t.sessionId,{cwd:t.cwd,peerName:t.name}),r=await hc(n);if(r===_o)return he(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:`agent "${t.agent}" is not installed on this box`}),!1;r===Io&&console.warn(`[track] ${t.name}: could not confirm "${t.agent}" on PATH \u2014 relaunching anyway (launch verifier will catch a real miss)`);try{let o=await Jn(t.name,t.cwd,{agentCmd:n,agent:t.agent,resumeSessionId:t.sessionId,pinned:t.pinned===!0});return t.hookTokenHash=Hs(o.hookToken),wa({cwd:t.cwd,sessionName:t.name,agent:t.agent,agentCmd:n}),t.state="live",he(e,"rehydrated",{box:t.name,agent:t.agent}),!0}catch(o){return he(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:String(o?.message||o)}),!1}}async function Nm(e){let t=await z(),n=re(t,e);if(!n)throw new Error(`track "${e}" not found`);if(!n.archivedAt)throw new Error(`track "${e}" is not archived`);return delete n.archivedAt,li.delete(e),he(n,"unarchived",{}),await gi(n),await Y(),_t(n)}async function Pm(e,t){let n=typeof t=="string"?t.trim():"";if(!n)throw new Error("name (non-empty string) required");if(n.length>fm)throw new Error(`name too long (max ${fm} chars)`);let r=await z(),o=re(r,e);if(!o)throw new Error(`track "${e}" not found`);if(String(o.name||"").startsWith("\u21BB"))throw new Error("loop run Tracks are named by their loop \u2014 rename the loop on the Loops tab");if(n===o.name)return _t(o);let s=o.name;return o.name=n,he(o,"renamed",{from:s,to:n}),await Y(),_t(o)}async function Dm(){let e=await z(),t=new Set((await Ot()).map(s=>s.name)),n=new Set((e.tracks||[]).filter(s=>!s.archivedAt).flatMap(s=>(s.boxes||[]).map(a=>a.name))),r=0,o=!1;for(let s of e.tracks||[])if(s.archivedAt)for(let a of s.boxes)t.has(a.name)&&!n.has(a.name)&&(await Ct(a.name).catch(()=>{}),he(s,"orphan-reaped",{box:a.name,agent:a.agent}),r++,o=!0),!Nn.has(a.state)&&a.state!=="stopped"&&(a.state="stopped",o=!0);return o&&await Y(),r}async function Hl(e){let t=await z(),n=re(t,e);if(!n)throw new Error(`track "${e}" not found`);if(n.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it before restarting the lead`);Hm(n);let r=n.boxes.find(a=>a.name===n.leadBox);if(!r)throw new Error(`track "${e}" has no lead box`);if(Nn.has(r.state))throw new Error("lead box is terminal \u2014 nothing to restart");if(await se(n.leadBox)){let a=await Te(n.leadBox,{lines:je}).catch(()=>"");if(_c(r.agent,a))throw new Error("lead is mid-turn \u2014 retry when it goes idle");await Ct(n.leadBox),r.state="stopped"}let s=await gi(n);if(await Y(),!s)throw new Error("rehydrate failed \u2014 see the track's rehydrate-failed event");return _t(n)}async function Bm(e,t,n){let r=await ne(e);if(!r)throw new Error(`track "${e}" not found`);if(!t)throw new Error("unknown offer");let o=await L(r).catch(()=>[]);if(!o.some(i=>i.type==="box.fullscreen.detected"&&i.payload?.offerId===t))throw new Error("unknown offer");if(o.some(i=>i.type==="box.fullscreen.answered"&&i.payload?.offerId===t))throw new Error("offer already answered");return n&&await Hl(e),await _(r,{type:"box.fullscreen.answered",actor:"user",source:"orchestrator",boxId:r.leadBox,payload:{ts:Date.now(),offerId:t,action:n?"restarted":"dismiss"}}).catch(()=>{}),{ok:!0,action:n?"restarted":"dismiss"}}function Wl(e){return(!Array.isArray(e.epochs)||e.epochs.length===0)&&(e.epochs=[{agent:e.agent??null,sessionId:e.sessionId??null,pinned:e.pinned===!0,startedAt:e.createdAt??null,endedAt:null}]),e.epochs}async function Ml(e,t){let n=await z(),r=re(n,e);r&&(r.handoff={...r.handoff||{},...t},await Y())}function lv(e,t=Date.now()){let n=e?.handoff;if(!n||n.finishedAt)return null;let r=n.step,o=!!n.toBox&&n.toBox===n.fromBox,s=e.boxes?.find?.(i=>i.name===e.leadBox)||null;return(o?e.leadBox===n.fromBox&&!!n.startedAt&&Array.isArray(s?.epochs)&&s.epochs.some(i=>i.startedAt!=null&&i.startedAt>=n.startedAt):!!n.toBox&&e.leadBox===n.toBox)?{...n,step:"done",finishedAt:t,recovered:`committed before restart (was "${r}")`}:{...n,step:"error",finishedAt:t,error:`interrupted by an agent restart during "${r}"; lead "${e.leadBox}" retained \u2014 retry the handoff`,recovered:"rolled-back"}}async function Lm(){let e=await z(),t=!1;for(let n of e.tracks||[]){let r=n.handoff,o=lv(n);if(!o)continue;t=!0;let s=!!r.toBox&&r.toBox===r.fromBox;if(s&&o.step==="error"){let c=await se(r.fromBox).catch(()=>null),l=n.boxes.find(u=>u.name===r.fromBox);if(c&&l&&c.agent===r.toAgent&&r.toAgent!==l.agent){let u=Date.now(),f=Wl(l),d=f[f.length-1],p=d.agent,m=d.sessionId??null;d.endedAt=u,r.reason&&(d.endReason=r.reason);let h=c.agent==="claude"&&!!c.sessionId;f.push({agent:r.toAgent,sessionId:c.sessionId||null,pinned:h,startedAt:u,endedAt:null}),l.agent=r.toAgent,l.sessionId=c.sessionId||null,l.pinned=h,l.state="live",n.pendingHandoffHydrate={artifact:oo,at:u},he(n,"lead-handoff",{from:r.fromBox,to:r.fromBox,fromAgent:p,toAgent:r.toAgent,fromSessionId:m,toSessionId:c.sessionId||null,epoch:f.length-1,singleBox:!0,skipPermissions:r.skipPermissions,reason:r.reason??null,handoffStartedAt:r.startedAt,recovered:!0}),n.handoff={...r,step:"done",finishedAt:u,recovered:"swap adopted from live tmux tags after restart"},await X({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 X({flow:"lead-handoff",phase:"reconciled",trackId:n.id,outcome:o.step,recovered:o.recovered,fromBox:o.fromBox,toBox:o.toBox}).catch(()=>{}),i&&await Ct(i).catch(()=>{}),a&&await Ct(a).catch(()=>{})}return t&&await Y(),t}async function ql(e,t,n=!0,r=null){let o=xs.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is already running for this Track");let s=re(await z(),e);if(!s)throw new Error(`track "${e}" not found`);hi(e,"handoff");let a=await pi(t,n),i=zr(t);if(i){let u=new Error(`can't hand off to ${t} \u2014 its ${i.window} spend limit is reached ($${i.spentUsd.toFixed(2)} of $${i.limitUsd.toFixed(2)})`);throw u.usageCap=i,u}let c=await se(s.leadBox);if(!c)throw new Error(`lead box "${s.leadBox}" is not running`);let l={trackId:e,step:"checkpoint",fromBox:s.leadBox,toAgent:t,skipPermissions:n,reason:VS(r),toBox:s.leadBox,startedAt:Date.now(),finishedAt:null,error:null};return xs.set(e,l),await Ml(e,{step:l.step,fromBox:l.fromBox,toAgent:t,toBox:l.toBox,skipPermissions:n,startedAt:l.startedAt,finishedAt:null,error:null}),GD(l,s,c,a,t).catch(async u=>{l.error=u?.message||String(u),l.finishedAt=Date.now(),console.error(`[lead-handoff ${e}] FAILED at step "${l.step}": ${l.error}`),await Ml(e,{step:l.step,error:l.error,finishedAt:l.finishedAt}).catch(()=>{}),X({flow:"lead-handoff",phase:"failed",trackId:e,step:l.step,error:l.error,fromBox:l.fromBox,toAgent:l.toAgent,toBox:l.toBox}).catch(()=>{})}),X({flow:"lead-handoff",phase:"started",trackId:e,fromBox:l.fromBox,toAgent:t,cwd:c.cwd}).catch(()=>{}),l}async function GD(e,t,n,r,o){let s=async(M,N={})=>{e.step=M,console.log(`[lead-handoff ${e.trackId}] step \u2192 ${M}`),await Ml(e.trackId,{step:M,toBox:e.toBox}),await X({flow:"lead-handoff",phase:M,trackId:e.trackId,fromBox:e.fromBox,toBox:e.toBox,toAgent:o,sessionName:N.sessionName,...N})};console.log(`[lead-handoff ${e.trackId}] ${e.fromBox}: ${n.agent} \u2192 ${o} IN PLACE`);let a=await z(),i=re(a,e.trackId)?.boxes.find(M=>M.name===e.fromBox)||null,c=i?.agent||n.agent,l=i?.sessionId??n.sessionId??null,u=i?.pinned===!0;if(await s("checkpoint",{sessionName:e.fromBox}),e.checkpoint="llm",zr(c))e.checkpoint="skipped-capped";else try{await Zd(e.fromBox,{timeoutMs:KS})}catch(M){e.checkpoint="reconstructed",await X({flow:"lead-handoff",phase:"checkpoint-fallback",trackId:e.trackId,fromBox:e.fromBox,error:M?.message||String(M)}).catch(()=>{})}e.checkpoint!=="llm"&&(e.statusArtifact=await Qd(e.trackId,n.cwd,{trackName:t.name||t.id}).catch(()=>null),await s("checkpoint-degraded",{sessionName:e.fromBox,checkpoint:e.checkpoint,statusArtifact:e.statusArtifact})),await s("swap",{cwd:n.cwd,agentCmd:r});let d=await sf(e.fromBox,{agentCmd:r,agent:o});await s("hydrate",{sessionName:e.fromBox});let p=ny(d.launchCmd);await Yn({cwd:n.cwd,sessionId:d.sessionId,sessionName:e.fromBox,agent:o,agentCmd:Ts(o),launchEcho:p}).catch(M=>{if(M?.code!=="cli-not-running")throw M});let m=Cd(await Te(e.fromBox,{lines:je}).catch(()=>""),p);if(!jo(o,m)){await s("rollback",{sessionName:e.fromBox,fromAgent:c});let M=hm(c,l,{skipPermissions:e.skipPermissions,cwd:n.cwd,peerName:e.fromBox});await sf(e.fromBox,{agentCmd:M,agent:c,resumeSessionId:l,pinned:u});let N=await z(),O=re(N,e.trackId);if(O){let T=O.boxes.find(j=>j.name===e.fromBox);T&&(T.state="live"),he(O,"lead-handoff-failed",{box:e.fromBox,fromAgent:c,toAgent:o,reason:e.reason,error:`incoming ${o} CLI never drew its composer`,rolledBack:!0,handoffStartedAt:e.startedAt}),await 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 z(),g=re(h,e.trackId);if(!g)throw new Error(`track "${e.trackId}" not found during handoff commit \u2014 was it deleted or archived mid-flight?`);let x=g.boxes.find(M=>M.name===e.fromBox);if(!x)throw new Error(`lead box row "${e.fromBox}" missing during handoff commit`);let k=Date.now(),E=Wl(x),I=E[E.length-1];I.endedAt=k,e.reason&&(I.endReason=e.reason),E.push({agent:o,sessionId:d.sessionId,pinned:d.pinned,startedAt:k,endedAt:null}),x.agent=o,x.sessionId=d.sessionId,x.pinned=d.pinned,x.state="live",x.role="lead",g.pendingHandoffHydrate={artifact:e.statusArtifact||oo,at:k},he(g,"lead-handoff",{from:e.fromBox,to:e.fromBox,fromAgent:c,toAgent:o,fromSessionId:l,toSessionId:d.sessionId,epoch:E.length-1,singleBox:!0,forced:d.forced||void 0,skipPermissions:e.skipPermissions,reason:e.reason,handoffStartedAt:e.startedAt,checkpoint:e.checkpoint}),await Y(),await s("done",{sessionName:e.fromBox}),await Ml(e.trackId,{finishedAt:Date.now(),error:null}),e.finishedAt=Date.now()}async function Um(e){let t=mm.get(e);if(t&&!t.finishedAt)throw new Error("a transfer is already running for this Track");let n=await z(),r=re(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error("track is archived \u2014 restore it before moving it");if(r.kind==="setup")throw new Error("setup boxes don't move");if(r.transferredTo)throw new Error(`track already transferred to ${r.transferredTo}`);let o=xs.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is running \u2014 retry when it settles");for(let a of wt.values())if(a.trackId===e&&!a.finishedAt)throw new Error("a subtask is still running on this Track \u2014 wait for it to merge back before moving");let s={trackId:e,step:"checkpoint",startedAt:Date.now(),finishedAt:null,error:null};return mm.set(e,s),VD(s,r).catch(a=>{s.error=a?.message||String(a),s.finishedAt=Date.now(),console.error(`[transfer-out ${e}] FAILED at step "${s.step}": ${s.error}`)}),s}async function VD(e,t){let n=t.boxes.find(u=>u.name===t.leadBox)||null,r=n?await se(n.name).catch(()=>null):null;if(e.checkpoint="llm",!r||n&&zr(n.agent))e.checkpoint=r?"skipped-capped":"skipped-dead";else try{await Zd(t.leadBox,{timeoutMs:KS})}catch{e.checkpoint="reconstructed"}e.checkpoint!=="llm"&&await Qd(t.id,t.cwd,{trackName:t.name||t.id}).catch(()=>null),e.step="push";let o=t.workspace?.branch??null,s=[];if(o)for(let u of gt(t.workspace)){if(!u?.dir)continue;let f={name:u.name??null,repo:u.repo??null,baseSha:null,pushed:!1};try{await Mn(u.dir,["push","origin",o],pm);let{stdout:d}=await Mn(u.dir,["rev-parse","HEAD"]);f.baseSha=d.trim(),f.pushed=!0}catch(d){f.error=String(d?.message||d).split(`
197
+ `)[0]}s.push(f)}e.step="wip";let a=await Xp({id:t.id,cwd:t.cwd}),i=await z(),c=re(i,t.id),l=c?.boxes.find(u=>u.name===c.leadBox)||null;l&&Wl(l),await Y(),e.result={name:c?.name??t.name,agent:l?.agent??null,leadBox:c?.leadBox??t.leadBox,createdAt:c?.createdAt??null,branch:o,repos:s.filter(u=>u.pushed).map(({name:u,repo:f,baseSha:d})=>({name:u,repo:f,baseSha:d})),unpushed:s.filter(u=>!u.pushed).map(({name:u,repo:f,error:d})=>({name:u,repo:f,error:d})),wip:a.pushed?{ref:a.ref,sha:a.sha}:null,checkpoint:e.checkpoint,epochs:l?.epochs??[],codeless:!o||!s.some(u=>u.pushed)},e.step="ready",e.finishedAt=Date.now()}function Hm(e){if(!e?.transferredTo)return;let t=new Error(`track "${e.id}" moved to node ${e.transferredTo} \u2014 drive it there`);throw t.transferredTo=e.transferredTo,t}async function Kl(e,{toNode:t,mode:n="transfer"}={}){if(!t||typeof t!="string")throw new Error("toNode required");let r=await z(),o=re(r,e);if(!o)throw new Error(`track "${e}" not found`);if(o.transferredTo)return{ok:!0,alreadyTransferred:o.transferredTo};Tm(e),await Om(e,o,n==="recover"?"track recovered onto another node":"track transferred to another node");let s=Date.now();for(let i of o.boxes){Nn.has(i.state)||(i.state="stopped");let c=Array.isArray(i.epochs)?i.epochs[i.epochs.length-1]:null;c&&typeof c=="object"&&c.endedAt==null&&(c.endedAt=s,c.endReason==null&&(c.endReason=n==="recover"?"node-offline":"node-transfer"))}let a=await Yp({id:o.id,cwd:o.cwd});return o.transferredTo=t,o.transferredAt=s,he(o,"transferred-out",{toNode:t,mode:n,box:o.leadBox,...a.pushed?{rescueRef:a.ref,rescueSha:a.sha}:{}}),await Y(),{ok:!0,toNode:t,rescue:a.pushed?{ref:a.ref,sha:a.sha}:null}}async function Wm(e){let t=[];for(let n of Array.isArray(e)?e:[])if(!(!n?.id||!n?.toNode))try{let r=await Kl(n.id,{toNode:n.toNode,mode:n.mode==="recover"?"recover":"transfer"});t.push({id:n.id,...r})}catch(r){/not found/i.test(String(r?.message))||console.error(`[transfer] demote of ${n.id} failed: ${r?.message||r}`)}return t}async function FS(e,t,n){try{await Hc(e,t,n)}catch{await Mn(e,["worktree","prune"]).catch(()=>{}),await Hc(e,t,n)}return t}async function qm(e={}){let{trackId:t,name:n,agent:r="claude",skipPermissions:o=!0,mode:s="transfer"}=e;if(!t||typeof t!="string"||!/^[0-9a-f]{8}$/.test(t))throw new Error("trackId (8-hex string) required");if(typeof n!="string"||!n.trim())throw new Error("name (string) required");if(s!=="transfer"&&s!=="recover")throw new Error(`unknown adopt mode "${s}"`);if(im.has(t))throw new Error("an adopt is already running for this Track");im.set(t,{startedAt:Date.now()});try{return await zD({...e,trackId:t,name:n,agent:r,skipPermissions:o,mode:s})}finally{im.delete(t)}}async function zD({trackId:e,name:t,agent:n,skipPermissions:r,mode:o,fromNode:s=null,toNode:a=null,branch:i=null,repos:c=[],wip:l=null,brief:u=null,epochs:f=[],createdAt:d=null,leadBox:p=null,reason:m=null}){let h=await pi(n,r),g=await z(),x=re(g,e);if(x&&!x.transferredTo)throw new Error(`track "${e}" is already hosted on this node`);x&&(await Yp({id:x.id,cwd:x.cwd}).catch(()=>{}),await sv(x),g.tracks.splice(g.tracks.indexOf(x),1),await Y()),await W.mkdir(ri,{recursive:!0});let k=G.join(ri,e);await W.rm(k,{recursive:!0,force:!0}).catch(()=>{});let E=null,I=!1,M=[];try{let N=[];if(i)for(let q of Array.isArray(c)?c:[]){let J=typeof q=="string"?q:q?.repo;if(!J||!/^[^/\s]+\/[^/\s]+$/.test(J))continue;let ee=await bo(J)??await Yi(J);await Mn(ee,["fetch","origin",`+refs/heads/${i}:refs/heads/${i}`],pm),N.push({slug:J,base:ee,name:typeof q=="object"?q?.name??null:null})}if(i&&N.length===1){let{base:q,slug:J}=N[0];await FS(q,k,i),M.push({base:q,dir:k}),await ci(k);let ee=await zo(q);E={dir:k,base:q,branch:i,kind:"worktree",baseRef:ee,repo:J}}else if(i&&N.length>=2){await W.mkdir(k,{recursive:!0});let q=new Set([".bostrat"]),J=[];for(let ee of N){let Ze=ee.name||G.basename(ee.base);q.has(Ze)&&(Ze=ee.slug.replace("/","-"));for(let v=2;q.has(Ze);v++)Ze=`${G.basename(ee.base)}-${v}`;q.add(Ze);let y=G.join(k,Ze);await FS(ee.base,y,i),M.push({base:ee.base,dir:y});let w=await zo(ee.base);J.push({name:Ze,dir:y,base:ee.base,baseRef:w,repo:ee.slug})}await wi(k,J,i),E={dir:k,kind:"multi",branch:i,repos:J}}else I=!0,await W.mkdir(k,{recursive:!0}),await Rf(k),await ci(k),E={dir:k,base:null,branch:null,kind:"repo"};let O=!1,T=null;if(l?.sha&&E.kind==="worktree")try{await Mn(k,["fetch","origin",l.ref||Jp(e)],pm);let{stdout:q}=await Mn(k,["rev-parse","FETCH_HEAD^"]),{stdout:J}=await Mn(k,["rev-parse","HEAD"]);q.trim()===J.trim()?(await Mn(k,["read-tree","--reset","-u","FETCH_HEAD"]),await Mn(k,["reset","-q"]),O=!0):T="snapshot does not parent the fetched branch head"}catch(q){T=String(q?.message||q).split(`
198
+ `)[0]}else l?.sha&&(T="wip snapshots cover single-repo worktrees only");await PS({id:e,cwd:k}).catch(()=>({restored:!1}));let j=G.join(k,oo),Z=null;(await lc(k)).restored?Z="checkpoint":typeof u=="string"&&u.trim()&&(await W.mkdir(G.dirname(j),{recursive:!0}),await W.writeFile(j,u),Z="brief");let ie=new Set(g.tracks.flatMap(q=>(q.boxes||[]).map(J=>J.name))),D=null;p&&!ie.has(p)&&!await se(p).catch(()=>null)?D=p:(D=`${t.trim()} lead`,ie.has(wc(D))&&(D=`${t.trim().slice(0,50).trim()} ${e} lead`));let R=await Jn(D,k,{agentCmd:h,agent:n});wa({cwd:R.cwd,sessionName:R.name,agent:n,agentCmd:h});let U=Date.now(),pe=jm(R,"lead","live"),Se=(Array.isArray(f)?f:[]).filter(q=>q&&typeof q=="object").map(q=>({...q})),He=Se[Se.length-1];He&&He.endedAt==null&&(He.endedAt=U,He.endReason==null&&(He.endReason=o==="recover"?"node-offline":"node-transfer")),Se.push({agent:n,sessionId:R.sessionId??null,pinned:R.pinned===!0,startedAt:U,endedAt:null}),pe.epochs=Se;let le={id:e,name:t.trim(),cwd:R.cwd,workspace:E,leadBox:R.name,boxes:[pe],events:[],createdAt:Number.isFinite(d)?d:U,...Z?{pendingHandoffHydrate:{artifact:oo,at:U}}:{}};return he(le,"transferred-in",{box:R.name,agent:n,fromNode:s,toNode:a,mode:o,reason:m,branch:E.branch??null,wip:O,epoch:Se.length-1,name:le.name,cwd:le.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:q,base:J,baseRef:ee,repo:Ze})=>({name:q,base:J,baseRef:ee,repo:Ze}))}:{}}}),g.tracks.push(le),await Y(),{...await _t(le),adopt:{wipApplied:O,wipSkipped:T,codeless:I,artifactSource:Z}}}catch(N){for(let O of M)await pt(O.base,O.dir).catch(()=>{});throw await W.rm(k,{recursive:!0,force:!0}).catch(()=>{}),N}}async function uv(e,t,n){let r=await z(),o=re(r,e);o&&(o.subtasks=o.subtasks||{},o.subtasks[t]={...o.subtasks[t]||{},...n},await Y())}async function gs(e,t){e.step=t,await yi(e)}function dv(e,t=Date.now()){if(!e||e.finishedAt)return null;let n=e.step;return["snapshot","spawn","working"].includes(n)?{...e,step:"error",finishedAt:t,error:`interrupted by an agent restart during "${n}"; no changes were applied to the lead \u2014 retry the delegation`,recovered:"rolled-back"}:{...e,step:"error",finishedAt:t,error:`interrupted by an agent restart during "${n}"; the lead's working tree may hold a PARTIAL merge \u2014 review git status. The subtask's work is preserved on branch ${e.branch}`,recovered:"partial-merge"}}function fv(e){return!!e&&!e.finishedAt&&!e.canceled&&e.step==="working"&&!!e.box&&!!e.dir&&!!e.base&&!!e.branch}async function ZD(e,t,n){if(!fv(n)||wt.has(t)||!await se(n.box).catch(()=>null))return!1;try{await W.access(n.dir)}catch{return!1}let o=await se(e.leadBox).catch(()=>null);if(!o?.cwd)return!1;let s={...n,id:t,leadBox:e.leadBox,step:"working",canceled:!1,forceMerge:!1};return wt.set(t,s),mv(s,o).catch(a=>pv(s,a)),!0}async function Km(){let e=await z(),t=!1;for(let n of e.tracks||[]){for(let[r,o]of Object.entries(n.subtasks||{})){if(wt.has(r))continue;if(await ZD(n,r,o)){t=!0,he(n,"subtask-resumed",{box:o.box,agent:o.agent,task:o.task,subtaskId:r,resumedStep:o.step}),await X({flow:"subtask",phase:"resumed",trackId:n.id,subtaskId:r,box:o.box,branch:o.branch}).catch(()=>{});continue}let s=o.step,a=dv(o);if(!a)continue;t=!0,n.subtasks[r]=a;let i=n.boxes.find(c=>c.subtaskId===r);i&&!Nn.has(i.state)&&(i.state="canceled"),he(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 X({flow:"subtask",phase:"reconciled",trackId:n.id,subtaskId:r,outcome:a.step,recovered:a.recovered,box:o.box,branch:o.branch}).catch(()=>{}),await US(n,o.box,o.dir)}for(let r of n.boxes){if(r.role!=="subtask"||Nn.has(r.state)||wt.has(r.subtaskId)||n.subtasks?.[r.subtaskId])continue;t=!0,r.state="canceled";let o=r.subtaskId?G.join(Ss,`${n.id}-${r.subtaskId}`):null;await X({flow:"subtask",phase:"reaped-legacy-orphan",trackId:n.id,subtaskId:r.subtaskId,box:r.name}).catch(()=>{}),await US(n,r.name,o)}}return t=await QD(e)||t,t&&await Y(),t}async function US(e,t,n){if(t&&await Ct(t).catch(()=>{}),!n)return;if(e.workspace?.kind==="multi"){for(let o of gt(e.workspace)){let s=G.join(n,o.name);await pt(o.base,s).then(()=>!0,()=>!1)||await pt(o.dir,s).catch(()=>{})}await W.rm(n,{recursive:!0,force:!0}).catch(()=>{});return}let r=await se(e.leadBox).catch(()=>null);r?.cwd&&await pt(r.cwd,n).catch(()=>{})}async function QD(e){let t;try{t=await W.readdir(Ss)}catch{return!1}let n=new Set;for(let o of e.tracks||[]){for(let s of Object.keys(o.subtasks||{}))n.add(`${o.id}-${s}`);for(let s of o.boxes||[])s.subtaskId&&n.add(`${o.id}-${s.subtaskId}`)}for(let o of wt.values())o.dir&&n.add(G.basename(o.dir));let r=!1;for(let o of t){if(n.has(o))continue;let s=G.join(Ss,o),a=(e.tracks||[]).find(i=>o.startsWith(`${i.id}-`));if(a?.workspace?.kind==="multi"){for(let i of gt(a.workspace))await pt(i.base,G.join(s,i.name)).catch(()=>{});await W.rm(s,{recursive:!0,force:!0}).catch(()=>{})}else{let i=a?await se(a.leadBox).catch(()=>null):null;i?.cwd?await pt(i.cwd,s).catch(()=>{}):await W.rm(s,{recursive:!0,force:!0}).catch(()=>{})}await X({flow:"subtask",phase:"swept-orphan-worktree",dir:s}).catch(()=>{}),r=!0}return r}async function Vm(e,{agent:t,task:n,skipPermissions:r=!0,reason:o=null}={}){if(typeof n!="string"||!qo(n))throw new Error("task (string) required");let s=await pi(t,r),a=zr(t);if(a){let p=new Error(`can't delegate to ${t} \u2014 its ${a.window} spend limit is reached ($${a.spentUsd.toFixed(2)} of $${a.limitUsd.toFixed(2)})`);throw p.usageCap=a,p}let i=re(await z(),e);if(!i)throw new Error(`track "${e}" not found`);let c=await se(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=gt(i.workspace);if(!p.length)throw new Error("this multi-repo Track has no tagged repos to delegate into");for(let m of p)if(!m?.dir||!await Ko(m.dir))throw new Error(`tagged checkout "${m?.name??"?"}" is missing from the lead workspace (${m?.dir??"no dir"})`);u=p.map(m=>({name:m.name,leadDir:m.dir,base:null}))}else if(!await Ko(c.cwd))throw new Error(`subtask delegation needs the lead's workspace to be a git repo (got ${c.cwd})`);let f=vs().slice(0,8),d={id:f,trackId:e,trackName:i.name,agent:t,task:qo(n),skipPermissions:r,reason:VS(o),step:"snapshot",leadBox:i.leadBox,box:null,branch:`bostrat/${Gm(i.name)}-${f}`,base:null,repos:u,dir:G.join(Ss,`${e}-${f}`),stat:null,conflicts:[],applied:null,startedAt:Date.now(),finishedAt:null,error:null,canceled:!1,forceMerge:!1};return wt.set(f,d),await yi(d),eB(d,c,s).catch(p=>pv(d,p)),d}async function pv(e,t){e.failedStep=e.step,e.error=t instanceof di?"canceled":t?.message||String(t),e.step=t instanceof di?"canceled":"error",e.finishedAt=Date.now(),await Jm(e).catch(()=>{}),await yi(e).catch(()=>{}),await oB(e).catch(()=>{})}function Vl(e){let t=wt.get(e);if(!t)throw new Error(`subtask "${e}" not found`);if(t.finishedAt)throw new Error("subtask already finished");return t.canceled=!0,t}function zm(e){let t=wt.get(e);if(!t)throw new Error(`subtask "${e}" not found`);if(t.finishedAt)throw new Error("subtask already finished");if(t.step!=="working")throw new Error(`subtask is not waiting to merge (step: ${t.step})`);return t.forceMerge=!0,t}async function eB(e,t,n){if(await gs(e,"snapshot"),e.repos){for(let s of e.repos)s.base=await Go(s.leadDir,`bostrat: snapshot for subtask ${e.id}`);await yi(e)}else e.base=await Go(t.cwd,`bostrat: snapshot for subtask ${e.id}`);if(await gs(e,"spawn"),await W.mkdir(Ss,{recursive:!0}),e.repos){await W.mkdir(e.dir,{recursive:!0});for(let a of e.repos)await Vo(a.leadDir,G.join(e.dir,a.name),e.branch,a.base);let s=gt((re(await z(),e.trackId)||{}).workspace);await wi(e.dir,e.repos.map(a=>{let i=s.find(c=>c?.name===a.name);return{name:a.name,repo:i?.repo??null,baseRef:null}}),e.branch)}else await Vo(t.cwd,e.dir,e.branch,e.base),await ci(e.dir);await tB(e,t);let r=e.trackName.slice(0,38).trim(),o=await Jn(`${r} ${e.agent} sub ${e.id}`,e.dir,{agentCmd:n,agent:e.agent});e.box=o.name,await nB(e,o),await zS(e.trackId,o.name,nD(e.task,!!e.repos),{kind:"subtask"}),await mv(e,t)}async function mv(e,t){await gs(e,"working");let n=G.join(e.dir,Cl);if(await aB(n,e),e.canceled)throw new di;if(await gs(e,"merge"),e.repos){let s={files:0,insertions:0,deletions:0},a=[],i=[],c=!0;for(let l of e.repos){let u=G.join(e.dir,l.name);await If(u,`bostrat: subtask ${e.id} result (auto-committed)`),l.stat=await Of(l.leadDir,l.base,e.branch,ws),l.files=await Cf(l.leadDir,l.base,e.branch,ws);let f=await Mf(l.leadDir,l.base,e.branch,ws);l.applied=f.applied,l.conflicts=f.conflicts??[],s.files+=l.stat.files,s.insertions+=l.stat.insertions,s.deletions+=l.stat.deletions,a.push(...l.files.map(d=>G.join(l.name,d))),i.push(...l.conflicts.map(d=>d.startsWith("patch did not apply cleanly")?`${l.name}: ${d}`:G.join(l.name,d))),f.applied||(c=!1)}e.stat=s,e.files=a,e.conflicts=i,e.applied=c}else{await If(e.dir,`bostrat: subtask ${e.id} result (auto-committed)`),e.stat=await Of(t.cwd,e.base,e.branch,ws),e.files=await Cf(t.cwd,e.base,e.branch,ws);let s=await Mf(t.cwd,e.base,e.branch,ws);e.applied=s.applied,e.conflicts=s.conflicts}await yi(e);let r=await sB(e,t,n);await gs(e,"resume"),await zS(e.trackId,e.leadBox,rD(e.task,e.stat,e.conflicts,r),{kind:"subtask-resume"}),await gs(e,"reap"),await Jm(e),e.step="done";let o=Date.now();await uv(e.trackId,e.id,{...Gl(e),finishedAt:o}),await rB(e,o),e.finishedAt=o}async function tB(e,t){let n=G.join(e.dir,G.dirname(oi));await W.mkdir(n,{recursive:!0});let r="";try{r=await Lg(t.cwd,t.sessionId)}catch{}if(!r)try{r=await W.readFile(G.join(t.cwd,".bostrat/handoff/latest.md"),"utf8")}catch{r="_(no prior conversation digest available \u2014 rely on the working tree.)_"}let o=`# Lead context for subtask ${e.id}
196
199
 
197
200
  **Delegated task:** ${e.task}
198
201
 
@@ -203,15 +206,15 @@ ${a}`}async function Im(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<
203
206
  ## Conversation so far (lead \u2192 you)
204
207
 
205
208
  ${r}
206
- `;await W.writeFile(G.join(e.dir,Qa),o)}async function UD(e,t){let n=await z(),r=re(n,e.trackId);r&&(r.boxes.push({name:t.name,agent:t.agent,role:"subtask",state:"live",cwd:t.cwd,sessionId:t.sessionId,hookTokenHash:js(t.hookToken),createdAt:Date.now(),subtaskId:e.id,branch:e.branch,task:e.task}),he(r,"subtask-delegated",{to:t.name,toAgent:e.agent,task:e.task,subtaskId:e.id,skipPermissions:e.skipPermissions,reason:e.reason}),r.subtasks=r.subtasks||{},r.subtasks[e.id]={...r.subtasks[e.id]||{},...Hl(e)},await X())}async function HD(e,t=e.finishedAt){let n=await z(),r=re(n,e.trackId);if(!r)return;let o=r.boxes.find(s=>s.subtaskId===e.id);o&&(o.state=e.conflicts.length?"conflict":"merged",o.stat=e.stat),he(r,"subtask-merged",{from:e.box,fromAgent:e.agent,task:e.task,subtaskId:e.id,stat:e.stat,conflicts:e.conflicts.length,files:e.files,durationMs:t?t-e.startedAt:null}),await X()}async function WD(e){let t=await z(),n=re(t,e.trackId);if(!n)return;let r=e.canceled||e.error==="canceled",o=n.boxes.find(s=>s.subtaskId===e.id);o&&(o.state=r?"canceled":"failed"),he(n,r?"subtask-canceled":"subtask-failed",{from:e.box,fromAgent:e.agent,task:e.task,subtaskId:e.id,failedStep:e.failedStep||e.step,error:e.error,durationMs:e.finishedAt?e.finishedAt-e.startedAt:null}),n.subtasks=n.subtasks||{},n.subtasks[e.id]={...n.subtasks[e.id]||{},...Hl(e)},await X()}async function qD(e,t,n){let r=`.bostrat/handoff/subtask-${e.id}.md`;try{let o=G.join(t.cwd,r);await W.mkdir(G.dirname(o),{recursive:!0}),await W.copyFile(n,o)}catch{}return r}async function qm(e){if(e.dir&&await Gu(e.dir).catch(()=>{}),e.box&&await Ct(e.box).catch(()=>{}),e.repos&&e.dir){for(let t of e.repos)await pt(t.leadDir,G.join(e.dir,t.name)).catch(()=>{});await W.rm(e.dir,{recursive:!0,force:!0}).catch(()=>{})}else if(e.dir){let n=(await se(e.leadBox).catch(()=>null))?.cwd;n&&await pt(n,e.dir).catch(()=>{})}}async function KD(e,t){let n=(t.startedAt||Date.now())+ND;for(;;){if(t.canceled||t.forceMerge)return;try{await W.access(e);return}catch{}if(Date.now()>n)throw new Error("subtask timed out without signaling completion (no result digest written)");await gr(PD)}}function gr(e){return new Promise(t=>setTimeout(t,e))}var PS,rn,DS,DP,Za,BP,$l,ii,wr,so,jS,jP,Il,Qa,LP,FP,At,zp,re,Jp,he,Yp,Xp,HP,Mn,$S,KP,GP,VP,zP,XP,ei,OS,eD,tD,nD,rD,oD,hs,ti,cD,uD,dD,pD,Zp,mD,wD,JS,ni,YS,kD,Xa,Qp,xD,em,ED,oi,AD,_D,CS,tm,im,Mm,ys,xs,cm,Cn,lm,Pm,nm,ND,PD,bs,ps,wt,DD,co,Hl,mi,Um,ai,fr=O(()=>{zs();tt();Jd();ab();Tc();Wn();bc();db();Qe();un();Fs();yc();Ib();Br();gf();bf();Kb();Cd();kc();Hd();Nt();Lc();Un();ha();Wc();yk();Nf();J0();qd();Bd();X0();up();ue();bl();Ba();Yo();Ep();us();Pp();Al();Hp();wn();vS();Gp();RS();ac();PS=PP(NP),rn=process.env.BOSTRAT_STATE_DIR||G.join(process.env.HOME||"/tmp",".bostrat"),DS=G.join(rn,"tracks.json"),DP=G.join(rn,"events.jsonl"),Za=G.join(rn,"workspaces"),BP=process.env.BOSTRAT_DEFAULT_REPO||null,$l={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"}},ii=Object.keys($l);wr={at:0,value:null};so=".bostrat/handoff/latest.md",jS=Number(process.env.BOSTRAT_HANDOFF_CHECKPOINT_TIMEOUT_MS)||9e4;jP=/\(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\.\)$/;Il=".bostrat/handoff/subtask-result.md",Qa=".bostrat/handoff/lead-context.md",LP=(e,t=!1)=>t?`You are a SUBTASK agent working in an isolated multi-repo workspace, delegated by a lead agent on a shared workstream. This directory is NOT itself a git repo: each subdirectory is an isolated git worktree of one of the workstream's repos, already seeded with the lead's full working tree for that repo. The conversation so far is summarized in ${Qa} \u2014 read that first for context. Your scoped task:
209
+ `;await W.writeFile(G.join(e.dir,oi),o)}async function nB(e,t){let n=await z(),r=re(n,e.trackId);r&&(r.boxes.push({name:t.name,agent:t.agent,role:"subtask",state:"live",cwd:t.cwd,sessionId:t.sessionId,hookTokenHash:Hs(t.hookToken),createdAt:Date.now(),subtaskId:e.id,branch:e.branch,task:e.task}),he(r,"subtask-delegated",{to:t.name,toAgent:e.agent,task:e.task,subtaskId:e.id,skipPermissions:e.skipPermissions,reason:e.reason}),r.subtasks=r.subtasks||{},r.subtasks[e.id]={...r.subtasks[e.id]||{},...Gl(e)},await Y())}async function rB(e,t=e.finishedAt){let n=await z(),r=re(n,e.trackId);if(!r)return;let o=r.boxes.find(s=>s.subtaskId===e.id);o&&(o.state=e.conflicts.length?"conflict":"merged",o.stat=e.stat),he(r,"subtask-merged",{from:e.box,fromAgent:e.agent,task:e.task,subtaskId:e.id,stat:e.stat,conflicts:e.conflicts.length,files:e.files,durationMs:t?t-e.startedAt:null}),await Y()}async function oB(e){let t=await z(),n=re(t,e.trackId);if(!n)return;let r=e.canceled||e.error==="canceled",o=n.boxes.find(s=>s.subtaskId===e.id);o&&(o.state=r?"canceled":"failed"),he(n,r?"subtask-canceled":"subtask-failed",{from:e.box,fromAgent:e.agent,task:e.task,subtaskId:e.id,failedStep:e.failedStep||e.step,error:e.error,durationMs:e.finishedAt?e.finishedAt-e.startedAt:null}),n.subtasks=n.subtasks||{},n.subtasks[e.id]={...n.subtasks[e.id]||{},...Gl(e)},await Y()}async function sB(e,t,n){let r=`.bostrat/handoff/subtask-${e.id}.md`;try{let o=G.join(t.cwd,r);await W.mkdir(G.dirname(o),{recursive:!0}),await W.copyFile(n,o)}catch{}return r}async function Jm(e){if(e.dir&&await Xu(e.dir).catch(()=>{}),e.box&&await Ct(e.box).catch(()=>{}),e.repos&&e.dir){for(let t of e.repos)await pt(t.leadDir,G.join(e.dir,t.name)).catch(()=>{});await W.rm(e.dir,{recursive:!0,force:!0}).catch(()=>{})}else if(e.dir){let n=(await se(e.leadBox).catch(()=>null))?.cwd;n&&await pt(n,e.dir).catch(()=>{})}}async function aB(e,t){let n=(t.startedAt||Date.now())+JD;for(;;){if(t.canceled||t.forceMerge)return;try{await W.access(e);return}catch{}if(Date.now()>n)throw new Error("subtask timed out without signaling completion (no result digest written)");await ao(XD)}}function ao(e){return new Promise(t=>setTimeout(t,e))}var HS,sn,WS,QP,ri,eD,Nl,fi,wr,oo,KS,tD,Cl,oi,nD,rD,At,em,re,tm,he,nm,rm,sD,Nn,BS,cD,lD,uD,dD,mD,si,jS,gD,yD,bD,kD,xD,ys,ai,ED,_D,ID,OD,nv,ii,rv,PD,ni,om,DD,sm,FD,li,UD,HD,LS,am,fm,jm,xs,Es,pm,Mn,mm,Fm,im,JD,XD,Ss,ws,wt,YD,co,Gl,yi,Gm,di,fr=C(()=>{Zs();Ve();tf();pb();ga();qn();vc();yb();et();Gt();qs();Sc();Pb();Dr();vf();Ef();Zb();Rc();Dd();Tc();zd();Nt();Wc();Hn();ya();Vc();Ek();Ff();n0();Xd();Wd();o0();wp();ue();vl();Ha();Qo();Op();ps();Up();$l();zp();gn();$S();Zp();DS();uc();HS=ZP(YP),sn=process.env.BOSTRAT_STATE_DIR||G.join(process.env.HOME||"/tmp",".bostrat"),WS=G.join(sn,"tracks.json"),QP=G.join(sn,"events.jsonl"),ri=G.join(sn,"workspaces"),eD=process.env.BOSTRAT_DEFAULT_REPO||null,Nl={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"}},fi=Object.keys(Nl);wr={at:0,value:null};oo=".bostrat/handoff/latest.md",KS=Number(process.env.BOSTRAT_HANDOFF_CHECKPOINT_TIMEOUT_MS)||9e4;tD=/\(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\.\)$/;Cl=".bostrat/handoff/subtask-result.md",oi=".bostrat/handoff/lead-context.md",nD=(e,t=!1)=>t?`You are a SUBTASK agent working in an isolated multi-repo workspace, delegated by a lead agent on a shared workstream. This directory is NOT itself a git repo: each subdirectory is an isolated git worktree of one of the workstream's repos, already seeded with the lead's full working tree for that repo. The conversation so far is summarized in ${oi} \u2014 read that first for context. Your scoped task:
207
210
 
208
211
  ${e}
209
212
 
210
- 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 ${Il} (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 ${Qa} \u2014 read that first for context. Your scoped task:
213
+ 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 ${Cl} (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 ${oi} \u2014 read that first for context. Your scoped task:
211
214
 
212
215
  ${e}
213
216
 
214
- 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 ${Il} 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.`,FP=(e,t,n,r)=>`A subtask box you delegated has finished: "${e}". Its changes are now merged into your working tree (${t.files} file${t.files===1?"":"s"}, +${t.insertions} \u2212${t.deletions}). Read ${r} for exactly what it did. `+(n.length?`IMPORTANT: ${n.length} merge conflict${n.length===1?"":"s"} need resolving \u2014 fix the conflict markers in: ${n.join(", ")}, then continue.`:"Review the merged changes and continue the work."),At=null,zp=null;re=(e,t)=>e.tracks.find(n=>n.id===t)||null,Jp=Promise.resolve();he=(e,t,n={})=>{let r={at:Date.now(),type:t,...n};return e.events.push(r),UP(e.id,r),xk(e,r),r};Bg(async({sessionName:e,from:t,to:n,version:r,status:o,error:s})=>{let i=(await z()).tracks.find(c=>c.leadBox===e||(c.boxes||[]).some(l=>l.name===e));i&&(he(i,"codex-update",{box:e,from:t,to:r||n,status:o,...s?{error:s}:{}}),await X().catch(()=>{}))});Yp=G.join(rn,"plane-link","update-notice.json");Xp=(e,t,n)=>t!=null&&n.some(r=>e===r.box&&t>=r.from&&t<=r.to),HP=new Set(["stuck","wrong-approach","too-slow","want-different-model","context-refresh","cost","parallelize","other"]);Mn=new Set(["merged","conflict","canceled","failed","handed-off"]),$S=new Map;KP=5e3;GP={claude:[/^\[Request interrupted by user(?: for tool use)?\]$/i],codex:[/^\[?Request interrupted/i,/^Conversation interrupted/i],cursor:[/^\[?Request interrupted/i]};VP=[/^\/model(?:\s|$)/i,/<command-(?:name|message|args)>[^<]*\bmodel\b/i,/^Model changed to\b/i];zP=10*6e4;XP=1500,ei=new Map;OS="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.";eD=4e3,tD=3,nD=[300,350,400],rD=1e3,oD=12,hs=new Map,ti=new Map;cD=[250,400,500,600];uD=3e4,dD=[350,650,900];pD=[250,450,700],Zp=2,mD=new Set(["claude","codex"]);wD=12e4;JS=e=>({branch:e.branch,kind:e.kind,repos:(e.repos??[]).filter(Boolean).map(({name:t,base:n,baseRef:r,repo:o})=>({name:t,base:n,baseRef:r,repo:o}))});ni="# bostrat workspace",YS=`${ni}
217
+ 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 ${Cl} 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.`,rD=(e,t,n,r)=>`A subtask box you delegated has finished: "${e}". Its changes are now merged into your working tree (${t.files} file${t.files===1?"":"s"}, +${t.insertions} \u2212${t.deletions}). Read ${r} for exactly what it did. `+(n.length?`IMPORTANT: ${n.length} merge conflict${n.length===1?"":"s"} need resolving \u2014 fix the conflict markers in: ${n.join(", ")}, then continue.`:"Review the merged changes and continue the work."),At=null,em=null;re=(e,t)=>e.tracks.find(n=>n.id===t)||null,tm=Promise.resolve();he=(e,t,n={})=>{let r={at:Date.now(),type:t,...n};return e.events.push(r),oD(e.id,r),Ik(e,r),r};Wg(async({sessionName:e,from:t,to:n,version:r,status:o,error:s})=>{let i=(await z()).tracks.find(c=>c.leadBox===e||(c.boxes||[]).some(l=>l.name===e));i&&(he(i,"codex-update",{box:e,from:t,to:r||n,status:o,...s?{error:s}:{}}),await Y().catch(()=>{}))});nm=G.join(sn,"plane-link","update-notice.json");rm=(e,t,n)=>t!=null&&n.some(r=>e===r.box&&t>=r.from&&t<=r.to),sD=new Set(["stuck","wrong-approach","too-slow","want-different-model","context-refresh","cost","parallelize","other"]);Nn=new Set(["merged","conflict","canceled","failed","handed-off"]),BS=new Map;cD=5e3;lD={claude:[/^\[Request interrupted by user(?: for tool use)?\]$/i],codex:[/^\[?Request interrupted/i,/^Conversation interrupted/i],cursor:[/^\[?Request interrupted/i]};uD=[/^\/model(?:\s|$)/i,/<command-(?:name|message|args)>[^<]*\bmodel\b/i,/^Model changed to\b/i];dD=10*6e4;mD=1500,si=new Map;jS="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.";gD=4e3,yD=3,bD=[300,350,400],kD=1e3,xD=12,ys=new Map,ai=new Map;ED=[250,400,500,600];_D=3e4,ID=[350,650,900];OD=12e4;nv=e=>({branch:e.branch,kind:e.kind,repos:(e.repos??[]).filter(Boolean).map(({name:t,base:n,baseRef:r,repo:o})=>({name:t,base:n,baseRef:r,repo:o}))});ii="# bostrat workspace",rv=`${ii}
215
218
 
216
219
  TRACK MEMORY: if \`.bostrat/memory/MEMORY.md\` exists in your workspace, read it
217
220
  before substantive work \u2014 it is the shared cross-provider memory for this repo
@@ -369,10 +372,13 @@ of publishing it.
369
372
  When a real DECISION gets made in this Track \u2014 an approach chosen over
370
373
  alternatives, a tradeoff settled, a plan changed \u2014 record it:
371
374
 
372
- bostrat-decision record --title "<the choice>" [--context "<why it came up>"]
373
- [--alt "<option rejected>"]\u2026 "<what was decided>"
375
+ bostrat-decision record --title "<the choice, \u226472 chars>" --summary "<one sentence, \u2264160 chars>"
376
+ [--context "<why it came up>"] [--alt "<option rejected>"]\u2026 "<what was decided>"
374
377
 
375
- Record the WHY, not a summary of the work: name each option you rejected
378
+ The title is the choice AS A LABEL; the summary is one sentence a reader can
379
+ act on without opening the record \u2014 both render on the Track-details rail, so
380
+ \`--summary\` is required and the caps are enforced (the full story goes in the
381
+ decision text). Record the WHY, not a summary of the work: name each option you rejected
376
382
  (\`--alt\`), because that is the half nobody can reconstruct weeks later. One
377
383
  decision per record. Records are IMMUTABLE \u2014 if the call later changes, record
378
384
  a NEW one with \`--supersedes <id>\` (\`bostrat-decision ls\` prints ids) and the
@@ -479,15 +485,15 @@ which steps to run (and which to skip). An offer buried mid-message, phrased as
479
485
  statement, or omitted entirely renders no controls \u2014 so close EVERY completed
480
486
  implementation turn this way, every time. When the operator has already asked you
481
487
  to commit / push / open the PR, just do it; do not re-offer.
482
- `,kD=YS,Xa=YS+xy;Qp=e=>typeof e=="string"&&(e===ni||e.startsWith(`${ni}
483
- `)),xD="# bostrat multi-repo workspace";em=Xa.replace(`${ni}
484
- `,`${ni}
488
+ `,PD=rv,ni=rv+_y;om=e=>typeof e=="string"&&(e===ii||e.startsWith(`${ii}
489
+ `)),DD="# bostrat multi-repo workspace";sm=ni.replace(`${ii}
490
+ `,`${ii}
485
491
 
486
492
  (Global copy managed by bostrat \u2014 rewritten on service start; edits will be lost.)
487
493
  SCOPE: these instructions apply ONLY when your working directory is under
488
494
  ~/.bostrat/workspaces/ or ~/.bostrat/worktrees/ \u2014 a bostrat-orchestrated box.
489
495
  When working anywhere else, ignore everything below.
490
- `);ED=new Set(["claude","codex","cursor"]);oi=new Set,AD=e=>oi.has(e);_D=9e4;CS={merged:"merged",closed:"closed on GitHub WITHOUT merging",lost:"no longer found on GitHub (deleted, or its repo left the grant)"};tm=new Map;im=120;Mm=(e,t,n)=>({name:e.name,agent:e.agent,role:t,state:n,cwd:e.cwd,sessionId:e.sessionId,pinned:e.pinned===!0,hookTokenHash:js(e.hookToken),createdAt:Date.now()});ys=new Map,xs=e=>ys.get(e)||(At?re(At,e)?.handoff:null)||null;cm=6e4,Cn=(e,t,n=15e3)=>PS("git",["-C",e,...t],{timeout:n,maxBuffer:8*1024*1024}),lm=new Map,Pm=e=>lm.get(e)||null;nm=new Map;ND=Number(process.env.BOSTRAT_SUBTASK_TIMEOUT_MS)||18e5,PD=Number(process.env.BOSTRAT_SUBTASK_POLL_MS)||3e3,bs=G.join(rn,"worktrees"),ps=[Qa,Il],wt=new Map,DD=e=>wt.get(e)||(At?At.tracks.map(t=>t.subtasks?.[e]).find(Boolean):null)||null,co=e=>{let t=new Map([...wt.values()].filter(r=>r.trackId===e).map(r=>[r.id,r])),n=At?re(At,e):null;if(n?.subtasks)for(let[r,o]of Object.entries(n.subtasks))t.has(r)||t.set(r,o);return[...t.values()].sort((r,o)=>r.startedAt-o.startedAt)},Hl=e=>({id:e.id,trackId:e.trackId,trackName:e.trackName,agent:e.agent,task:e.task,skipPermissions:e.skipPermissions,reason:e.reason||null,step:e.step,failedStep:e.failedStep||null,box:e.box,branch:e.branch,base:e.base,repos:e.repos||null,dir:e.dir,stat:e.stat,files:e.files||null,conflicts:e.conflicts||[],applied:e.applied,error:e.error,canceled:e.canceled,startedAt:e.startedAt,finishedAt:e.finishedAt});mi=e=>rv(e.trackId,e.id,Hl(e));Um=e=>e.trim().replace(/\s+/g,"-").replace(/[^A-Za-z0-9._-]/g,"").toLowerCase()||"track",ai=class extends Error{}});tt();import ge from"node:path";import Ye from"node:fs";import YF from"node:readline";import{fileURLToPath as XF}from"node:url";import Rt from"express";import ZF from"node:http";import QF from"node:https";import Xh from"node:os";import{WebSocketServer as eU}from"ws";tt();import wI from"node-pty";async function dg(e,t,n={}){if(!_e(t)){wc(e,`invalid session name: ${t}`),e.close(1008,"invalid session name");return}if(!await Vn()){wc(e,`host tmux server not running on ${ft}`),e.close(1011,"tmux server unavailable");return}if(!await se(t)){wc(e,`session "${t}" not found`),e.close(1008,"session not found");return}let r=ug(n.cols,120,fg),o=ug(n.rows,32,pg),s;try{s=wI.spawn(F,["-S",ft,"attach-session","-d","-t",t],{name:"xterm-256color",cols:r,rows:o,cwd:process.env.HOME||"/",env:{...process.env,TERM:"xterm-256color"}})}catch(a){wc(e,`failed to spawn tmux attach: ${a.message}`),e.close(1011,"spawn failed");return}s.onData(a=>{e.readyState===e.OPEN&&sd(e,{type:"data",data:a})}),s.onExit(({exitCode:a,signal:i})=>{e.readyState===e.OPEN&&(sd(e,{type:"exit",code:a??null,signal:i??null}),e.close(1e3,"tmux exited"))}),e.on("message",a=>{let i;try{i=JSON.parse(a.toString())}catch{return}if(!(!i||typeof i!="object")){if(i.type==="data"&&typeof i.data=="string")s.write(i.data);else if(i.type==="resize"&&kI(i.cols,i.rows))try{s.resize(Math.min(500,i.cols|0),Math.min(500,i.rows|0))}catch{}}}),e.on("close",()=>{try{s.kill()}catch{}bI(t)})}var gI=6,yI=250;async function bI(e,t=gI,n=yI){for(let r=0;r<t;r++){if(await Nr(e).catch(()=>!0))return!0;await new Promise(o=>setTimeout(o,n))}return!1}var fg=20,pg=6;function kI(e,t){return Number.isFinite(Number(e))&&Number.isFinite(Number(t))&&Number(e)>=fg&&Number(t)>=pg}function ug(e,t,n){let r=Number(e);return!Number.isFinite(r)||r<n?t:Math.min(500,r|0)}function sd(e,t){try{e.send(JSON.stringify(t))}catch{}}function wc(e,t){sd(e,{type:"error",message:t})}function mg(e){let t=typeof e=="string"&&e?e:"/",n=t.indexOf("?"),r=n===-1?t:t.slice(0,n),o=n===-1?"":t.slice(n+1),s=r.match(/^\/api\/attach\/([^/]+)$/);if(!s)return{ok:!1,status:404};let a;try{a=decodeURIComponent(s[1])}catch{return{ok:!1,status:400}}let i=new URLSearchParams(o);return{ok:!0,sessionName:a,cols:Number(i.get("cols"))||void 0,rows:Number(i.get("rows"))||void 0}}Nt();yc();Jd();fr();import{createRequire as tU}from"node:module";var GD=e=>!!e&&!e.finishedAt&&!e.canceled&&!e.error;function Km({tracks:e=[],views:t=[],queuedOf:n=()=>[]}={}){let r=[];for(let o of e)!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(GD)&&r.push(`merge-back:${o.id}`));return t.some(o=>o?.state==="live"||o?.state==="starting")&&r.push("views"),{busy:r.length>0,reasons:r}}import hv from"node:fs";import yr from"node:fs/promises";import iB from"node:os";import Ge from"node:path";import{spawn as cB}from"node:child_process";import{createRequire as lB}from"node:module";ue();Wc();import pv from"node:fs";import Vm from"node:fs/promises";import JD from"node:http";import Nn from"node:path";import Gl from"node:os";import{createRequire as YD}from"node:module";import zm from"ws";import VD from"node:path";import zD from"node:os";var hi=process.env.BOSTRAT_STATE_DIR||VD.join(process.env.HOME||zD.tmpdir(),".bostrat");function Gm(e=process.env){let t=(e.BOSTRAT_HOST||"").trim();if(t!=="all")return t||(e.BOSTRAT_PLANE_URL?"127.0.0.1":void 0)}function lv(e=process.env){if(!e.BOSTRAT_PLANE_URL)return null;let t=Gm(e);return t==="127.0.0.1"||t==="::1"||t==="localhost"?null:{host:t}}function uv(e){let t=String(e||"").trim();if(!t)return"";let n=/^[a-z][a-z0-9+.-]*:\/\//i.test(t)?t:`wss://${t}`,r;try{r=new URL(n)}catch{return t}let o={"https:":"wss:","http:":"ws:","wss:":"wss:","ws:":"ws:"}[r.protocol];return o?(r.protocol=o,(r.pathname===""||r.pathname==="/")&&(r.pathname="/v1/node"),r.toString()):t}var jt=(()=>{try{return YD(import.meta.url)("../package.json").version||null}catch{return null}})(),XD=process.env.BOSTRAT_STATE_DIR||Nn.join(process.env.HOME||Gl.tmpdir(),".bostrat");function lo({env:e=process.env,pkgDir:t=Nn.resolve(Nn.dirname(new URL(import.meta.url).pathname),".."),exists:n=pv.existsSync}={}){let r=String(e.BOSTRAT_INSTALL_KIND||"").trim();return["container","npm-global","git-checkout","dev"].includes(r)?r:/\/lib\/node_modules\/bostrat-node(?:\/|$)/.test(t.replace(/\\/g,"/"))?"npm-global":n(Nn.join(t,"..",".git"))?"git-checkout":"dev"}function wi(e,t){let n=String(e).split(".").map(Number),r=String(t).split(".").map(Number);if(n.some(Number.isNaN)||r.some(Number.isNaN))return!1;for(let o=0;o<Math.max(n.length,r.length);o++){let s=(n[o]||0)-(r[o]||0);if(s)return s<0}return!1}function ql(e){switch(e){case"npm-global":return"npm install -g bostrat-node && restart the bostrat-node service";case"git-checkout":return"scripts/deploy-pi.sh (or The Bakery \u2192 Deploy to Pi \u2192 bostrat)";case"container":return"Links \u2192 Fly \u2192 Update (or the plane's auto-update while the node sleeps)";default:return"update this node's bostrat-node checkout/install"}}function ZD({home:e=process.env.HOME||Gl.homedir(),env:t=process.env}={}){let n=r=>{try{return pv.statSync(r),!0}catch{return!1}};return{claude:n(Nn.join(e,".claude",".credentials.json")),codex:n(Nn.join(t.CODEX_HOME||Nn.join(e,".codex"),"auth.json"))}}var Ke=1,dv=1e3,fv=3e4,QD=6e4,eB=1500,tB=500,Kl=100,nB=2e3,rB=25e3,oB=6e4,sB=6e4,aB=6e4;function mv({url:e,token:t,nodeId:n=Gl.hostname(),name:r=Gl.hostname(),listTracks:o,detectAgents:s=null,onTracksTransferred:a=null,sampleMetrics:i=null,metricsMs:c=sB,onUpdateAvailable:l=null,onUpdatePolicy:u=null,onHelloRefused:f=null,updatePolicy:d=null,installKind:p=lo(),selfUrl:m=`http://127.0.0.1:${process.env.PORT||3362}`,log:h=console}){if(!e||!t)throw new Error("plane-link: url and token are required");if(typeof o!="function")throw new Error("plane-link: listTracks is required");e=uv(e);let g=m.replace(/^http/,"ws"),x=new Set,k=new Map,E=new Map,I=Nn.join(XD,"plane-link","cursor.json"),M={},N={},C=new Map,T=null,j=!1,Z=!1,fe=dv,ie=null,D=null,R=null,U=null,pe=null,Se=!1,He=0;async function le(){try{M=JSON.parse(await Vm.readFile(I,"utf8"))}catch{M={}}}function q(){Se=!0,!R&&(R=setTimeout(async()=>{if(R=null,!!Se){Se=!1;try{await Vm.mkdir(Nn.dirname(I),{recursive:!0}),await Vm.writeFile(I,JSON.stringify(M))}catch(te){h.error("[plane-link] cursor flush failed:",te?.message||te)}}},nB),R.unref?.())}function J(te){return!T||T.readyState!==zm.OPEN?!1:(T.send(JSON.stringify(te)),!0)}function ee(te){let V=Date.now();for(let{trackId:A,event:B}of te){let ye=C.get(B.id);C.set(B.id,{trackId:A,seq:B.seq,event:B,sentAt:V,tries:(ye?.tries??0)+1})}return J({v:Ke,ch:"events",type:"append",events:te})}function Xe(te){let V=null;for(let A of C.values())A.trackId===te&&(V==null||A.seq<V)&&(V=A.seq);return V}function y(te){let V=N[te];if(V==null)return;let A=Xe(te),B=A==null?V:Math.min(V,A-1);B>(M[te]??0)&&(M[te]=B,q())}function w(){if(!j)return;let te=Date.now(),V=[...C.values()].filter(A=>A.event&&te-A.sentAt>=oB);if(V.length){V.sort((A,B)=>A.trackId===B.trackId?A.seq-B.seq:A.trackId<B.trackId?-1:1),h.log(`[plane-link] re-sending ${V.length} unacked event(s) the plane never confirmed`);for(let A=0;A<V.length;A+=Kl){let B=V.slice(A,A+Kl).map(ye=>({trackId:ye.trackId,event:ye.event}));if(!ee(B))return}}}async function v(){if(!i)return;let te;try{te=await i()}catch(V){h.error("[plane-link] metrics sample failed:",V?.message||V);return}te&&J({v:Ke,ch:"ctl",type:"metrics",metrics:te})}function $(){i&&(pe&&clearInterval(pe),v(),pe=setInterval(v,c),pe.unref?.())}async function ve(){let te;try{te=await o()}catch(V){h.error("[plane-link] backfill listTracks failed:",V?.message||V);return}J({v:Ke,ch:"ctl",type:"tracks",ids:te.filter(V=>!V.transferredTo).map(V=>V.id).filter(V=>typeof V=="string")});for(let V of te){if(!j)return;let A;try{A=await L(V)}catch{continue}let B=M[V.id]??0,ye=A.filter(be=>be.seq>B&&typeof be.id=="string");for(let be=0;be<ye.length;be+=Kl){let Ze=ye.slice(be,be+Kl).map(kt=>({trackId:V.id,event:kt}));if(!ee(Ze))return}}}function b(te){!j||!te?.trackId||typeof te.id!="string"||ee([{trackId:te.trackId,event:te}])}let P=new Map;async function Me(te){let{reqId:V,method:A,path:B,headers:ye={},body:be}=te,Ze=Object.fromEntries(Object.entries(ye).filter(([,Wt])=>Wt!=null)),kt=new AbortController;P.set(V,kt);try{if(te.host){await We(te,Ze,kt);return}let Wt=await fetch(m+B,{method:A,headers:Ze,body:be?Buffer.from(be,"base64"):void 0,signal:kt.signal}),jn=Object.fromEntries(Wt.headers);for(let xt of["connection","keep-alive","transfer-encoding","upgrade","content-encoding","content-length"])delete jn[xt];if(jn["content-type"]||(jn["content-type"]="application/octet-stream"),J({v:Ke,ch:"control",type:"http_head",reqId:V,status:Wt.status,headers:jn}),Wt.body){for await(let xt of Wt.body)if(!J({v:Ke,ch:"control",type:"http_data",reqId:V,data:Buffer.from(xt).toString("base64")}))break}J({v:Ke,ch:"control",type:"http_end",reqId:V,error:null})}finally{P.delete(V)}}function We(te,V,A){let{reqId:B,method:ye,path:be,body:Ze}=te,kt=new URL(m);return new Promise(Wt=>{let jn=JD.request({host:kt.hostname,port:kt.port,method:ye,path:be,headers:{...V,host:te.host},signal:A.signal},xt=>{let{connection:yU,"keep-alive":bU,"transfer-encoding":kU,upgrade:xU,...lA}=xt.headers;J({v:Ke,ch:"control",type:"http_head",reqId:B,status:xt.statusCode||502,headers:lA}),xt.on("data",uA=>{J({v:Ke,ch:"control",type:"http_data",reqId:B,data:Buffer.from(uA).toString("base64")})||xt.destroy()}),xt.on("end",()=>{J({v:Ke,ch:"control",type:"http_end",reqId:B,error:null}),Wt()}),xt.on("error",()=>{J({v:Ke,ch:"control",type:"http_end",reqId:B,error:"view upstream error"}),Wt()})});jn.on("error",xt=>{J({v:Ke,ch:"control",type:"http_end",reqId:B,error:xt?.message||"view request failed"}),Wt()}),Ze&&jn.write(Buffer.from(Ze,"base64")),jn.end()})}function Ht(){if(Z)return;T=new zm(e,{headers:{authorization:`Bearer ${t}`}}),T.on("open",async()=>{let V=null;try{V=await s?.()||null}catch{V=null}J({v:Ke,ch:"ctl",type:"hello",nodeId:n,name:r,platform:process.platform,version:jt,installKind:p,...typeof d=="function"?{updatePolicy:d()}:d?{updatePolicy:d}:{},providers:ZD(),...V?{agents:V}:{}})}),T.on("message",V=>{let A;try{A=JSON.parse(V)}catch{return}if(A.ch==="ctl"&&A.type==="hello_ok"){j=!0,fe=dv,ie=null,h.log(`[plane-link] connected to plane as ${n}`),A.minNodeVersion&&jt&&wi(jt,A.minNodeVersion)&&h.error(`[plane-link] this node is bostrat-node ${jt}; the plane asks for \u2265${A.minNodeVersion} \u2014 update with: ${ql(p)}`);try{u?.(typeof A.updatePolicy=="string"?A.updatePolicy:null)}catch{}let B=typeof A.latestNodeVersion=="string"?A.latestNodeVersion:null;if(B&&jt&&wi(jt,B)&&!x.has(B)){x.add(B),h.log(`[plane-link] bostrat-node ${B} is available (this node runs ${jt}) \u2014 ${ql(p)}`);try{l?.({current:jt,latest:B,min:A.minNodeVersion??null,installKind:p,required:!!(A.minNodeVersion&&wi(jt,A.minNodeVersion))})}catch(ye){h.error(`[plane-link] update notice failed: ${ye?.message||ye}`)}}U&&clearInterval(U),U=setInterval(()=>{J({v:Ke,ch:"ctl",type:"ping"}),w()},rB),U.unref?.(),$(),ve().catch(ye=>h.error("[plane-link] backfill failed:",ye?.message||ye));return}if(A.ch==="ctl"&&A.type==="hello_refused"){let B=typeof A.minNodeVersion=="string"?A.minNodeVersion:null,ye=typeof A.latestNodeVersion=="string"?A.latestNodeVersion:null;h.error(`[plane-link] plane REFUSED this node: bostrat-node ${jt??"?"} is below its minimum ${B??"?"} \u2014 ${A.fix||ql(p)}`),fe=fv,ie=0;try{f?.({current:jt,min:B,latest:ye,fix:A.fix||ql(p),installKind:p})}catch(be){h.error(`[plane-link] refusal handler failed: ${be?.message||be}`)}return}if(A.ch==="ctl"&&A.type==="update_policy"){try{u?.(typeof A.mode=="string"?A.mode:null)}catch{}return}if(A.ch==="ctl"&&A.type==="usage_caps"){Hc(A.caps??{},{source:"plane",updatedAt:A.updatedAt??Date.now()}).then(B=>h.log(`[plane-link] spend caps ${Object.keys(B.caps).length?`updated (${Object.keys(B.caps).join(", ")})`:"cleared"} from plane`)).catch(B=>h.error("[plane-link] spend-caps push rejected:",B?.message||B));return}if(A.ch==="ctl"&&A.type==="transferred"&&Array.isArray(A.tracks)){Promise.resolve().then(()=>a?.(A.tracks)).catch(B=>h.error("[plane-link] transfer notice failed:",B?.message||B));return}if(A.ch==="events"&&A.type==="ack"&&Array.isArray(A.ids)){let B=new Set;for(let ye of A.ids){let be=C.get(ye);be&&(C.delete(ye),(N[be.trackId]??0)<be.seq&&(N[be.trackId]=be.seq),B.add(be.trackId))}for(let ye of B)y(ye);return}if(A.ch==="control"&&A.type==="http_open"){Me(A).catch(B=>J({v:Ke,ch:"control",type:"http_end",reqId:A.reqId,error:B?.message||"tunnel error"}));return}if(A.ch==="control"&&A.type==="http_cancel"){P.get(A.reqId)?.abort();return}if(A.ch==="attach"&&A.type==="open"){let B=new zm(g+A.path,Array.isArray(A.protocols)?A.protocols:[],A.host?{headers:{host:A.host}}:void 0);k.set(A.streamId,B),E.set(A.streamId,[]),B.on("open",()=>{let be=E.get(A.streamId)||[];E.delete(A.streamId);for(let{buf:Ze,bin:kt}of be)B.send(Ze,{binary:kt})}),B.on("message",(be,Ze)=>{let kt=Ze?be:Buffer.from(String(be));J({v:Ke,ch:"attach",type:"data",streamId:A.streamId,data:kt.toString("base64"),...Ze?{bin:!0}:{}})});let ye=()=>{E.delete(A.streamId),k.delete(A.streamId)&&J({v:Ke,ch:"attach",type:"close",streamId:A.streamId})};B.on("close",ye),B.on("error",ye);return}if(A.ch==="attach"&&A.type==="data"){let B=k.get(A.streamId);if(!B)return;let ye=Buffer.from(A.data,"base64"),be=A.bin===!0,Ze=E.get(A.streamId);Ze?Ze.push({buf:ye,bin:be}):B.send(ye,{binary:be});return}if(A.ch==="attach"&&A.type==="close"){let B=k.get(A.streamId);k.delete(A.streamId),E.delete(A.streamId),B?.close();return}});let te=()=>{j&&h.log("[plane-link] disconnected from plane"),j=!1,U&&(clearInterval(U),U=null),pe&&(clearInterval(pe),pe=null),C.clear(),N={};for(let B of k.values())B.close();k.clear(),E.clear();for(let B of P.values())B.abort();if(P.clear(),Z||D)return;ie==null&&(ie=Date.now());let V=Date.now()-ie<QD,A=V?eB+Math.random()*tB:fe;D=setTimeout(()=>{D=null,Ht()},A),D.unref?.(),V||(fe=Math.min(fe*2,fv))};T.on("close",te),T.on("error",V=>{let A=/Unexpected server response: (\d+)/.exec(V?.message||"")?.[1];(A==="401"||A==="403")&&Date.now()-He>=aB&&(He=Date.now(),h.error(`[plane-link] plane refused this node's credentials (HTTP ${A}) \u2014 the token was revoked or is unknown to the plane; mint a new node token and update this node's BOSTRAT_PLANE_TOKEN (still retrying)`)),te()})}return st.on("event",b),le().then(Ht),{stop:()=>{Z=!0,st.off("event",b),D&&clearTimeout(D),R&&clearTimeout(R),U&&clearInterval(U),pe&&clearInterval(pe),J({v:Ke,ch:"ctl",type:"bye",reason:"shutdown"}),T?.close()},status:()=>({connected:j,nodeId:n,cursor:{...M},inflight:C.size})}}bc();var Vl=(()=>{try{return lB(import.meta.url)("../package.json").version||null}catch{return null}})(),uB=process.env.BOSTRAT_STATE_DIR||Ge.join(process.env.HOME||iB.tmpdir(),".bostrat"),wv=Ge.join(uB,"self-update"),zl=Ge.join(wv,"status.json"),dB=1440*6e4,fB=6e4,Jm=new Set(["npm-global","git-checkout"]);function gv({kind:e=lo(),env:t=process.env}={}){let n=String(t.BOSTRAT_UPDATE_POLICY||"").trim();return["auto","prompt","off"].includes(n)?n:Jm.has(e)?e==="git-checkout"||pB(t)?"auto":"prompt":"off"}function pB(e=process.env){return!!(e.INVOCATION_ID||e.XPC_SERVICE_NAME&&e.XPC_SERVICE_NAME!=="0")}var yt=e=>`'${String(e).replace(/'/g,"'\\''")}'`;function mB({kind:e,to:t,from:n=Vl,statusFile:r=zl,logFile:o=Ge.join(wv,"last.log"),port:s=Number(process.env.PORT)||3362,npmPrefix:a=null,serviceName:i=process.platform==="darwin"?"com.bostrat.node":"bostrat-node.service",uid:c=typeof process.getuid=="function"?process.getuid():0,liveDir:l=process.env.BOSTRAT_LIVE_CHECKOUT||Ge.resolve(Ge.dirname(new URL(import.meta.url).pathname),"..",".."),startedAt:u=Date.now()}={}){if(!Jm.has(e))throw new Error(`self-update: install kind "${e}" is not actionable here`);if(!/^\d+\.\d+\.\d+$/.test(String(t)))throw new Error(`self-update: bad target version "${t}"`);if(n&&!/^\d+\.\d+\.\d+$/.test(String(n)))throw new Error(`self-update: bad current version "${n}"`);let f=(g,x="")=>`write_status ${yt(g)} ${x}`,d=process.platform==="darwin"?`launchctl kickstart -k gui/${c}/${i}`:`systemctl --user restart ${yt(i)}`,p=`
496
+ `);FD=new Set(["claude","codex","cursor"]);li=new Set,UD=e=>li.has(e);HD=9e4;LS={merged:"merged",closed:"closed on GitHub WITHOUT merging",lost:"no longer found on GitHub (deleted, or its repo left the grant)"};am=new Map;fm=120;jm=(e,t,n)=>({name:e.name,agent:e.agent,role:t,state:n,cwd:e.cwd,sessionId:e.sessionId,pinned:e.pinned===!0,hookTokenHash:Hs(e.hookToken),createdAt:Date.now()});xs=new Map,Es=e=>xs.get(e)||(At?re(At,e)?.handoff:null)||null;pm=6e4,Mn=(e,t,n=15e3)=>HS("git",["-C",e,...t],{timeout:n,maxBuffer:8*1024*1024}),mm=new Map,Fm=e=>mm.get(e)||null;im=new Map;JD=Number(process.env.BOSTRAT_SUBTASK_TIMEOUT_MS)||18e5,XD=Number(process.env.BOSTRAT_SUBTASK_POLL_MS)||3e3,Ss=G.join(sn,"worktrees"),ws=[oi,Cl],wt=new Map,YD=e=>wt.get(e)||(At?At.tracks.map(t=>t.subtasks?.[e]).find(Boolean):null)||null,co=e=>{let t=new Map([...wt.values()].filter(r=>r.trackId===e).map(r=>[r.id,r])),n=At?re(At,e):null;if(n?.subtasks)for(let[r,o]of Object.entries(n.subtasks))t.has(r)||t.set(r,o);return[...t.values()].sort((r,o)=>r.startedAt-o.startedAt)},Gl=e=>({id:e.id,trackId:e.trackId,trackName:e.trackName,agent:e.agent,task:e.task,skipPermissions:e.skipPermissions,reason:e.reason||null,step:e.step,failedStep:e.failedStep||null,box:e.box,branch:e.branch,base:e.base,repos:e.repos||null,dir:e.dir,stat:e.stat,files:e.files||null,conflicts:e.conflicts||[],applied:e.applied,error:e.error,canceled:e.canceled,startedAt:e.startedAt,finishedAt:e.finishedAt});yi=e=>uv(e.trackId,e.id,Gl(e));Gm=e=>e.trim().replace(/\s+/g,"-").replace(/[^A-Za-z0-9._-]/g,"").toLowerCase()||"track",di=class extends Error{}});Ve();import ge from"node:path";import Ye from"node:fs";import dU from"node:readline";import{fileURLToPath as fU}from"node:url";import Rt from"express";import pU from"node:http";import mU from"node:https";import rw from"node:os";import{WebSocketServer as hU}from"ws";Ve();import TI from"node-pty";async function gg(e,t,n={}){if(!_e(t)){kc(e,`invalid session name: ${t}`),e.close(1008,"invalid session name");return}if(!await zn()){kc(e,`host tmux server not running on ${ft}`),e.close(1011,"tmux server unavailable");return}if(!await se(t)){kc(e,`session "${t}" not found`),e.close(1008,"session not found");return}let r=wg(n.cols,120,yg),o=wg(n.rows,32,bg),s;try{s=TI.spawn(F,["-S",ft,"attach-session","-d","-t",t],{name:"xterm-256color",cols:r,rows:o,cwd:process.env.HOME||"/",env:{...process.env,TERM:"xterm-256color"}})}catch(a){kc(e,`failed to spawn tmux attach: ${a.message}`),e.close(1011,"spawn failed");return}s.onData(a=>{e.readyState===e.OPEN&&ld(e,{type:"data",data:a})}),s.onExit(({exitCode:a,signal:i})=>{e.readyState===e.OPEN&&(ld(e,{type:"exit",code:a??null,signal:i??null}),e.close(1e3,"tmux exited"))}),e.on("message",a=>{let i;try{i=JSON.parse(a.toString())}catch{return}if(!(!i||typeof i!="object")){if(i.type==="data"&&typeof i.data=="string")s.write(i.data);else if(i.type==="resize"&&II(i.cols,i.rows))try{s.resize(Math.min(500,i.cols|0),Math.min(500,i.rows|0))}catch{}}}),e.on("close",()=>{try{s.kill()}catch{}_I(t)})}var EI=6,AI=250;async function _I(e,t=EI,n=AI){for(let r=0;r<t;r++){if(await Mr(e).catch(()=>!0))return!0;await new Promise(o=>setTimeout(o,n))}return!1}var yg=20,bg=6;function II(e,t){return Number.isFinite(Number(e))&&Number.isFinite(Number(t))&&Number(e)>=yg&&Number(t)>=bg}function wg(e,t,n){let r=Number(e);return!Number.isFinite(r)||r<n?t:Math.min(500,r|0)}function ld(e,t){try{e.send(JSON.stringify(t))}catch{}}function kc(e,t){ld(e,{type:"error",message:t})}function kg(e){let t=typeof e=="string"&&e?e:"/",n=t.indexOf("?"),r=n===-1?t:t.slice(0,n),o=n===-1?"":t.slice(n+1),s=r.match(/^\/api\/attach\/([^/]+)$/);if(!s)return{ok:!1,status:404};let a;try{a=decodeURIComponent(s[1])}catch{return{ok:!1,status:400}}let i=new URLSearchParams(o);return{ok:!0,sessionName:a,cols:Number(i.get("cols"))||void 0,rows:Number(i.get("rows"))||void 0}}Nt();Sc();tf();fr();import{createRequire as wU}from"node:module";var iB=e=>!!e&&!e.finishedAt&&!e.canceled&&!e.error;function Xm({tracks:e=[],views:t=[],queuedOf:n=()=>[]}={}){let r=[];for(let o of e)!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(iB)&&r.push(`merge-back:${o.id}`));return t.some(o=>o?.state==="live"||o?.state==="starting")&&r.push("views"),{busy:r.length>0,reasons:r}}import Sv from"node:fs";import gr from"node:fs/promises";import SB from"node:os";import Ge from"node:path";import{spawn as vB}from"node:child_process";import{createRequire as TB}from"node:module";ue();Vc();import kv from"node:fs";import Zm from"node:fs/promises";import uB from"node:http";import Pn from"node:path";import Xl from"node:os";import{createRequire as dB}from"node:module";import Qm from"ws";import cB from"node:path";import lB from"node:os";var bi=process.env.BOSTRAT_STATE_DIR||cB.join(process.env.HOME||lB.tmpdir(),".bostrat");function Ym(e=process.env){let t=(e.BOSTRAT_HOST||"").trim();if(t!=="all")return t||(e.BOSTRAT_PLANE_URL?"127.0.0.1":void 0)}function wv(e=process.env){if(!e.BOSTRAT_PLANE_URL)return null;let t=Ym(e);return t==="127.0.0.1"||t==="::1"||t==="localhost"?null:{host:t}}function gv(e){let t=String(e||"").trim();if(!t)return"";let n=/^[a-z][a-z0-9+.-]*:\/\//i.test(t)?t:`wss://${t}`,r;try{r=new URL(n)}catch{return t}let o={"https:":"wss:","http:":"ws:","wss:":"wss:","ws:":"ws:"}[r.protocol];return o?(r.protocol=o,(r.pathname===""||r.pathname==="/")&&(r.pathname="/v1/node"),r.toString()):t}var jt=(()=>{try{return dB(import.meta.url)("../package.json").version||null}catch{return null}})(),fB=process.env.BOSTRAT_STATE_DIR||Pn.join(process.env.HOME||Xl.tmpdir(),".bostrat");function lo({env:e=process.env,pkgDir:t=Pn.resolve(Pn.dirname(new URL(import.meta.url).pathname),".."),exists:n=kv.existsSync}={}){let r=String(e.BOSTRAT_INSTALL_KIND||"").trim();return["container","npm-global","git-checkout","dev"].includes(r)?r:/\/lib\/node_modules\/bostrat-node(?:\/|$)/.test(t.replace(/\\/g,"/"))?"npm-global":n(Pn.join(t,"..",".git"))?"git-checkout":"dev"}function ki(e,t){let n=String(e).split(".").map(Number),r=String(t).split(".").map(Number);if(n.some(Number.isNaN)||r.some(Number.isNaN))return!1;for(let o=0;o<Math.max(n.length,r.length);o++){let s=(n[o]||0)-(r[o]||0);if(s)return s<0}return!1}function zl(e){switch(e){case"npm-global":return"npm install -g bostrat-node && restart the bostrat-node service";case"git-checkout":return"scripts/deploy-pi.sh (or The Bakery \u2192 Deploy to Pi \u2192 bostrat)";case"container":return"Links \u2192 Fly \u2192 Update (or the plane's auto-update while the node sleeps)";default:return"update this node's bostrat-node checkout/install"}}function pB({home:e=process.env.HOME||Xl.homedir(),env:t=process.env}={}){let n=r=>{try{return kv.statSync(r),!0}catch{return!1}};return{claude:n(Pn.join(e,".claude",".credentials.json")),codex:n(Pn.join(t.CODEX_HOME||Pn.join(e,".codex"),"auth.json"))}}var Ke=1,yv=1e3,bv=3e4,mB=6e4,hB=1500,wB=500,Jl=100,gB=2e3,yB=25e3,bB=6e4,kB=6e4,xB=6e4;function xv({url:e,token:t,nodeId:n=Xl.hostname(),name:r=Xl.hostname(),listTracks:o,detectAgents:s=null,onTracksTransferred:a=null,sampleMetrics:i=null,metricsMs:c=kB,onUpdateAvailable:l=null,onUpdatePolicy:u=null,onHelloRefused:f=null,updatePolicy:d=null,installKind:p=lo(),selfUrl:m=`http://127.0.0.1:${process.env.PORT||3362}`,log:h=console}){if(!e||!t)throw new Error("plane-link: url and token are required");if(typeof o!="function")throw new Error("plane-link: listTracks is required");e=gv(e);let g=m.replace(/^http/,"ws"),x=new Set,k=new Map,E=new Map,I=Pn.join(fB,"plane-link","cursor.json"),M={},N={},O=new Map,T=null,j=!1,Z=!1,fe=yv,ie=null,D=null,R=null,U=null,pe=null,Se=!1,He=0;async function le(){try{M=JSON.parse(await Zm.readFile(I,"utf8"))}catch{M={}}}function q(){Se=!0,!R&&(R=setTimeout(async()=>{if(R=null,!!Se){Se=!1;try{await Zm.mkdir(Pn.dirname(I),{recursive:!0}),await Zm.writeFile(I,JSON.stringify(M))}catch(te){h.error("[plane-link] cursor flush failed:",te?.message||te)}}},gB),R.unref?.())}function J(te){return!T||T.readyState!==Qm.OPEN?!1:(T.send(JSON.stringify(te)),!0)}function ee(te){let V=Date.now();for(let{trackId:A,event:B}of te){let ye=O.get(B.id);O.set(B.id,{trackId:A,seq:B.seq,event:B,sentAt:V,tries:(ye?.tries??0)+1})}return J({v:Ke,ch:"events",type:"append",events:te})}function Ze(te){let V=null;for(let A of O.values())A.trackId===te&&(V==null||A.seq<V)&&(V=A.seq);return V}function y(te){let V=N[te];if(V==null)return;let A=Ze(te),B=A==null?V:Math.min(V,A-1);B>(M[te]??0)&&(M[te]=B,q())}function w(){if(!j)return;let te=Date.now(),V=[...O.values()].filter(A=>A.event&&te-A.sentAt>=bB);if(V.length){V.sort((A,B)=>A.trackId===B.trackId?A.seq-B.seq:A.trackId<B.trackId?-1:1),h.log(`[plane-link] re-sending ${V.length} unacked event(s) the plane never confirmed`);for(let A=0;A<V.length;A+=Jl){let B=V.slice(A,A+Jl).map(ye=>({trackId:ye.trackId,event:ye.event}));if(!ee(B))return}}}async function v(){if(!i)return;let te;try{te=await i()}catch(V){h.error("[plane-link] metrics sample failed:",V?.message||V);return}te&&J({v:Ke,ch:"ctl",type:"metrics",metrics:te})}function $(){i&&(pe&&clearInterval(pe),v(),pe=setInterval(v,c),pe.unref?.())}async function ve(){let te;try{te=await o()}catch(V){h.error("[plane-link] backfill listTracks failed:",V?.message||V);return}J({v:Ke,ch:"ctl",type:"tracks",ids:te.filter(V=>!V.transferredTo).map(V=>V.id).filter(V=>typeof V=="string")});for(let V of te){if(!j)return;let A;try{A=await L(V)}catch{continue}let B=M[V.id]??0,ye=A.filter(be=>be.seq>B&&typeof be.id=="string");for(let be=0;be<ye.length;be+=Jl){let Qe=ye.slice(be,be+Jl).map(kt=>({trackId:V.id,event:kt}));if(!ee(Qe))return}}}function b(te){!j||!te?.trackId||typeof te.id!="string"||ee([{trackId:te.trackId,event:te}])}let P=new Map;async function Me(te){let{reqId:V,method:A,path:B,headers:ye={},body:be}=te,Qe=Object.fromEntries(Object.entries(ye).filter(([,Wt])=>Wt!=null)),kt=new AbortController;P.set(V,kt);try{if(te.host){await We(te,Qe,kt);return}let Wt=await fetch(m+B,{method:A,headers:Qe,body:be?Buffer.from(be,"base64"):void 0,signal:kt.signal}),Ln=Object.fromEntries(Wt.headers);for(let xt of["connection","keep-alive","transfer-encoding","upgrade","content-encoding","content-length"])delete Ln[xt];if(Ln["content-type"]||(Ln["content-type"]="application/octet-stream"),J({v:Ke,ch:"control",type:"http_head",reqId:V,status:Wt.status,headers:Ln}),Wt.body){for await(let xt of Wt.body)if(!J({v:Ke,ch:"control",type:"http_data",reqId:V,data:Buffer.from(xt).toString("base64")}))break}J({v:Ke,ch:"control",type:"http_end",reqId:V,error:null})}finally{P.delete(V)}}function We(te,V,A){let{reqId:B,method:ye,path:be,body:Qe}=te,kt=new URL(m);return new Promise(Wt=>{let Ln=uB.request({host:kt.hostname,port:kt.port,method:ye,path:be,headers:{...V,host:te.host},signal:A.signal},xt=>{let{connection:MU,"keep-alive":NU,"transfer-encoding":PU,upgrade:DU,...gA}=xt.headers;J({v:Ke,ch:"control",type:"http_head",reqId:B,status:xt.statusCode||502,headers:gA}),xt.on("data",yA=>{J({v:Ke,ch:"control",type:"http_data",reqId:B,data:Buffer.from(yA).toString("base64")})||xt.destroy()}),xt.on("end",()=>{J({v:Ke,ch:"control",type:"http_end",reqId:B,error:null}),Wt()}),xt.on("error",()=>{J({v:Ke,ch:"control",type:"http_end",reqId:B,error:"view upstream error"}),Wt()})});Ln.on("error",xt=>{J({v:Ke,ch:"control",type:"http_end",reqId:B,error:xt?.message||"view request failed"}),Wt()}),Qe&&Ln.write(Buffer.from(Qe,"base64")),Ln.end()})}function Ht(){if(Z)return;T=new Qm(e,{headers:{authorization:`Bearer ${t}`}}),T.on("open",async()=>{let V=null;try{V=await s?.()||null}catch{V=null}J({v:Ke,ch:"ctl",type:"hello",nodeId:n,name:r,platform:process.platform,version:jt,installKind:p,...typeof d=="function"?{updatePolicy:d()}:d?{updatePolicy:d}:{},providers:pB(),...V?{agents:V}:{}})}),T.on("message",V=>{let A;try{A=JSON.parse(V)}catch{return}if(A.ch==="ctl"&&A.type==="hello_ok"){j=!0,fe=yv,ie=null,h.log(`[plane-link] connected to plane as ${n}`),A.minNodeVersion&&jt&&ki(jt,A.minNodeVersion)&&h.error(`[plane-link] this node is bostrat-node ${jt}; the plane asks for \u2265${A.minNodeVersion} \u2014 update with: ${zl(p)}`);try{u?.(typeof A.updatePolicy=="string"?A.updatePolicy:null)}catch{}let B=typeof A.latestNodeVersion=="string"?A.latestNodeVersion:null;if(B&&jt&&ki(jt,B)&&!x.has(B)){x.add(B),h.log(`[plane-link] bostrat-node ${B} is available (this node runs ${jt}) \u2014 ${zl(p)}`);try{l?.({current:jt,latest:B,min:A.minNodeVersion??null,installKind:p,required:!!(A.minNodeVersion&&ki(jt,A.minNodeVersion))})}catch(ye){h.error(`[plane-link] update notice failed: ${ye?.message||ye}`)}}U&&clearInterval(U),U=setInterval(()=>{J({v:Ke,ch:"ctl",type:"ping"}),w()},yB),U.unref?.(),$(),ve().catch(ye=>h.error("[plane-link] backfill failed:",ye?.message||ye));return}if(A.ch==="ctl"&&A.type==="hello_refused"){let B=typeof A.minNodeVersion=="string"?A.minNodeVersion:null,ye=typeof A.latestNodeVersion=="string"?A.latestNodeVersion:null;h.error(`[plane-link] plane REFUSED this node: bostrat-node ${jt??"?"} is below its minimum ${B??"?"} \u2014 ${A.fix||zl(p)}`),fe=bv,ie=0;try{f?.({current:jt,min:B,latest:ye,fix:A.fix||zl(p),installKind:p})}catch(be){h.error(`[plane-link] refusal handler failed: ${be?.message||be}`)}return}if(A.ch==="ctl"&&A.type==="update_policy"){try{u?.(typeof A.mode=="string"?A.mode:null)}catch{}return}if(A.ch==="ctl"&&A.type==="usage_caps"){Gc(A.caps??{},{source:"plane",updatedAt:A.updatedAt??Date.now()}).then(B=>h.log(`[plane-link] spend caps ${Object.keys(B.caps).length?`updated (${Object.keys(B.caps).join(", ")})`:"cleared"} from plane`)).catch(B=>h.error("[plane-link] spend-caps push rejected:",B?.message||B));return}if(A.ch==="ctl"&&A.type==="transferred"&&Array.isArray(A.tracks)){Promise.resolve().then(()=>a?.(A.tracks)).catch(B=>h.error("[plane-link] transfer notice failed:",B?.message||B));return}if(A.ch==="events"&&A.type==="ack"&&Array.isArray(A.ids)){let B=new Set;for(let ye of A.ids){let be=O.get(ye);be&&(O.delete(ye),(N[be.trackId]??0)<be.seq&&(N[be.trackId]=be.seq),B.add(be.trackId))}for(let ye of B)y(ye);return}if(A.ch==="control"&&A.type==="http_open"){Me(A).catch(B=>J({v:Ke,ch:"control",type:"http_end",reqId:A.reqId,error:B?.message||"tunnel error"}));return}if(A.ch==="control"&&A.type==="http_cancel"){P.get(A.reqId)?.abort();return}if(A.ch==="attach"&&A.type==="open"){let B=new Qm(g+A.path,Array.isArray(A.protocols)?A.protocols:[],A.host?{headers:{host:A.host}}:void 0);k.set(A.streamId,B),E.set(A.streamId,[]),B.on("open",()=>{let be=E.get(A.streamId)||[];E.delete(A.streamId);for(let{buf:Qe,bin:kt}of be)B.send(Qe,{binary:kt})}),B.on("message",(be,Qe)=>{let kt=Qe?be:Buffer.from(String(be));J({v:Ke,ch:"attach",type:"data",streamId:A.streamId,data:kt.toString("base64"),...Qe?{bin:!0}:{}})});let ye=()=>{E.delete(A.streamId),k.delete(A.streamId)&&J({v:Ke,ch:"attach",type:"close",streamId:A.streamId})};B.on("close",ye),B.on("error",ye);return}if(A.ch==="attach"&&A.type==="data"){let B=k.get(A.streamId);if(!B)return;let ye=Buffer.from(A.data,"base64"),be=A.bin===!0,Qe=E.get(A.streamId);Qe?Qe.push({buf:ye,bin:be}):B.send(ye,{binary:be});return}if(A.ch==="attach"&&A.type==="close"){let B=k.get(A.streamId);k.delete(A.streamId),E.delete(A.streamId),B?.close();return}});let te=()=>{j&&h.log("[plane-link] disconnected from plane"),j=!1,U&&(clearInterval(U),U=null),pe&&(clearInterval(pe),pe=null),O.clear(),N={};for(let B of k.values())B.close();k.clear(),E.clear();for(let B of P.values())B.abort();if(P.clear(),Z||D)return;ie==null&&(ie=Date.now());let V=Date.now()-ie<mB,A=V?hB+Math.random()*wB:fe;D=setTimeout(()=>{D=null,Ht()},A),D.unref?.(),V||(fe=Math.min(fe*2,bv))};T.on("close",te),T.on("error",V=>{let A=/Unexpected server response: (\d+)/.exec(V?.message||"")?.[1];(A==="401"||A==="403")&&Date.now()-He>=xB&&(He=Date.now(),h.error(`[plane-link] plane refused this node's credentials (HTTP ${A}) \u2014 the token was revoked or is unknown to the plane; mint a new node token and update this node's BOSTRAT_PLANE_TOKEN (still retrying)`)),te()})}return st.on("event",b),le().then(Ht),{stop:()=>{Z=!0,st.off("event",b),D&&clearTimeout(D),R&&clearTimeout(R),U&&clearInterval(U),pe&&clearInterval(pe),J({v:Ke,ch:"ctl",type:"bye",reason:"shutdown"}),T?.close()},status:()=>({connected:j,nodeId:n,cursor:{...M},inflight:O.size})}}vc();var Yl=(()=>{try{return TB(import.meta.url)("../package.json").version||null}catch{return null}})(),EB=process.env.BOSTRAT_STATE_DIR||Ge.join(process.env.HOME||SB.tmpdir(),".bostrat"),vv=Ge.join(EB,"self-update"),Zl=Ge.join(vv,"status.json"),AB=1440*6e4,_B=6e4,eh=new Set(["npm-global","git-checkout"]);function Tv({kind:e=lo(),env:t=process.env}={}){let n=String(t.BOSTRAT_UPDATE_POLICY||"").trim();return["auto","prompt","off"].includes(n)?n:eh.has(e)?e==="git-checkout"||IB(t)?"auto":"prompt":"off"}function IB(e=process.env){return!!(e.INVOCATION_ID||e.XPC_SERVICE_NAME&&e.XPC_SERVICE_NAME!=="0")}var yt=e=>`'${String(e).replace(/'/g,"'\\''")}'`;function RB({kind:e,to:t,from:n=Yl,statusFile:r=Zl,logFile:o=Ge.join(vv,"last.log"),port:s=Number(process.env.PORT)||3362,npmPrefix:a=null,serviceName:i=process.platform==="darwin"?"com.bostrat.node":"bostrat-node.service",uid:c=typeof process.getuid=="function"?process.getuid():0,liveDir:l=process.env.BOSTRAT_LIVE_CHECKOUT||Ge.resolve(Ge.dirname(new URL(import.meta.url).pathname),"..",".."),startedAt:u=Date.now()}={}){if(!eh.has(e))throw new Error(`self-update: install kind "${e}" is not actionable here`);if(!/^\d+\.\d+\.\d+$/.test(String(t)))throw new Error(`self-update: bad target version "${t}"`);if(n&&!/^\d+\.\d+\.\d+$/.test(String(n)))throw new Error(`self-update: bad current version "${n}"`);let f=(g,x="")=>`write_status ${yt(g)} ${x}`,d=process.platform==="darwin"?`launchctl kickstart -k gui/${c}/${i}`:`systemctl --user restart ${yt(i)}`,p=`
491
497
  health() {
492
498
  for i in $(seq 1 45); do
493
499
  sleep 1
@@ -552,60 +558,60 @@ if [ -n "$FROM" ] && ${h("$FROM")}; then
552
558
  fi
553
559
  ${f("failed",'"deploy-pi.sh v$TO failed AND the rollback failed"')}
554
560
  exit 1
555
- `}async function Ss(e=zl){try{return JSON.parse(await yr.readFile(e,"utf8"))}catch{return null}}var hB=new Set(["updating","restarting","rolling-back"]),gi=e=>!!(e&&hB.has(e.status));async function Jl({to:e,from:t=Vl,kind:n=lo(),reason:r="manual",statusFile:o=zl,spawnImpl:s=cB,now:a=Date.now,npmPrefix:i=void 0,log:c=console}={}){if(!e)return{ok:!1,reason:"no target version"};if(!Jm.has(n))return{ok:!1,reason:`install kind "${n}" updates elsewhere`};if(t&&!wi(t,e))return{ok:!1,reason:`already on ${t} (target ${e})`};let l=await Ss(o);if(gi(l))return{ok:!1,reason:`an update to ${l.to} is already in flight`,status:l};if(l&&l.to===e&&(l.status==="failed"||l.status==="rolled-back"))return{ok:!1,reason:`update to ${e} already ${l.status} (${l.error||"no detail"}) \u2014 retried when a newer release exists`,status:l};await yr.mkdir(Ge.dirname(o),{recursive:!0});let u=i!==void 0?i:n==="npm-global"?Sd(await wB())||Ge.resolve(Ge.dirname(process.execPath),".."):null,f=mB({kind:n,to:e,from:t,statusFile:o,npmPrefix:u,startedAt:a()}),d=Ge.join(Ge.dirname(o),`update-${e}.sh`),p=Ge.join(Ge.dirname(o),"last.log");await yr.writeFile(d,f,{mode:448}),await yr.writeFile(o,JSON.stringify({status:"updating",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a()}));let m=hv.existsSync("/run/systemd/system")&&await gB("systemd-run")?["systemd-run",["--user","--collect","--quiet",`--unit=bostrat-self-update-${e}`,"--property=KillMode=process","bash",d]]:["setsid",["-f","bash","-c",`exec bash ${yt(d)} >> ${yt(p)} 2>&1`]];try{s(m[0],m[1],{detached:!0,stdio:"ignore"}).unref?.()}catch(h){return await yr.writeFile(o,JSON.stringify({status:"failed",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a(),error:`could not spawn updater: ${h?.message||h}`})),{ok:!1,reason:`could not spawn updater: ${h?.message||h}`}}return c.log?.(`[self-update] ${t??"?"} \u2192 ${e} (${n}, ${r}) started \u2014 status ${o}`),{ok:!0,to:e,from:t,kind:n,scriptFile:d,statusFile:o}}async function wB(){try{return await yr.realpath(new URL(import.meta.url).pathname)}catch{return""}}async function gB(e){for(let t of String(process.env.PATH||"").split(Ge.delimiter))try{return await yr.access(Ge.join(t,e),hv.constants.X_OK),!0}catch{}return!1}var yB=45*6e4;async function yv({statusFile:e=zl,current:t=Vl,now:n=Date.now,staleMs:r=yB}={}){let o=await Ss(e);if(!o)return null;let s=a=>yr.writeFile(e,JSON.stringify(a)).catch(()=>{});if(gi(o)){if(t&&o.to===t){let a={...o,status:"done",updatedAt:n(),finishedAt:n(),announced:!0};return await s(a),a}if(n()-Number(o.updatedAt||o.startedAt||0)>r){let a={...o,status:"failed",error:`updater went silent while ${o.status} (no status change for ${Math.round(r/6e4)} min)`,updatedAt:n(),finishedAt:n(),announced:!0};return await s(a),a}return null}if(["failed","rolled-back","done"].includes(o.status)&&!o.announced){let a={...o,announced:!0};return await s(a),a}return null}function bv({isBusy:e,start:t=Jl,onStuck:n=null,onStarted:r=null,tickMs:o=fB,stuckMs:s=dB,now:a=Date.now,setIntervalImpl:i=setInterval,clearIntervalImpl:c=clearInterval,log:l=console}={}){let u=null,f=()=>{u?.timer&&c(u.timer),u=null},d=async()=>{if(!u)return;let p=!0;try{p=await e()!==!1}catch{p=!0}if(p){if(!u.stuckFired&&a()-u.since>=s){u.stuckFired=!0;try{await n?.({to:u.to,from:u.from,since:u.since})}catch{}}return}let m=u;f();let h=await t({to:m.to,from:m.from,kind:m.kind,reason:"auto"});l.log?.(`[self-update] stasis reached \u2192 ${h.ok?"started":`not started: ${h.reason}`}`);try{await r?.({...m,result:h})}catch{}};return{arm({to:p,from:m=Vl,kind:h=lo()}){return u?.to===p?!1:(f(),u={to:p,from:m,kind:h,since:a(),stuckFired:!1,timer:i(d,o)},u.timer.unref?.(),!0)},tick:d,cancel:f,get armed(){return u?{to:u.to,from:u.from,kind:u.kind,since:u.since}:null}}}ue();Qe();var bB=(...e)=>fetch(...e);function kB(e=process.env){return!!(ke(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Ym(e=process.env){if(!kB(e))throw new Error("no plane configured \u2014 circuits live on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let t=new AbortController,n=setTimeout(()=>t.abort(),1e4);try{let r=await bB(`${ke(e)}/v1/circuits`,{headers:{authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN}`},signal:t.signal}),o=await r.json().catch(()=>({}));if(!r.ok)throw new Error(o?.error||`plane answered ${r.status}`);return Array.isArray(o.circuits)?o.circuits:[]}finally{clearTimeout(n)}}async function vs(e,t=process.env){let n=String(e??"").trim();if(!n)throw new Error("a circuit name or id is required");let r=await Ym(t),o=r.find(c=>c.id===n);if(o)return o;let s=n.toLowerCase(),a=r.filter(c=>c.name.toLowerCase()===s);if(a.length===1)return a[0];if(a.length>1)throw new Error(`"${n}" names ${a.length} circuits \u2014 use an id (bostrat-circuit ls)`);let i=r.filter(c=>c.name.toLowerCase().includes(s)).slice(0,5);throw new Error(i.length?`no circuit named "${n}" \u2014 near matches: ${i.map(c=>`${c.name} (${c.id})`).join(", ")}`:`no circuit named "${n}" \u2014 create it on the Circuits page first (bostrat-circuit ls lists yours)`)}async function Yl(e,t,{source:n="chat"}={}){return _(e,{type:"track.circuit.tagged",actor:"orchestrator",source:"orchestrator",payload:t?{circuitId:t.id,circuitName:t.name??null,source:n}:{circuitId:null,source:n}})}ue();Qe();var xB=(...e)=>fetch(...e);async function Xl(e,t,n,r=process.env){if(!(ke(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 xB(`${ke(r)}${t}`,{method:e,headers:{authorization:`Bearer ${r.BOSTRAT_PLANE_TOKEN}`,...n?{"content-type":"application/json"}:{}},body:n?JSON.stringify(n):void 0,signal:o.signal}),i=await a.json().catch(()=>({}));if(!a.ok)throw new Error(i?.error||`plane answered ${a.status}`);return i}finally{clearTimeout(s)}}function SB(e,t=process.env){return Xl("POST","/v1/circuits",{name:e},t).then(n=>n.circuit)}async function kv({circuitRef:e,newCircuitName:t,name:n,markdown:r},o=process.env){let s=t?await SB(t,o):await vs(e,o),a=await Xl("POST","/v1/blueprints",{circuitId:s.id,name:n,markdown:r},o);return{circuit:s,...a}}async function Xm(e,t=process.env){let n=await vs(e,t),r=await Xl("GET",`/v1/blueprints/${encodeURIComponent(n.id)}`,null,t);return{circuit:n,...r}}async function Zm(e,t=process.env){return(await Xl("GET","/v1/circuits",null,t)).memberships?.[e]??null}async function xv(e,t,n,r=process.env){let{blueprint:o,items:s}=await Xm(t,r),a=new Map(s.map(c=>[c.itemId,c])),i=n.filter(c=>!a.get(c)?.bindable);if(i.length){let c=s.filter(l=>l.bindable).map(l=>l.itemId);throw new Error(`unknown/unbindable item(s): ${i.join(", ")} \u2014 bindable ids: ${c.join(", ")||"(none)"}`)}return await _(e,{type:"blueprint.item.bound",actor:"orchestrator",source:"orchestrator",payload:{itemIds:n,blueprintId:o.id,source:"cli"}}),{blueprint:o,itemIds:n}}ue();Qe();var vB=(...e)=>fetch(...e);async function TB(e,t,n,r=process.env){if(!(ke(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 vB(`${ke(r)}${t}`,{method:e,headers:{authorization:`Bearer ${r.BOSTRAT_PLANE_TOKEN}`,...n?{"content-type":"application/json"}:{}},body:n?JSON.stringify(n):void 0,signal:o.signal}),i=await a.json().catch(()=>({}));if(!a.ok)throw new Error(i?.error||`plane answered ${a.status}`);return i}finally{clearTimeout(s)}}async function Sv(e,{title:t,context:n="",decision:r,alternatives:o=[],supersedesId:s=null}){if(!String(t??"").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 _(e,{type:"decision.recorded",actor:"orchestrator",source:"orchestrator",payload:{title:String(t).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(t).trim()}}function vv(e,t=process.env){return TB("GET",`/v1/decisions?track=${encodeURIComponent(e)}`,null,t)}Hp();ue();import vi from"node:fs/promises";import au from"node:path";import m1 from"node:os";Wn();import EB from"node:fs/promises";import Tv from"node:path";import AB from"node:os";var Ev=()=>Tv.join(process.env.BOSTRAT_STATE_DIR||Tv.join(process.env.HOME||AB.tmpdir(),".bostrat"),"integrations.json");async function Pn(){try{return JSON.parse(await EB.readFile(Ev(),"utf8"))||{}}catch{return{}}}var Zl=["linked","prOpened","prMerged","create"],Qm=["prompt","auto","off"],_B={create:["prompt","off"]},Av=e=>_B[e]??Qm;function Ql(e){let t=e.linear||{},n=t.transitions===!0?"auto":"prompt",r={};for(let o of Zl){let s=Av(o),a=s.includes(n)?n:"prompt",i=e.ticketFlow?.[o]??t.ticketFlow?.[o];r[o]=s.includes(i)?i:a}return r}async function uo(){let e=await Pn(),t=process.env.BOSTRAT_LINEAR_API_KEY||e.linear?.apiKey,n=process.env.BOSTRAT_LINEAR_DEFAULT_TEAM||e.linear?.defaultTeam||null;return t?{apiKey:t,ticketFlow:Ql(e),defaultTeam:n}:null}async function eu(){let e=await Pn(),t=e.jira||{},n=process.env.BOSTRAT_JIRA_BASE_URL||t.baseUrl,r=process.env.BOSTRAT_JIRA_EMAIL||t.email,o=process.env.BOSTRAT_JIRA_API_TOKEN||t.apiToken;return!n||!r||!o?null:{baseUrl:String(n).replace(/\/$/,""),email:r,apiToken:o,tokenExpiresAt:t.tokenExpiresAt??null,ticketFlow:Ql(e)}}async function eh(){return Ql(await Pn())}async function _v(e){let t=Object.entries(e||{});if(!t.length)throw new Error(`nothing to set \u2014 phases: ${Zl.join(", ")}`);for(let[r,o]of t){if(!Zl.includes(r))throw new Error(`unknown phase "${r}" \u2014 configurable phases: ${Zl.join(", ")}`);let s=Av(r);if(!s.includes(o))throw new Error(s.length<Qm.length?`mode "${o}" not allowed for "${r}" \u2014 ${r} is always confirmed (modes: ${s.join(", ")})`:`unknown mode "${o}" \u2014 modes: ${Qm.join(", ")}`)}let n=await Pn();return n.ticketFlow={...Ql(n),...Object.fromEntries(t)},n.linear&&(delete n.linear.ticketFlow,delete n.linear.transitions),await at(Ev(),n,{mode:384}),n.ticketFlow}async function yi(){let e=(await Pn()).deepgram||{},t=process.env.DEEPGRAM_API_KEY||e.apiKey;return t?{apiKey:t}:null}async function IB(){let e=(await Pn()).openai||{},t=process.env.BOSTRAT_OPENAI_API_KEY||e.apiKey;return t?{apiKey:t}:null}var RB={openai:{model:"gpt-realtime-2.1-mini",voice:"marin"}};async function tu(){let t=(await Pn()).voiceChat||{},n=t.provider||"openai",r=RB[n];if(!r)return null;let o=n==="openai"?await IB():null;return o?{provider:n,model:t.model||r.model,voice:t.voice||r.voice,apiKey:o.apiKey}:null}async function Iv(){let e=(await Pn()).cedar||{},t=process.env.BOSTRAT_CEDAR_INGEST_KEY||e.ingestKey,n=process.env.BOSTRAT_CEDAR_URL||e.url||"https://cedar-api.fly.dev";return t?{url:n,ingestKey:t}:null}async function fo(){let e=(await Pn()).slack||{},t=process.env.BOSTRAT_SLACK_BOT_TOKEN||e.botToken,n=process.env.BOSTRAT_SLACK_APP_TOKEN||e.appToken;return!t||!n?null:{botToken:t,appToken:n,channel:process.env.BOSTRAT_SLACK_CHANNEL||e.channel||null,maxConcurrent:Number.isInteger(e.maxConcurrent)&&e.maxConcurrent>0?e.maxConcurrent:2}}ue();Kn();Fr();us();import ki from"node:fs/promises";import Bv from"node:path";import e1 from"node:os";import{randomUUID as jv}from"node:crypto";var nh={};$u(nh,{createComment:()=>jB,findIssueUrl:()=>MB,issueStates:()=>UB,mdToAdf:()=>Ov,moveIssue:()=>HB,parseIssueRef:()=>CB,resolveIssue:()=>NB,uploadImage:()=>LB,upsertCard:()=>PB,whoami:()=>th});var Ts=e=>String(e.baseUrl||"").replace(/\/$/,""),$v=e=>`Basic ${Buffer.from(`${e.email}:${e.apiToken}`).toString("base64")}`;async function po(e,t,n,r){let o=await fetch(`${Ts(e)}${n}`,{method:t,headers:{authorization:$v(e),accept:"application/json",...r!==void 0?{"content-type":"application/json"}:{}},body:r!==void 0?JSON.stringify(r):void 0}),s=await o.text(),a=null;try{a=s?JSON.parse(s):null}catch{a=null}if(!o.ok){let i=a?.errorMessages?.[0]??Object.values(a?.errors??{})[0]??`HTTP ${o.status}`,c=new Error(`jira: ${i}`);throw c.status=o.status,c}return a}var $B=/\/browse\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,OB=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function CB(e){let t=String(e||"").trim();if(/^https?:\/\//i.test(t)){let r=t.match($B);return r?r[1].toUpperCase():null}let n=t.match(OB);return n?n[1]:null}function MB(e,t=null){let n=null;try{n=t?.baseUrl?new URL(t.baseUrl).host:null}catch{n=null}let r=/https?:\/\/[^\s)]+\/browse\/[A-Za-z][A-Za-z0-9]{0,9}-\d+[^\s)]*/g;for(let o of String(e||"").matchAll(r))try{let s=new URL(o[0]).host;if(s===n||/\.atlassian\.net$/i.test(s))return o[0]}catch{}return null}async function NB(e,t){let n;try{n=await po(e,"GET",`/rest/api/3/issue/${encodeURIComponent(t)}?fields=summary,status`)}catch(r){throw r.status===404?new Error(`jira: issue "${t}" not found`):r}return{issueId:n.id,key:n.key,title:n.fields?.summary??null,url:`${Ts(e)}/browse/${n.key}`,state:n.fields?.status?.name??null}}async function PB(e,t,{url:n,title:r,subtitle:o}){await po(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/remotelink`,{globalId:n,application:{type:"com.bostrat.tracks",name:"Bostrat"},object:{url:n,title:r,summary:o,icon:{title:"Bostrat"}}})}var DB=/(!\[[^\]]*\]\([^)\s]+\)|\*\*[^*\n]+\*\*|`[^`\n]+`|_[^_\n]+_|https?:\/\/[^\s)]+)/g;function BB(e){let t=[],n=0;for(let r of e.matchAll(DB)){r.index>n&&t.push({type:"text",text:e.slice(n,r.index)});let o=r[0];if(o.startsWith("![")){let[,s,a]=o.match(/^!\[([^\]]*)\]\(([^)\s]+)\)$/);t.push({type:"text",text:s||a,marks:[{type:"link",attrs:{href:a}}]})}else o.startsWith("**")?t.push({type:"text",text:o.slice(2,-2),marks:[{type:"strong"}]}):o.startsWith("`")?t.push({type:"text",text:o.slice(1,-1),marks:[{type:"code"}]}):o.startsWith("_")?t.push({type:"text",text:o.slice(1,-1),marks:[{type:"em"}]}):t.push({type:"text",text:o,marks:[{type:"link",attrs:{href:o}}]});n=r.index+o.length}return n<e.length&&t.push({type:"text",text:e.slice(n)}),t}function Ov(e){let t=String(e??"").split(/\n{2,}/).map(n=>n.trim()).filter(Boolean).map(n=>{let r=[];return n.split(`
556
- `).forEach((o,s)=>{s>0&&r.push({type:"hardBreak"}),r.push(...BB(o))}),{type:"paragraph",content:r.length?r:[{type:"text",text:" "}]}});return{type:"doc",version:1,content:t.length?t:[{type:"paragraph",content:[{type:"text",text:" "}]}]}}async function jB(e,t,n){let r=await po(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/comment`,{body:Ov(n)});return r?.id?`${Ts(e)}/browse/${t.key}?focusedCommentId=${r.id}`:null}async function th(e){let t=await po(e,"GET","/rest/api/3/myself"),n=null;try{n=new URL(Ts(e)).host}catch{n=e.baseUrl??null}return{user:t?.displayName??t?.emailAddress??null,org:n}}async function LB(e,{issue:t,filename:n,contentType:r,buffer:o}){let s=new FormData;s.append("file",new Blob([o],{type:r}),n);let a=await fetch(`${Ts(e)}/rest/api/3/issue/${encodeURIComponent(t)}/attachments`,{method:"POST",headers:{authorization:$v(e),"x-atlassian-token":"no-check",accept:"application/json"},body:s}),i=await a.json().catch(()=>null),c=Array.isArray(i)?i[0]:null;if(!a.ok||!c)throw new Error(`jira: attachment upload failed (HTTP ${a.status})`);return c.content??`${Ts(e)}/rest/api/3/attachment/content/${c.id}`}var FB={new:"unstarted",indeterminate:"started",done:"completed"},Rv=e=>FB[e?.key]??"started";async function UB(e,t){let n=encodeURIComponent(t.key),[r,o]=await Promise.all([po(e,"GET",`/rest/api/3/issue/${n}?fields=status`),po(e,"GET",`/rest/api/3/issue/${n}/transitions`)]),s=r?.fields?.status??null,a=s?{id:`status:${s.id}`,name:s.name,type:Rv(s.statusCategory)}:null,i=(o?.transitions??[]).map((c,l)=>({id:c.id,name:c.to?.name??c.name,type:Rv(c.to?.statusCategory),position:l}));return{current:a,states:i}}async function HB(e,t,n){await po(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/transitions`,{transition:{id:String(n)}})}var ah={};$u(ah,{createComment:()=>YB,createIssue:()=>sh,createProject:()=>oh,findIssueUrl:()=>VB,issueStates:()=>ZB,moveIssue:()=>QB,parseIssueRef:()=>GB,resolveIssue:()=>zB,teams:()=>Es,uploadImage:()=>XB,upsertCard:()=>JB,whoami:()=>rh});var WB=()=>process.env.BOSTRAT_LINEAR_API_URL||"https://api.linear.app/graphql";async function sn(e,t,n={}){let r=await fetch(WB(),{method:"POST",headers:{"content-type":"application/json",authorization:e.apiKey},body:JSON.stringify({query:t,variables:n})}),o=await r.json().catch(()=>null);if(!r.ok)throw new Error(`linear: HTTP ${r.status}${o?.errors?.[0]?.message?` \u2014 ${o.errors[0].message}`:""}`);if(o?.errors?.length){let s=o.errors[0],a=(s.extensions?.validationErrors??[]).flatMap(i=>Object.values(i?.constraints??{})).join("; ");throw new Error(`linear: ${s.message}${a?` \u2014 ${a}`:""}`)}return o?.data??{}}var qB=/linear\.app\/[^/\s]+\/issue\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,KB=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function GB(e){let t=String(e||"").trim(),n=t.match(qB);if(n)return n[1].toUpperCase();let r=t.match(KB);return r?r[1]:null}function VB(e){let t=String(e||"").match(/https?:\/\/linear\.app\/[^/\s]+\/issue\/[A-Za-z][A-Za-z0-9]{0,9}-\d+[^\s)]*/);return t?t[0]:null}async function zB(e,t){let r=(await sn(e,"query($id: String!) { issue(id: $id) { id identifier title url state { name } team { key } } }",{id:t})).issue;if(!r)throw new Error(`linear: issue "${t}" not found`);return{issueId:r.id,key:r.identifier,title:r.title,url:r.url,state:r.state?.name??null,team:r.team?.key??null}}async function JB(e,t,{url:n,title:r,subtitle:o}){let s=await sn(e,"mutation($input: AttachmentCreateInput!) { attachmentCreate(input: $input) { success attachment { id } } }",{input:{issueId:t.issueId,url:n,title:r,subtitle:o}});if(!s.attachmentCreate?.success)throw new Error("linear: attachmentCreate did not succeed");return s.attachmentCreate.attachment?.id??null}async function YB(e,t,n){let r=await sn(e,"mutation($input: CommentCreateInput!) { commentCreate(input: $input) { success comment { url } } }",{input:{issueId:t.issueId,body:n}});if(!r.commentCreate?.success)throw new Error("linear: commentCreate did not succeed");return r.commentCreate.comment?.url??null}async function rh(e){let t=await sn(e,"query { viewer { name email } organization { name urlKey } }");return{user:t.viewer?.name??t.viewer?.email??null,org:t.organization?.name??t.organization?.urlKey??null}}async function XB(e,{filename:t,contentType:n,buffer:r}){let o=await sn(e,`mutation($contentType: String!, $filename: String!, $size: Int!) {
561
+ `}async function As(e=Zl){try{return JSON.parse(await gr.readFile(e,"utf8"))}catch{return null}}var $B=new Set(["updating","restarting","rolling-back"]),xi=e=>!!(e&&$B.has(e.status));async function Ql({to:e,from:t=Yl,kind:n=lo(),reason:r="manual",statusFile:o=Zl,spawnImpl:s=vB,now:a=Date.now,npmPrefix:i=void 0,log:c=console}={}){if(!e)return{ok:!1,reason:"no target version"};if(!eh.has(n))return{ok:!1,reason:`install kind "${n}" updates elsewhere`};if(t&&!ki(t,e))return{ok:!1,reason:`already on ${t} (target ${e})`};let l=await As(o);if(xi(l))return{ok:!1,reason:`an update to ${l.to} is already in flight`,status:l};if(l&&l.to===e&&(l.status==="failed"||l.status==="rolled-back"))return{ok:!1,reason:`update to ${e} already ${l.status} (${l.error||"no detail"}) \u2014 retried when a newer release exists`,status:l};await gr.mkdir(Ge.dirname(o),{recursive:!0});let u=i!==void 0?i:n==="npm-global"?Ad(await OB())||Ge.resolve(Ge.dirname(process.execPath),".."):null,f=RB({kind:n,to:e,from:t,statusFile:o,npmPrefix:u,startedAt:a()}),d=Ge.join(Ge.dirname(o),`update-${e}.sh`),p=Ge.join(Ge.dirname(o),"last.log");await gr.writeFile(d,f,{mode:448}),await gr.writeFile(o,JSON.stringify({status:"updating",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a()}));let m=Sv.existsSync("/run/systemd/system")&&await CB("systemd-run")?["systemd-run",["--user","--collect","--quiet",`--unit=bostrat-self-update-${e}`,"--property=KillMode=process","bash",d]]:["setsid",["-f","bash","-c",`exec bash ${yt(d)} >> ${yt(p)} 2>&1`]];try{s(m[0],m[1],{detached:!0,stdio:"ignore"}).unref?.()}catch(h){return await gr.writeFile(o,JSON.stringify({status:"failed",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a(),error:`could not spawn updater: ${h?.message||h}`})),{ok:!1,reason:`could not spawn updater: ${h?.message||h}`}}return c.log?.(`[self-update] ${t??"?"} \u2192 ${e} (${n}, ${r}) started \u2014 status ${o}`),{ok:!0,to:e,from:t,kind:n,scriptFile:d,statusFile:o}}async function OB(){try{return await gr.realpath(new URL(import.meta.url).pathname)}catch{return""}}async function CB(e){for(let t of String(process.env.PATH||"").split(Ge.delimiter))try{return await gr.access(Ge.join(t,e),Sv.constants.X_OK),!0}catch{}return!1}var MB=45*6e4;async function Ev({statusFile:e=Zl,current:t=Yl,now:n=Date.now,staleMs:r=MB}={}){let o=await As(e);if(!o)return null;let s=a=>gr.writeFile(e,JSON.stringify(a)).catch(()=>{});if(xi(o)){if(t&&o.to===t){let a={...o,status:"done",updatedAt:n(),finishedAt:n(),announced:!0};return await s(a),a}if(n()-Number(o.updatedAt||o.startedAt||0)>r){let a={...o,status:"failed",error:`updater went silent while ${o.status} (no status change for ${Math.round(r/6e4)} min)`,updatedAt:n(),finishedAt:n(),announced:!0};return await s(a),a}return null}if(["failed","rolled-back","done"].includes(o.status)&&!o.announced){let a={...o,announced:!0};return await s(a),a}return null}function Av({isBusy:e,start:t=Ql,onStuck:n=null,onStarted:r=null,tickMs:o=_B,stuckMs:s=AB,now:a=Date.now,setIntervalImpl:i=setInterval,clearIntervalImpl:c=clearInterval,log:l=console}={}){let u=null,f=()=>{u?.timer&&c(u.timer),u=null},d=async()=>{if(!u)return;let p=!0;try{p=await e()!==!1}catch{p=!0}if(p){if(!u.stuckFired&&a()-u.since>=s){u.stuckFired=!0;try{await n?.({to:u.to,from:u.from,since:u.since})}catch{}}return}let m=u;f();let h=await t({to:m.to,from:m.from,kind:m.kind,reason:"auto"});l.log?.(`[self-update] stasis reached \u2192 ${h.ok?"started":`not started: ${h.reason}`}`);try{await r?.({...m,result:h})}catch{}};return{arm({to:p,from:m=Yl,kind:h=lo()}){return u?.to===p?!1:(f(),u={to:p,from:m,kind:h,since:a(),stuckFired:!1,timer:i(d,o)},u.timer.unref?.(),!0)},tick:d,cancel:f,get armed(){return u?{to:u.to,from:u.from,kind:u.kind,since:u.since}:null}}}ue();et();var NB=(...e)=>fetch(...e);function PB(e=process.env){return!!(ke(e)&&e.BOSTRAT_PLANE_TOKEN)}async function th(e=process.env){if(!PB(e))throw new Error("no plane configured \u2014 circuits live on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let t=new AbortController,n=setTimeout(()=>t.abort(),1e4);try{let r=await NB(`${ke(e)}/v1/circuits`,{headers:{authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN}`},signal:t.signal}),o=await r.json().catch(()=>({}));if(!r.ok)throw new Error(o?.error||`plane answered ${r.status}`);return Array.isArray(o.circuits)?o.circuits:[]}finally{clearTimeout(n)}}async function _s(e,t=process.env){let n=String(e??"").trim();if(!n)throw new Error("a circuit name or id is required");let r=await th(t),o=r.find(c=>c.id===n);if(o)return o;let s=n.toLowerCase(),a=r.filter(c=>c.name.toLowerCase()===s);if(a.length===1)return a[0];if(a.length>1)throw new Error(`"${n}" names ${a.length} circuits \u2014 use an id (bostrat-circuit ls)`);let i=r.filter(c=>c.name.toLowerCase().includes(s)).slice(0,5);throw new Error(i.length?`no circuit named "${n}" \u2014 near matches: ${i.map(c=>`${c.name} (${c.id})`).join(", ")}`:`no circuit named "${n}" \u2014 create it on the Circuits page first (bostrat-circuit ls lists yours)`)}async function eu(e,t,{source:n="chat"}={}){return _(e,{type:"track.circuit.tagged",actor:"orchestrator",source:"orchestrator",payload:t?{circuitId:t.id,circuitName:t.name??null,source:n}:{circuitId:null,source:n}})}ue();et();var DB=(...e)=>fetch(...e);async function tu(e,t,n,r=process.env){if(!(ke(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 DB(`${ke(r)}${t}`,{method:e,headers:{authorization:`Bearer ${r.BOSTRAT_PLANE_TOKEN}`,...n?{"content-type":"application/json"}:{}},body:n?JSON.stringify(n):void 0,signal:o.signal}),i=await a.json().catch(()=>({}));if(!a.ok)throw new Error(i?.error||`plane answered ${a.status}`);return i}finally{clearTimeout(s)}}function BB(e,t=process.env){return tu("POST","/v1/circuits",{name:e},t).then(n=>n.circuit)}async function _v({circuitRef:e,newCircuitName:t,name:n,markdown:r},o=process.env){let s=t?await BB(t,o):await _s(e,o),a=await tu("POST","/v1/blueprints",{circuitId:s.id,name:n,markdown:r},o);return{circuit:s,...a}}async function nh(e,t=process.env){let n=await _s(e,t),r=await tu("GET",`/v1/blueprints/${encodeURIComponent(n.id)}`,null,t);return{circuit:n,...r}}async function rh(e,t=process.env){return(await tu("GET","/v1/circuits",null,t)).memberships?.[e]??null}async function Iv(e,t,n,r=process.env){let{blueprint:o,items:s}=await nh(t,r),a=new Map(s.map(c=>[c.itemId,c])),i=n.filter(c=>!a.get(c)?.bindable);if(i.length){let c=s.filter(l=>l.bindable).map(l=>l.itemId);throw new Error(`unknown/unbindable item(s): ${i.join(", ")} \u2014 bindable ids: ${c.join(", ")||"(none)"}`)}return await _(e,{type:"blueprint.item.bound",actor:"orchestrator",source:"orchestrator",payload:{itemIds:n,blueprintId:o.id,source:"cli"}}),{blueprint:o,itemIds:n}}ue();et();var jB=(...e)=>fetch(...e);async function LB(e,t,n,r=process.env){if(!(ke(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 jB(`${ke(r)}${t}`,{method:e,headers:{authorization:`Bearer ${r.BOSTRAT_PLANE_TOKEN}`,...n?{"content-type":"application/json"}:{}},body:n?JSON.stringify(n):void 0,signal:o.signal}),i=await a.json().catch(()=>({}));if(!a.ok)throw new Error(i?.error||`plane answered ${a.status}`);return i}finally{clearTimeout(s)}}var Rv=72,oh=160;async function $v(e,{title:t,context:n="",decision:r,summary:o,alternatives:s=[],supersedesId:a=null}){let i=String(t??"").trim(),c=String(o??"").trim();if(!i)throw new Error("a title is required");if(i.length>Rv)throw new Error(`the title is the choice as a LABEL \u2014 ${Rv} chars max (yours is ${i.length}); the full story goes in the decision text`);if(!c)throw new Error(`a summary is required \u2014 one sentence (max ${oh} chars) a reader can act on without opening the record`);if(c.length>oh)throw new Error(`the summary is one sentence \u2014 ${oh} chars max (yours is ${c.length}); the full story goes in the decision text`);if(!String(r??"").trim())throw new Error("the decision itself is required (what was decided)");return await _(e,{type:"decision.recorded",actor:"orchestrator",source:"orchestrator",payload:{title:i,context:String(n??"").trim(),decision:String(r).trim(),summary:c,alternatives:(Array.isArray(s)?s:[]).map(l=>typeof l=="string"?{label:l}:l).filter(l=>l?.label),...a?{supersedesId:a}:{}}}),{title:i}}function Ov(e,t=process.env){return LB("GET",`/v1/decisions?track=${encodeURIComponent(e)}`,null,t)}zp();ue();import _i from"node:fs/promises";import uu from"node:path";import R1 from"node:os";qn();import FB from"node:fs/promises";import Cv from"node:path";import UB from"node:os";var Mv=()=>Cv.join(process.env.BOSTRAT_STATE_DIR||Cv.join(process.env.HOME||UB.tmpdir(),".bostrat"),"integrations.json");async function Dn(){try{return JSON.parse(await FB.readFile(Mv(),"utf8"))||{}}catch{return{}}}var nu=["linked","prOpened","prMerged","create"],sh=["prompt","auto","off"],HB={create:["prompt","off"]},Nv=e=>HB[e]??sh;function ru(e){let t=e.linear||{},n=t.transitions===!0?"auto":"prompt",r={};for(let o of nu){let s=Nv(o),a=s.includes(n)?n:"prompt",i=e.ticketFlow?.[o]??t.ticketFlow?.[o];r[o]=s.includes(i)?i:a}return r}async function uo(){let e=await Dn(),t=process.env.BOSTRAT_LINEAR_API_KEY||e.linear?.apiKey,n=process.env.BOSTRAT_LINEAR_DEFAULT_TEAM||e.linear?.defaultTeam||null;return t?{apiKey:t,ticketFlow:ru(e),defaultTeam:n}:null}async function ou(){let e=await Dn(),t=e.jira||{},n=process.env.BOSTRAT_JIRA_BASE_URL||t.baseUrl,r=process.env.BOSTRAT_JIRA_EMAIL||t.email,o=process.env.BOSTRAT_JIRA_API_TOKEN||t.apiToken;return!n||!r||!o?null:{baseUrl:String(n).replace(/\/$/,""),email:r,apiToken:o,tokenExpiresAt:t.tokenExpiresAt??null,ticketFlow:ru(e)}}async function ah(){return ru(await Dn())}async function Pv(e){let t=Object.entries(e||{});if(!t.length)throw new Error(`nothing to set \u2014 phases: ${nu.join(", ")}`);for(let[r,o]of t){if(!nu.includes(r))throw new Error(`unknown phase "${r}" \u2014 configurable phases: ${nu.join(", ")}`);let s=Nv(r);if(!s.includes(o))throw new Error(s.length<sh.length?`mode "${o}" not allowed for "${r}" \u2014 ${r} is always confirmed (modes: ${s.join(", ")})`:`unknown mode "${o}" \u2014 modes: ${sh.join(", ")}`)}let n=await Dn();return n.ticketFlow={...ru(n),...Object.fromEntries(t)},n.linear&&(delete n.linear.ticketFlow,delete n.linear.transitions),await at(Mv(),n,{mode:384}),n.ticketFlow}async function Si(){let e=(await Dn()).deepgram||{},t=process.env.DEEPGRAM_API_KEY||e.apiKey;return t?{apiKey:t}:null}async function WB(){let e=(await Dn()).openai||{},t=process.env.BOSTRAT_OPENAI_API_KEY||e.apiKey;return t?{apiKey:t}:null}var qB={openai:{model:"gpt-realtime-2.1-mini",voice:"marin"}};async function su(){let t=(await Dn()).voiceChat||{},n=t.provider||"openai",r=qB[n];if(!r)return null;let o=n==="openai"?await WB():null;return o?{provider:n,model:t.model||r.model,voice:t.voice||r.voice,apiKey:o.apiKey}:null}async function Dv(){let e=(await Dn()).cedar||{},t=process.env.BOSTRAT_CEDAR_INGEST_KEY||e.ingestKey,n=process.env.BOSTRAT_CEDAR_URL||e.url||"https://cedar-api.fly.dev";return t?{url:n,ingestKey:t}:null}async function fo(){let e=(await Dn()).slack||{},t=process.env.BOSTRAT_SLACK_BOT_TOKEN||e.botToken,n=process.env.BOSTRAT_SLACK_APP_TOKEN||e.appToken;return!t||!n?null:{botToken:t,appToken:n,channel:process.env.BOSTRAT_SLACK_CHANNEL||e.channel||null,maxConcurrent:Number.isInteger(e.maxConcurrent)&&e.maxConcurrent>0?e.maxConcurrent:2}}ue();Gn();Lr();ps();import Ti from"node:fs/promises";import Kv from"node:path";import h1 from"node:os";import{randomUUID as Gv}from"node:crypto";var ch={};Nu(ch,{createComment:()=>QB,findIssueUrl:()=>zB,issueStates:()=>n1,mdToAdf:()=>Lv,moveIssue:()=>r1,parseIssueRef:()=>VB,resolveIssue:()=>JB,uploadImage:()=>e1,upsertCard:()=>XB,whoami:()=>ih});var Is=e=>String(e.baseUrl||"").replace(/\/$/,""),jv=e=>`Basic ${Buffer.from(`${e.email}:${e.apiToken}`).toString("base64")}`;async function po(e,t,n,r){let o=await fetch(`${Is(e)}${n}`,{method:t,headers:{authorization:jv(e),accept:"application/json",...r!==void 0?{"content-type":"application/json"}:{}},body:r!==void 0?JSON.stringify(r):void 0}),s=await o.text(),a=null;try{a=s?JSON.parse(s):null}catch{a=null}if(!o.ok){let i=a?.errorMessages?.[0]??Object.values(a?.errors??{})[0]??`HTTP ${o.status}`,c=new Error(`jira: ${i}`);throw c.status=o.status,c}return a}var KB=/\/browse\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,GB=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function VB(e){let t=String(e||"").trim();if(/^https?:\/\//i.test(t)){let r=t.match(KB);return r?r[1].toUpperCase():null}let n=t.match(GB);return n?n[1]:null}function zB(e,t=null){let n=null;try{n=t?.baseUrl?new URL(t.baseUrl).host:null}catch{n=null}let r=/https?:\/\/[^\s)]+\/browse\/[A-Za-z][A-Za-z0-9]{0,9}-\d+[^\s)]*/g;for(let o of String(e||"").matchAll(r))try{let s=new URL(o[0]).host;if(s===n||/\.atlassian\.net$/i.test(s))return o[0]}catch{}return null}async function JB(e,t){let n;try{n=await po(e,"GET",`/rest/api/3/issue/${encodeURIComponent(t)}?fields=summary,status`)}catch(r){throw r.status===404?new Error(`jira: issue "${t}" not found`):r}return{issueId:n.id,key:n.key,title:n.fields?.summary??null,url:`${Is(e)}/browse/${n.key}`,state:n.fields?.status?.name??null}}async function XB(e,t,{url:n,title:r,subtitle:o}){await po(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/remotelink`,{globalId:n,application:{type:"com.bostrat.tracks",name:"Bostrat"},object:{url:n,title:r,summary:o,icon:{title:"Bostrat"}}})}var YB=/(!\[[^\]]*\]\([^)\s]+\)|\*\*[^*\n]+\*\*|`[^`\n]+`|_[^_\n]+_|https?:\/\/[^\s)]+)/g;function ZB(e){let t=[],n=0;for(let r of e.matchAll(YB)){r.index>n&&t.push({type:"text",text:e.slice(n,r.index)});let o=r[0];if(o.startsWith("![")){let[,s,a]=o.match(/^!\[([^\]]*)\]\(([^)\s]+)\)$/);t.push({type:"text",text:s||a,marks:[{type:"link",attrs:{href:a}}]})}else o.startsWith("**")?t.push({type:"text",text:o.slice(2,-2),marks:[{type:"strong"}]}):o.startsWith("`")?t.push({type:"text",text:o.slice(1,-1),marks:[{type:"code"}]}):o.startsWith("_")?t.push({type:"text",text:o.slice(1,-1),marks:[{type:"em"}]}):t.push({type:"text",text:o,marks:[{type:"link",attrs:{href:o}}]});n=r.index+o.length}return n<e.length&&t.push({type:"text",text:e.slice(n)}),t}function Lv(e){let t=String(e??"").split(/\n{2,}/).map(n=>n.trim()).filter(Boolean).map(n=>{let r=[];return n.split(`
562
+ `).forEach((o,s)=>{s>0&&r.push({type:"hardBreak"}),r.push(...ZB(o))}),{type:"paragraph",content:r.length?r:[{type:"text",text:" "}]}});return{type:"doc",version:1,content:t.length?t:[{type:"paragraph",content:[{type:"text",text:" "}]}]}}async function QB(e,t,n){let r=await po(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/comment`,{body:Lv(n)});return r?.id?`${Is(e)}/browse/${t.key}?focusedCommentId=${r.id}`:null}async function ih(e){let t=await po(e,"GET","/rest/api/3/myself"),n=null;try{n=new URL(Is(e)).host}catch{n=e.baseUrl??null}return{user:t?.displayName??t?.emailAddress??null,org:n}}async function e1(e,{issue:t,filename:n,contentType:r,buffer:o}){let s=new FormData;s.append("file",new Blob([o],{type:r}),n);let a=await fetch(`${Is(e)}/rest/api/3/issue/${encodeURIComponent(t)}/attachments`,{method:"POST",headers:{authorization:jv(e),"x-atlassian-token":"no-check",accept:"application/json"},body:s}),i=await a.json().catch(()=>null),c=Array.isArray(i)?i[0]:null;if(!a.ok||!c)throw new Error(`jira: attachment upload failed (HTTP ${a.status})`);return c.content??`${Is(e)}/rest/api/3/attachment/content/${c.id}`}var t1={new:"unstarted",indeterminate:"started",done:"completed"},Bv=e=>t1[e?.key]??"started";async function n1(e,t){let n=encodeURIComponent(t.key),[r,o]=await Promise.all([po(e,"GET",`/rest/api/3/issue/${n}?fields=status`),po(e,"GET",`/rest/api/3/issue/${n}/transitions`)]),s=r?.fields?.status??null,a=s?{id:`status:${s.id}`,name:s.name,type:Bv(s.statusCategory)}:null,i=(o?.transitions??[]).map((c,l)=>({id:c.id,name:c.to?.name??c.name,type:Bv(c.to?.statusCategory),position:l}));return{current:a,states:i}}async function r1(e,t,n){await po(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/transitions`,{transition:{id:String(n)}})}var fh={};Nu(fh,{createComment:()=>d1,createIssue:()=>dh,createProject:()=>uh,findIssueUrl:()=>c1,issueStates:()=>p1,moveIssue:()=>m1,parseIssueRef:()=>i1,resolveIssue:()=>l1,teams:()=>Rs,uploadImage:()=>f1,upsertCard:()=>u1,whoami:()=>lh});var o1=()=>process.env.BOSTRAT_LINEAR_API_URL||"https://api.linear.app/graphql";async function cn(e,t,n={}){let r=await fetch(o1(),{method:"POST",headers:{"content-type":"application/json",authorization:e.apiKey},body:JSON.stringify({query:t,variables:n})}),o=await r.json().catch(()=>null);if(!r.ok)throw new Error(`linear: HTTP ${r.status}${o?.errors?.[0]?.message?` \u2014 ${o.errors[0].message}`:""}`);if(o?.errors?.length){let s=o.errors[0],a=(s.extensions?.validationErrors??[]).flatMap(i=>Object.values(i?.constraints??{})).join("; ");throw new Error(`linear: ${s.message}${a?` \u2014 ${a}`:""}`)}return o?.data??{}}var s1=/linear\.app\/[^/\s]+\/issue\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,a1=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function i1(e){let t=String(e||"").trim(),n=t.match(s1);if(n)return n[1].toUpperCase();let r=t.match(a1);return r?r[1]:null}function c1(e){let t=String(e||"").match(/https?:\/\/linear\.app\/[^/\s]+\/issue\/[A-Za-z][A-Za-z0-9]{0,9}-\d+[^\s)]*/);return t?t[0]:null}async function l1(e,t){let r=(await cn(e,"query($id: String!) { issue(id: $id) { id identifier title url state { name } team { key } } }",{id:t})).issue;if(!r)throw new Error(`linear: issue "${t}" not found`);return{issueId:r.id,key:r.identifier,title:r.title,url:r.url,state:r.state?.name??null,team:r.team?.key??null}}async function u1(e,t,{url:n,title:r,subtitle:o}){let s=await cn(e,"mutation($input: AttachmentCreateInput!) { attachmentCreate(input: $input) { success attachment { id } } }",{input:{issueId:t.issueId,url:n,title:r,subtitle:o}});if(!s.attachmentCreate?.success)throw new Error("linear: attachmentCreate did not succeed");return s.attachmentCreate.attachment?.id??null}async function d1(e,t,n){let r=await cn(e,"mutation($input: CommentCreateInput!) { commentCreate(input: $input) { success comment { url } } }",{input:{issueId:t.issueId,body:n}});if(!r.commentCreate?.success)throw new Error("linear: commentCreate did not succeed");return r.commentCreate.comment?.url??null}async function lh(e){let t=await cn(e,"query { viewer { name email } organization { name urlKey } }");return{user:t.viewer?.name??t.viewer?.email??null,org:t.organization?.name??t.organization?.urlKey??null}}async function f1(e,{filename:t,contentType:n,buffer:r}){let o=await cn(e,`mutation($contentType: String!, $filename: String!, $size: Int!) {
557
563
  fileUpload(contentType: $contentType, filename: $filename, size: $size) {
558
564
  success
559
565
  uploadFile { uploadUrl assetUrl headers { key value } }
560
566
  }
561
- }`,{contentType:n,filename:t,size:r.length}),s=o.fileUpload?.uploadFile;if(!o.fileUpload?.success||!s?.uploadUrl)throw new Error("linear: fileUpload did not succeed");let a={"content-type":n};for(let c of s.headers||[])a[c.key]=c.value;let i=await fetch(s.uploadUrl,{method:"PUT",headers:a,body:r});if(!i.ok)throw new Error(`linear: asset PUT failed (HTTP ${i.status})`);return s.assetUrl}async function ZB(e,t){let n=await sn(e,"query($id: String!) { issue(id: $id) { state { id name type } team { states { nodes { id name type position } } } } }",{id:t.key});if(!n.issue)throw new Error(`linear: issue "${t.key}" not found`);return{current:n.issue.state??null,states:n.issue.team?.states?.nodes??[]}}async function QB(e,t,n){if(!(await sn(e,"mutation($id: String!, $input: IssueUpdateInput!) { issueUpdate(id: $id, input: $input) { success } }",{id:t.issueId,input:{stateId:n}})).issueUpdate?.success)throw new Error("linear: issueUpdate did not succeed")}async function Es(e){return((await sn(e,"query { teams(first: 100) { nodes { id key name } } }")).teams?.nodes??[]).map(n=>({id:n.id,key:n.key,name:n.name}))}var Cv=255;async function oh(e,{teamId:t,name:n,description:r}){let o=r||null,s=!!o&&o.length>Cv,a=s?`${o.slice(0,Cv-1).trimEnd()}\u2026`:o,i=await sn(e,"mutation($input: ProjectCreateInput!) { projectCreate(input: $input) { success project { id url name } } }",{input:{teamIds:[t],name:n,...a?{description:a}:{},...s?{content:o}:{}}}),c=i.projectCreate?.project;if(!i.projectCreate?.success||!c)throw new Error("linear: projectCreate did not succeed");return{id:c.id,url:c.url,name:c.name}}async function sh(e,{teamId:t,title:n,description:r,projectId:o,priority:s}){let a=await sn(e,"mutation($input: IssueCreateInput!) { issueCreate(input: $input) { success issue { id identifier url title } } }",{input:{teamId:t,title:n,...r?{description:r}:{},...o?{projectId:o}:{},...Number.isInteger(s)?{priority:s}:{}}}),i=a.issueCreate?.issue;if(!a.issueCreate?.success||!i)throw new Error("linear: issueCreate did not succeed");return{id:i.id,key:i.identifier,url:i.url,title:i.title}}var Lv={linear:{api:ah,config:uo},jira:{api:nh,config:eu}};async function ph(){let e=[];for(let[t,{api:n,config:r}]of Object.entries(Lv)){let o=await r();o&&e.push({name:t,api:n,cfg:o})}return e}async function mo(e){let t=Lv[e?.provider];if(!t)return null;let n=await t.config();return n?{name:e.provider,api:t.api,cfg:n}:null}function mh(e,t){if(!e||e.name)return e;let n=t.find(r=>r.id===e.id);return n?{...e,name:n.name}:e}var Fv=()=>process.env.BOSTRAT_STATE_DIR||Bv.join(process.env.HOME||e1.tmpdir(),".bostrat"),uh=()=>Bv.join(Fv(),"tickets.json"),Uv=()=>(process.env.BOSTRAT_PUBLIC_URL||"http://bostrat.globopi").replace(/\/$/,""),nu=e=>`${Uv()}/track/${e}`,br=null,ih=null,ch=Promise.resolve();async function Si(){return br||(ih??=ki.readFile(uh(),"utf8").then(e=>({tickets:JSON.parse(e)?.tickets??{},existed:!0})).catch(()=>({tickets:{},existed:!1})).then(async({tickets:e,existed:t})=>{if(br=e,!t&&Ee()){let{records:n,source:r}=await je("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;br[s]=i}Object.keys(br).length&&await dh().catch(()=>{})}}return br}).finally(()=>ih=null),ih)}async function dh(){let e=JSON.stringify({tickets:br},null,2),t=`${uh()}.${process.pid}.tmp`;await ki.mkdir(Fv(),{recursive:!0}),await ki.writeFile(t,e),await ki.rename(t,uh())}async function kr(e=null){if(ch=ch.then(dh,dh),await ch.catch(()=>{}),!e)return;let t=br?.[e];t?et("tickets",{id:e,updatedAt:Date.now(),...t},{trackId:e}).catch(()=>{}):$t("tickets",e).catch(()=>{})}async function an(e){return(await Si())[e]??null}async function Hv(){return{...await Si()}}async function Wv(){return(await ph()).length>0}async function As(e,t,{source:n="api"}={}){let r=await ph();if(!r.length)throw new Error("no ticketing integration configured \u2014 add a linear or jira entry to ~/.bostrat/integrations.json");let o=null,s=null,a=null;for(let u of r){let f=u.api.parseIssueRef(t);if(f)try{s=await u.api.resolveIssue(u.cfg,f),o=u;break}catch(d){a=d}}if(!o)throw a||new Error(`"${t}" is not a Linear or Jira issue URL or key (ABC-123)`);let i=(e.boxes||[]).find(u=>u.name===e.leadBox),c={provider:o.name,key:s.key,issueId:s.issueId,url:s.url,title:s.title,state:s.state,source:n,linkedAt:Date.now(),track:{name:e.name,branch:e.workspace?.branch??null,leadAgent:i?.agent??null,cwd:e.cwd??null,...e.workspace?.kind==="multi"?{repos:(e.workspace.repos??[]).map(u=>u?.name).filter(Boolean)}:{}},pr:null};(await Si())[e.id]=c,await kr(e.id),await _({id:e.id,cwd:e.cwd},{type:"ticket.linked",actor:"user",source:"orchestrator",payload:{ts:Date.now(),provider:c.provider,key:c.key,url:c.url,title:c.title,linkSource:n}}).catch(()=>{}),await xi(e.id,c);let l=[];return c.track.branch&&l.push(`\`${c.track.branch}\``),c.track.repos?.length&&l.push(`repos ${c.track.repos.join(" + ")}`),c.track.leadAgent&&l.push(`lead ${c.track.leadAgent}`),await bi(c,`**Bostrat** \u2014 Track **${c.track.name}** linked${l.length?` (${l.join(", ")})`:""}.`),await Gv(e.id,c,"linked"),c}async function hh(e){let t=await Si();return t[e]?(delete t[e],await kr(e),!0):!1}var fh=e=>`$${e>=100?Math.round(e):e.toFixed(2)}`;async function qv(e,t){if(!e.track?.cwd)return null;let n=nr(await L({id:t,cwd:e.track.cwd}));return!n.totalUsd||n.totalUsd<.01?null:n}function t1(e){let t=Object.entries(e.byProvider).sort((r,o)=>o[1].usd-r[1].usd).map(([r,o])=>`${r} ${fh(o.usd)}`).join(" \xB7 "),n=Object.keys(e.byBox).length;return`${fh(e.totalUsd)}${t?` (${t})`:""}${n>1?` across ${n} boxes`:""}`}function n1(e,t){let n=[];return e.track.leadAgent&&n.push(`lead ${e.track.leadAgent}`),e.track.branch&&n.push(e.track.branch),e.track.repos?.length&&n.push(e.track.repos.join(" + ")),e.pr?.number&&n.push(`PR #${e.pr.number} ${e.pr.change==="merged"?"merged":"open"}`),t&&n.push(fh(t.totalUsd)),n.join(" \xB7 ")||"linked"}async function xi(e,t){let n=await mo(t);if(!n)return;let r=await qv(t,e).catch(()=>null);await n.api.upsertCard(n.cfg,t,{url:nu(e),title:`Bostrat Track: ${t.track.name}`,subtitle:n1(t,r)})}function ru(e){let t=new URL(Uv());return`${t.protocol}//${e}.${t.host}/`}var r1={linked:"linked",opened:"prOpened",merged:"prMerged"};function o1(e,t,n){let r=o=>t.filter(s=>s.type===o).sort((s,a)=>s.position-a.position);if(n==="linked"){if(["triage","backlog","unstarted"].includes(e?.type))return r("started")[0]??null}else if(n==="opened"){if(e?.type!=="completed")return r("started").find(o=>/review/i.test(o.name))??null}else if(n==="merged"&&e?.type!=="completed")return r("completed")[0]??null;return null}async function Kv(e,t,{from:n,to:r,mode:o,phase:s=null,actor:a="user"}){t.state=r,await kr(e),await _({id:e,cwd:t.track?.cwd},{type:"ticket.state.changed",actor:a,source:"orchestrator",payload:{ts:Date.now(),key:t.key,url:t.url,from:n??null,to:r,mode:o,...s?{phase:s}:{}}}).catch(()=>{})}async function Gv(e,t,n){let r=await mo(t);if(!r)return;let o=r.cfg.ticketFlow?.[r1[n]]??"prompt";if(o==="off")return;let{current:s,states:a}=await r.api.issueStates(r.cfg,t),i=mh(s,a),c=o1(i,a,n);if(!c||c.id===i?.id)return;let l=i?.name??t.state??null;if(o==="auto"){await r.api.moveIssue(r.cfg,t,c.id),await Kv(e,t,{from:l,to:c.name,mode:"auto",phase:n,actor:"system"});return}await _({id:e,cwd:t.track?.cwd},{type:"ticket.move.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),offerId:jv(),provider:t.provider,key:t.key,url:t.url,phase:n,from:l,to:{id:c.id,name:c.name,type:c.type},...t.pr?.number?{prNumber:t.pr.number}:{}}}).catch(()=>{})}async function Vv(e){let t=await an(e);if(!t)throw new Error("no ticket linked to this Track");let n=await mo(t);if(!n)throw new Error("no ticketing integration configured");let{current:r,states:o}=await n.api.issueStates(n.cfg,t),s=mh(r,o);return s?.name&&t.state!==s.name&&(t.state=s.name,await kr(e)),{key:t.key,url:t.url,current:s?{id:s.id,name:s.name??null,type:s.type??null}:null,states:[...o].sort((a,i)=>a.position-i.position).map(({id:a,name:i,type:c,position:l})=>({id:a,name:i,type:c,position:l}))}}async function wh(e,t,{mode:n="manual"}={}){if(!t)throw new Error("stateId required");let r=await an(e);if(!r)throw new Error("no ticket linked to this Track");let o=await mo(r);if(!o)throw new Error("no ticketing integration configured");let{current:s,states:a}=await o.api.issueStates(o.cfg,r),i=mh(s,a),c=a.find(u=>u.id===t);if(!c)throw new Error("unknown state for this ticket's team");let l=i?.name??r.state??null;return i?.id===c.id?(r.state!==c.name&&(r.state=c.name,await kr(e)),{key:r.key,from:l,to:c.name,moved:!1}):(await o.api.moveIssue(o.cfg,r,c.id),await Kv(e,r,{from:l,to:c.name,mode:n}),{key:r.key,from:l,to:c.name,moved:!0})}async function zv(e,t){let n=await an(e);if(!n)throw new Error("no ticket linked to this Track");let r=await mo(n);if(!r)throw new Error("no ticketing integration configured");let o=String(t||"").trim();if(!o)throw new Error("comment body required");let s=await r.api.createComment(r.cfg,n,o);return await _({id:e,cwd:n.track?.cwd},{type:"ticket.commented",actor:"user",source:"orchestrator",payload:{ts:Date.now(),key:n.key,url:s??n.url,excerpt:o.length>280?`${o.slice(0,279)}\u2026`:o}}).catch(()=>{}),{key:n.key,url:s??n.url}}async function Jv(e,t,n){if(!t)throw new Error("offerId required");let r=await L({id:e.id,cwd:e.cwd}),o=r.find(a=>a.type==="ticket.move.offered"&&a.payload?.offerId===t);if(!o)throw new Error("unknown offer");if(r.some(a=>a.type==="ticket.move.answered"&&a.payload?.offerId===t))throw new Error("offer already answered");let s=null;return n&&(s=await wh(e.id,o.payload.to?.id,{mode:"offer"})),await _({id:e.id,cwd:e.cwd},{type:"ticket.move.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,action:n?"moved":"dismiss",...s?{from:s.from,to:s.to}:{}}}),{offerId:t,action:n?"moved":"dismiss",...s??{}}}var Mv=50;async function Yv(){let e=await uo();if(!e)throw new Error("no ticketing integration configured");return Es(e)}function s1(e){let t=e&&typeof e=="object"?e:{},n=(Array.isArray(t.issues)?t.issues:[]).map(o=>o&&typeof o=="object"?o:{title:String(o||"")}).map(o=>({title:String(o.title||"").trim(),description:o.description?String(o.description):null,priority:Number.isInteger(o.priority)&&o.priority>=0&&o.priority<=4?o.priority:null})).filter(o=>o.title),r=t.epic&&String(t.epic.name||"").trim()?{name:String(t.epic.name).trim(),description:t.epic.description?String(t.epic.description):null}:null;if(!n.length&&!r)throw new Error("a plan needs an epic or at least one issue");if(n.length>Mv)throw new Error(`too many issues (${n.length}); cap is ${Mv} per proposal`);return{epic:r,issues:n,team:t.team?String(t.team).trim():null,linkCurrentTrack:t.linkCurrentTrack===!0}}async function a1(e,t,n,r){let o=r??await Es(e),s=i=>o.find(c=>c.id===i||c.key.toLowerCase()===String(i).toLowerCase()||c.name.toLowerCase()===String(i).toLowerCase())??null;if(t.team){let i=s(t.team);if(i)return i}let a=await an(n.id);if(a?.key){let i=a.key.split("-")[0],c=o.find(l=>l.key===i);if(c)return c}if(e.defaultTeam){let i=s(e.defaultTeam);if(i)return i}return o.length===1?o[0]:null}async function Xv(e,t){let n=await uo();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=s1(t),o=await Es(n),s=await a1(n,r,e,o),a=s?{id:s.id,key:s.key,name:s.name}:null,i=jv();return await _({id:e.id,cwd:e.cwd},{type:"ticket.create.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),proposalId:i,provider:"linear",epic:r.epic,issues:r.issues,team:a,needsTeam:!s,linkCurrentTrack:r.linkCurrentTrack}}),{proposalId:i,epic:r.epic,issues:r.issues,team:a,needsTeam:!s}}async function Zv(e,t,n,{teamId:r=null}={}){if(!t)throw new Error("proposalId required");let o=await L({id:e.id,cwd:e.cwd}),s=o.find(m=>m.type==="ticket.create.offered"&&m.payload?.proposalId===t);if(!s)throw new Error("unknown proposal");if(o.some(m=>m.type==="ticket.create.answered"&&m.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await _({id:e.id,cwd:e.cwd},{type:"ticket.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"dismiss"}}),{proposalId:t,action:"dismiss"};let a=await uo();if(!a)throw new Error("no ticketing integration configured");let i=s.payload,c=i.team??null;if(!c&&r){let m=(await Es(a)).find(h=>h.id===r);if(!m)throw new Error("unknown team");c={id:m.id,key:m.key,name:m.name}}if(!c)throw new Error("a team is required to create \u2014 pick one");let l=[],u=[],f=null;if(i.epic){let m=await oh(a,{teamId:c.id,name:i.epic.name,description:i.epic.description});f=m.id,l.push({kind:"epic",title:m.name,url:m.url})}for(let m of i.issues||[])try{let h=await sh(a,{teamId:c.id,title:m.title,description:m.description,projectId:f,priority:m.priority});l.push({kind:"issue",key:h.key,title:h.title,url:h.url})}catch(h){u.push({title:m.title,message:h?.message||String(h)})}await _({id:e.id,cwd:e.cwd},{type:"ticket.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,team:{key:c.key,name:c.name},items:l,failed:u}}),await _({id:e.id,cwd:e.cwd},{type:"ticket.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",createdCount:l.length,failedCount:u.length}});let d=l.filter(m=>m.kind==="issue"),p=null;return i.linkCurrentTrack&&d.length===1&&!await an(e.id)&&(p=await As(e,d[0].key,{source:"created"}).catch(()=>null)),{proposalId:t,action:"created",created:l,failed:u,linked:p?p.key:null}}async function bi(e,t){let n=await mo(e);n&&await n.api.createComment(n.cfg,e,t)}async function i1(e,t,n){let r=await mo(e);if(!r)return null;let o=await En(t);if(!o)return null;let s=Bt(o,n);if(!s)return null;let a=await ki.readFile(Et(o,s.v).png).catch(()=>null);return a?r.api.uploadImage(r.cfg,{issue:e.key,filename:`${o.name.replace(/[^\w.-]+/g,"-")}.v${s.v}.png`,contentType:"image/png",buffer:a}):null}var Nv=()=>Number(process.env.BOSTRAT_TICKET_COST_SYNC_MS??12e4),lh=new Map;function c1(e,t){if(Nv()<=0)return xi(e,t);if(lh.has(e))return;let n=setTimeout(()=>{lh.delete(e),an(e).then(r=>r?xi(e,r):null).catch(()=>{})},Nv());n.unref?.(),lh.set(e,n)}var Pv=new Map;async function Dv(e,t,n){let r=Pv.get(e)??0;Date.now()-r<600*1e3||(Pv.set(e,Date.now()),await _({id:e,cwd:t},{type:"ticket.sync.failed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),message:n?.message||String(n)}}).catch(()=>{}))}async function l1(e,{resolveTrack:t=null}={}){let n=await an(e.trackId),r=e.payload||{};if(!n){if(e.type!=="turn.user"||e.actor!=="user")return;let o=null;for(let a of await ph())if(o=a.api.findIssueUrl(r.text,a.cfg),o)break;if(!o)return;let s=t?await t(e.trackId):null;if(!s)return;try{await As(s,o,{source:"chat"})}catch(a){await Dv(e.trackId,s.cwd,a)}return}if(!n.track.cwd&&t){let o=await t(e.trackId).catch(()=>null);o?.cwd&&(n.track.cwd=o.cwd,await kr(e.trackId))}try{switch(e.type){case"handoff.done":n.track.leadAgent=r.toAgent??n.track.leadAgent,await kr(e.trackId),await xi(e.trackId,n);break;case"pr.state.changed":{if(!r.change)break;if(r.number&&(n.pr={number:r.number,url:r.url??n.pr?.url??null,change:r.change}),await kr(e.trackId),await xi(e.trackId,n),r.change==="opened"||r.change==="merged"){let o=r.change==="merged"?await qv(n,e.trackId).catch(()=>null):null;await bi(n,`**Bostrat** \u2014 PR ${r.change} for **${n.track.name}**${r.url?`: ${r.url}`:r.number?` (#${r.number})`:""}`+(o?`
567
+ }`,{contentType:n,filename:t,size:r.length}),s=o.fileUpload?.uploadFile;if(!o.fileUpload?.success||!s?.uploadUrl)throw new Error("linear: fileUpload did not succeed");let a={"content-type":n};for(let c of s.headers||[])a[c.key]=c.value;let i=await fetch(s.uploadUrl,{method:"PUT",headers:a,body:r});if(!i.ok)throw new Error(`linear: asset PUT failed (HTTP ${i.status})`);return s.assetUrl}async function p1(e,t){let n=await cn(e,"query($id: String!) { issue(id: $id) { state { id name type } team { states { nodes { id name type position } } } } }",{id:t.key});if(!n.issue)throw new Error(`linear: issue "${t.key}" not found`);return{current:n.issue.state??null,states:n.issue.team?.states?.nodes??[]}}async function m1(e,t,n){if(!(await cn(e,"mutation($id: String!, $input: IssueUpdateInput!) { issueUpdate(id: $id, input: $input) { success } }",{id:t.issueId,input:{stateId:n}})).issueUpdate?.success)throw new Error("linear: issueUpdate did not succeed")}async function Rs(e){return((await cn(e,"query { teams(first: 100) { nodes { id key name } } }")).teams?.nodes??[]).map(n=>({id:n.id,key:n.key,name:n.name}))}var Fv=255;async function uh(e,{teamId:t,name:n,description:r}){let o=r||null,s=!!o&&o.length>Fv,a=s?`${o.slice(0,Fv-1).trimEnd()}\u2026`:o,i=await cn(e,"mutation($input: ProjectCreateInput!) { projectCreate(input: $input) { success project { id url name } } }",{input:{teamIds:[t],name:n,...a?{description:a}:{},...s?{content:o}:{}}}),c=i.projectCreate?.project;if(!i.projectCreate?.success||!c)throw new Error("linear: projectCreate did not succeed");return{id:c.id,url:c.url,name:c.name}}async function dh(e,{teamId:t,title:n,description:r,projectId:o,priority:s}){let a=await cn(e,"mutation($input: IssueCreateInput!) { issueCreate(input: $input) { success issue { id identifier url title } } }",{input:{teamId:t,title:n,...r?{description:r}:{},...o?{projectId:o}:{},...Number.isInteger(s)?{priority:s}:{}}}),i=a.issueCreate?.issue;if(!a.issueCreate?.success||!i)throw new Error("linear: issueCreate did not succeed");return{id:i.id,key:i.identifier,url:i.url,title:i.title}}var Vv={linear:{api:fh,config:uo},jira:{api:ch,config:ou}};async function bh(){let e=[];for(let[t,{api:n,config:r}]of Object.entries(Vv)){let o=await r();o&&e.push({name:t,api:n,cfg:o})}return e}async function mo(e){let t=Vv[e?.provider];if(!t)return null;let n=await t.config();return n?{name:e.provider,api:t.api,cfg:n}:null}function kh(e,t){if(!e||e.name)return e;let n=t.find(r=>r.id===e.id);return n?{...e,name:n.name}:e}var zv=()=>process.env.BOSTRAT_STATE_DIR||Kv.join(process.env.HOME||h1.tmpdir(),".bostrat"),wh=()=>Kv.join(zv(),"tickets.json"),Jv=()=>(process.env.BOSTRAT_PUBLIC_URL||"http://bostrat.globopi").replace(/\/$/,""),au=e=>`${Jv()}/track/${e}`,yr=null,ph=null,mh=Promise.resolve();async function Ai(){return yr||(ph??=Ti.readFile(wh(),"utf8").then(e=>({tickets:JSON.parse(e)?.tickets??{},existed:!0})).catch(()=>({tickets:{},existed:!1})).then(async({tickets:e,existed:t})=>{if(yr=e,!t&&Ae()){let{records:n,source:r}=await Fe("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;yr[s]=i}Object.keys(yr).length&&await gh().catch(()=>{})}}return yr}).finally(()=>ph=null),ph)}async function gh(){let e=JSON.stringify({tickets:yr},null,2),t=`${wh()}.${process.pid}.tmp`;await Ti.mkdir(zv(),{recursive:!0}),await Ti.writeFile(t,e),await Ti.rename(t,wh())}async function br(e=null){if(mh=mh.then(gh,gh),await mh.catch(()=>{}),!e)return;let t=yr?.[e];t?tt("tickets",{id:e,updatedAt:Date.now(),...t},{trackId:e}).catch(()=>{}):$t("tickets",e).catch(()=>{})}async function ln(e){return(await Ai())[e]??null}async function Xv(){return{...await Ai()}}async function Yv(){return(await bh()).length>0}async function $s(e,t,{source:n="api"}={}){let r=await bh();if(!r.length)throw new Error("no ticketing integration configured \u2014 add a linear or jira entry to ~/.bostrat/integrations.json");let o=null,s=null,a=null;for(let u of r){let f=u.api.parseIssueRef(t);if(f)try{s=await u.api.resolveIssue(u.cfg,f),o=u;break}catch(d){a=d}}if(!o)throw a||new Error(`"${t}" is not a Linear or Jira issue URL or key (ABC-123)`);let i=(e.boxes||[]).find(u=>u.name===e.leadBox),c={provider:o.name,key:s.key,issueId:s.issueId,url:s.url,title:s.title,state:s.state,source:n,linkedAt:Date.now(),track:{name:e.name,branch:e.workspace?.branch??null,leadAgent:i?.agent??null,cwd:e.cwd??null,...e.workspace?.kind==="multi"?{repos:(e.workspace.repos??[]).map(u=>u?.name).filter(Boolean)}:{}},pr:null};(await Ai())[e.id]=c,await br(e.id),await _({id:e.id,cwd:e.cwd},{type:"ticket.linked",actor:"user",source:"orchestrator",payload:{ts:Date.now(),provider:c.provider,key:c.key,url:c.url,title:c.title,linkSource:n}}).catch(()=>{}),await Ei(e.id,c);let l=[];return c.track.branch&&l.push(`\`${c.track.branch}\``),c.track.repos?.length&&l.push(`repos ${c.track.repos.join(" + ")}`),c.track.leadAgent&&l.push(`lead ${c.track.leadAgent}`),await vi(c,`**Bostrat** \u2014 Track **${c.track.name}** linked${l.length?` (${l.join(", ")})`:""}.`),await eT(e.id,c,"linked"),c}async function xh(e){let t=await Ai();return t[e]?(delete t[e],await br(e),!0):!1}var yh=e=>`$${e>=100?Math.round(e):e.toFixed(2)}`;async function Zv(e,t){if(!e.track?.cwd)return null;let n=nr(await L({id:t,cwd:e.track.cwd}));return!n.totalUsd||n.totalUsd<.01?null:n}function w1(e){let t=Object.entries(e.byProvider).sort((r,o)=>o[1].usd-r[1].usd).map(([r,o])=>`${r} ${yh(o.usd)}`).join(" \xB7 "),n=Object.keys(e.byBox).length;return`${yh(e.totalUsd)}${t?` (${t})`:""}${n>1?` across ${n} boxes`:""}`}function g1(e,t){let n=[];return e.track.leadAgent&&n.push(`lead ${e.track.leadAgent}`),e.track.branch&&n.push(e.track.branch),e.track.repos?.length&&n.push(e.track.repos.join(" + ")),e.pr?.number&&n.push(`PR #${e.pr.number} ${e.pr.change==="merged"?"merged":"open"}`),t&&n.push(yh(t.totalUsd)),n.join(" \xB7 ")||"linked"}async function Ei(e,t){let n=await mo(t);if(!n)return;let r=await Zv(t,e).catch(()=>null);await n.api.upsertCard(n.cfg,t,{url:au(e),title:`Bostrat Track: ${t.track.name}`,subtitle:g1(t,r)})}function iu(e){let t=new URL(Jv());return`${t.protocol}//${e}.${t.host}/`}var y1={linked:"linked",opened:"prOpened",merged:"prMerged"};function b1(e,t,n){let r=o=>t.filter(s=>s.type===o).sort((s,a)=>s.position-a.position);if(n==="linked"){if(["triage","backlog","unstarted"].includes(e?.type))return r("started")[0]??null}else if(n==="opened"){if(e?.type!=="completed")return r("started").find(o=>/review/i.test(o.name))??null}else if(n==="merged"&&e?.type!=="completed")return r("completed")[0]??null;return null}async function Qv(e,t,{from:n,to:r,mode:o,phase:s=null,actor:a="user"}){t.state=r,await br(e),await _({id:e,cwd:t.track?.cwd},{type:"ticket.state.changed",actor:a,source:"orchestrator",payload:{ts:Date.now(),key:t.key,url:t.url,from:n??null,to:r,mode:o,...s?{phase:s}:{}}}).catch(()=>{})}async function eT(e,t,n){let r=await mo(t);if(!r)return;let o=r.cfg.ticketFlow?.[y1[n]]??"prompt";if(o==="off")return;let{current:s,states:a}=await r.api.issueStates(r.cfg,t),i=kh(s,a),c=b1(i,a,n);if(!c||c.id===i?.id)return;let l=i?.name??t.state??null;if(o==="auto"){await r.api.moveIssue(r.cfg,t,c.id),await Qv(e,t,{from:l,to:c.name,mode:"auto",phase:n,actor:"system"});return}await _({id:e,cwd:t.track?.cwd},{type:"ticket.move.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),offerId:Gv(),provider:t.provider,key:t.key,url:t.url,phase:n,from:l,to:{id:c.id,name:c.name,type:c.type},...t.pr?.number?{prNumber:t.pr.number}:{}}}).catch(()=>{})}async function tT(e){let t=await ln(e);if(!t)throw new Error("no ticket linked to this Track");let n=await mo(t);if(!n)throw new Error("no ticketing integration configured");let{current:r,states:o}=await n.api.issueStates(n.cfg,t),s=kh(r,o);return s?.name&&t.state!==s.name&&(t.state=s.name,await br(e)),{key:t.key,url:t.url,current:s?{id:s.id,name:s.name??null,type:s.type??null}:null,states:[...o].sort((a,i)=>a.position-i.position).map(({id:a,name:i,type:c,position:l})=>({id:a,name:i,type:c,position:l}))}}async function Sh(e,t,{mode:n="manual"}={}){if(!t)throw new Error("stateId required");let r=await ln(e);if(!r)throw new Error("no ticket linked to this Track");let o=await mo(r);if(!o)throw new Error("no ticketing integration configured");let{current:s,states:a}=await o.api.issueStates(o.cfg,r),i=kh(s,a),c=a.find(u=>u.id===t);if(!c)throw new Error("unknown state for this ticket's team");let l=i?.name??r.state??null;return i?.id===c.id?(r.state!==c.name&&(r.state=c.name,await br(e)),{key:r.key,from:l,to:c.name,moved:!1}):(await o.api.moveIssue(o.cfg,r,c.id),await Qv(e,r,{from:l,to:c.name,mode:n}),{key:r.key,from:l,to:c.name,moved:!0})}async function nT(e,t){let n=await ln(e);if(!n)throw new Error("no ticket linked to this Track");let r=await mo(n);if(!r)throw new Error("no ticketing integration configured");let o=String(t||"").trim();if(!o)throw new Error("comment body required");let s=await r.api.createComment(r.cfg,n,o);return await _({id:e,cwd:n.track?.cwd},{type:"ticket.commented",actor:"user",source:"orchestrator",payload:{ts:Date.now(),key:n.key,url:s??n.url,excerpt:o.length>280?`${o.slice(0,279)}\u2026`:o}}).catch(()=>{}),{key:n.key,url:s??n.url}}async function rT(e,t,n){if(!t)throw new Error("offerId required");let r=await L({id:e.id,cwd:e.cwd}),o=r.find(a=>a.type==="ticket.move.offered"&&a.payload?.offerId===t);if(!o)throw new Error("unknown offer");if(r.some(a=>a.type==="ticket.move.answered"&&a.payload?.offerId===t))throw new Error("offer already answered");let s=null;return n&&(s=await Sh(e.id,o.payload.to?.id,{mode:"offer"})),await _({id:e.id,cwd:e.cwd},{type:"ticket.move.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,action:n?"moved":"dismiss",...s?{from:s.from,to:s.to}:{}}}),{offerId:t,action:n?"moved":"dismiss",...s??{}}}var Uv=50;async function oT(){let e=await uo();if(!e)throw new Error("no ticketing integration configured");return Rs(e)}function k1(e){let t=e&&typeof e=="object"?e:{},n=(Array.isArray(t.issues)?t.issues:[]).map(o=>o&&typeof o=="object"?o:{title:String(o||"")}).map(o=>({title:String(o.title||"").trim(),description:o.description?String(o.description):null,priority:Number.isInteger(o.priority)&&o.priority>=0&&o.priority<=4?o.priority:null})).filter(o=>o.title),r=t.epic&&String(t.epic.name||"").trim()?{name:String(t.epic.name).trim(),description:t.epic.description?String(t.epic.description):null}:null;if(!n.length&&!r)throw new Error("a plan needs an epic or at least one issue");if(n.length>Uv)throw new Error(`too many issues (${n.length}); cap is ${Uv} per proposal`);return{epic:r,issues:n,team:t.team?String(t.team).trim():null,linkCurrentTrack:t.linkCurrentTrack===!0}}async function x1(e,t,n,r){let o=r??await Rs(e),s=i=>o.find(c=>c.id===i||c.key.toLowerCase()===String(i).toLowerCase()||c.name.toLowerCase()===String(i).toLowerCase())??null;if(t.team){let i=s(t.team);if(i)return i}let a=await ln(n.id);if(a?.key){let i=a.key.split("-")[0],c=o.find(l=>l.key===i);if(c)return c}if(e.defaultTeam){let i=s(e.defaultTeam);if(i)return i}return o.length===1?o[0]:null}async function sT(e,t){let n=await uo();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=k1(t),o=await Rs(n),s=await x1(n,r,e,o),a=s?{id:s.id,key:s.key,name:s.name}:null,i=Gv();return await _({id:e.id,cwd:e.cwd},{type:"ticket.create.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),proposalId:i,provider:"linear",epic:r.epic,issues:r.issues,team:a,needsTeam:!s,linkCurrentTrack:r.linkCurrentTrack}}),{proposalId:i,epic:r.epic,issues:r.issues,team:a,needsTeam:!s}}async function aT(e,t,n,{teamId:r=null}={}){if(!t)throw new Error("proposalId required");let o=await L({id:e.id,cwd:e.cwd}),s=o.find(m=>m.type==="ticket.create.offered"&&m.payload?.proposalId===t);if(!s)throw new Error("unknown proposal");if(o.some(m=>m.type==="ticket.create.answered"&&m.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await _({id:e.id,cwd:e.cwd},{type:"ticket.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"dismiss"}}),{proposalId:t,action:"dismiss"};let a=await uo();if(!a)throw new Error("no ticketing integration configured");let i=s.payload,c=i.team??null;if(!c&&r){let m=(await Rs(a)).find(h=>h.id===r);if(!m)throw new Error("unknown team");c={id:m.id,key:m.key,name:m.name}}if(!c)throw new Error("a team is required to create \u2014 pick one");let l=[],u=[],f=null;if(i.epic){let m=await uh(a,{teamId:c.id,name:i.epic.name,description:i.epic.description});f=m.id,l.push({kind:"epic",title:m.name,url:m.url})}for(let m of i.issues||[])try{let h=await dh(a,{teamId:c.id,title:m.title,description:m.description,projectId:f,priority:m.priority});l.push({kind:"issue",key:h.key,title:h.title,url:h.url})}catch(h){u.push({title:m.title,message:h?.message||String(h)})}await _({id:e.id,cwd:e.cwd},{type:"ticket.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,team:{key:c.key,name:c.name},items:l,failed:u}}),await _({id:e.id,cwd:e.cwd},{type:"ticket.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",createdCount:l.length,failedCount:u.length}});let d=l.filter(m=>m.kind==="issue"),p=null;return i.linkCurrentTrack&&d.length===1&&!await ln(e.id)&&(p=await $s(e,d[0].key,{source:"created"}).catch(()=>null)),{proposalId:t,action:"created",created:l,failed:u,linked:p?p.key:null}}async function vi(e,t){let n=await mo(e);n&&await n.api.createComment(n.cfg,e,t)}async function S1(e,t,n){let r=await mo(e);if(!r)return null;let o=await An(t);if(!o)return null;let s=Bt(o,n);if(!s)return null;let a=await Ti.readFile(Et(o,s.v).png).catch(()=>null);return a?r.api.uploadImage(r.cfg,{issue:e.key,filename:`${o.name.replace(/[^\w.-]+/g,"-")}.v${s.v}.png`,contentType:"image/png",buffer:a}):null}var Hv=()=>Number(process.env.BOSTRAT_TICKET_COST_SYNC_MS??12e4),hh=new Map;function v1(e,t){if(Hv()<=0)return Ei(e,t);if(hh.has(e))return;let n=setTimeout(()=>{hh.delete(e),ln(e).then(r=>r?Ei(e,r):null).catch(()=>{})},Hv());n.unref?.(),hh.set(e,n)}var Wv=new Map;async function qv(e,t,n){let r=Wv.get(e)??0;Date.now()-r<600*1e3||(Wv.set(e,Date.now()),await _({id:e,cwd:t},{type:"ticket.sync.failed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),message:n?.message||String(n)}}).catch(()=>{}))}async function T1(e,{resolveTrack:t=null}={}){let n=await ln(e.trackId),r=e.payload||{};if(!n){if(e.type!=="turn.user"||e.actor!=="user")return;let o=null;for(let a of await bh())if(o=a.api.findIssueUrl(r.text,a.cfg),o)break;if(!o)return;let s=t?await t(e.trackId):null;if(!s)return;try{await $s(s,o,{source:"chat"})}catch(a){await qv(e.trackId,s.cwd,a)}return}if(!n.track.cwd&&t){let o=await t(e.trackId).catch(()=>null);o?.cwd&&(n.track.cwd=o.cwd,await br(e.trackId))}try{switch(e.type){case"handoff.done":n.track.leadAgent=r.toAgent??n.track.leadAgent,await br(e.trackId),await Ei(e.trackId,n);break;case"pr.state.changed":{if(!r.change)break;if(r.number&&(n.pr={number:r.number,url:r.url??n.pr?.url??null,change:r.change}),await br(e.trackId),await Ei(e.trackId,n),r.change==="opened"||r.change==="merged"){let o=r.change==="merged"?await Zv(n,e.trackId).catch(()=>null):null;await vi(n,`**Bostrat** \u2014 PR ${r.change} for **${n.track.name}**${r.url?`: ${r.url}`:r.number?` (#${r.number})`:""}`+(o?`
562
568
 
563
- Agent cost for this Track: ${t1(o)}.`:"")),await Gv(e.trackId,n,r.change)}break}case"mock.state.changed":{if(r.change==="ready"&&r.mockId){let o=await i1(n,r.mockId,r.version??null);if(!o)break;let s=(r.version??1)>1?` revised (v${r.version})`:"";await bi(n,`**Bostrat** \u2014 mock **${r.name}**${s}${r.group?` (group \`${r.group}\`)`:""}:
569
+ Agent cost for this Track: ${w1(o)}.`:"")),await eT(e.trackId,n,r.change)}break}case"mock.state.changed":{if(r.change==="ready"&&r.mockId){let o=await S1(n,r.mockId,r.version??null);if(!o)break;let s=(r.version??1)>1?` revised (v${r.version})`:"";await vi(n,`**Bostrat** \u2014 mock **${r.name}**${s}${r.group?` (group \`${r.group}\`)`:""}:
564
570
 
565
- ![${r.name}](${o})`)}else if(r.change==="picked"){let o=(r.siblings??[]).map(s=>`**${s.name}**`).join(", ");await bi(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 bi(n,`**Bostrat** \u2014 live preview **${r.name}**: ${ru(r.slug)}
566
- _(runs on the Track's branch; reachable on the operator's private network only)_`);break}case"cost.recorded":await c1(e.trackId,n);break;default:break}}catch(o){let s=t?await t(e.trackId).catch(()=>null):null;await Dv(e.trackId,s?.cwd??null,o)}}function Qv({resolveTrack:e}){st.on("event",t=>{l1(t,{resolveTrack:e}).catch(()=>{})})}async function eT(){if(!Ee())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await je("tickets");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Si(),r=0;for(let[o,s]of Object.entries(n))await et("tickets",{id:o,updatedAt:Date.now(),...s},{trackId:o}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}Yo();us();import u1 from"ws";var tT=()=>process.env.BOSTRAT_SLACK_API_BASE||"https://slack.com/api";async function ou(e,t,n={}){let r=await fetch(`${tT()}/${e}`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/json; charset=utf-8"},body:JSON.stringify(n)}),o=await r.json().catch(()=>null);if(!o?.ok)throw new Error(`slack ${e}: ${o?.error||`http ${r.status}`}`);return o}var gh=(e,t)=>ou("chat.postMessage",e,t),ho=(e,t)=>ou("chat.update",e,t);async function rt(e,t){await fetch(e,{method:"POST",headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify(t)}).catch(()=>{})}async function d1(e,t,n={}){let r=await fetch(`${tT()}/${e}`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/x-www-form-urlencoded; charset=utf-8"},body:new URLSearchParams(n).toString()}),o=await r.json().catch(()=>null);if(!o?.ok)throw new Error(`slack ${e}: ${o?.error||`http ${r.status}`}`);return o}async function nT(e,{filename:t,buffer:n,title:r,channelId:o,threadTs:s,initialComment:a}){let{upload_url:i,file_id:c}=await d1("files.getUploadURLExternal",e,{filename:t,length:String(n.length)}),l=await fetch(i,{method:"POST",body:n});if(!l.ok)throw new Error(`slack upload: http ${l.status}`);return ou("files.completeUploadExternal",e,{files:[{id:c,title:r}],channel_id:o,thread_ts:s,...a?{initial_comment:a}:{}})}var f1=2200;function rT({getToken:e,onEnvelope:t,log:n=()=>{}}){let r=!1,o=null,s=null,a=1e3;async function i(){if(r)return;let l;try{let u=await e();if(!u)throw new Error("app token missing");({url:l}=await ou("apps.connections.open",u))}catch(u){return n(`connections.open failed: ${u?.message||u}`),c()}o=new u1(l),o.on("message",u=>{let f;try{f=JSON.parse(u)}catch{return}if(f.type==="hello"){a=1e3,n("socket connected");return}if(f.type==="disconnect"){try{o.close()}catch{}return}if(!f.envelope_id)return;let d=h=>{try{o.send(JSON.stringify(h?{envelope_id:f.envelope_id,payload:h}:{envelope_id:f.envelope_id}))}catch{}},p=!1,m=setTimeout(()=>{p=!0,d()},f1);Promise.resolve().then(()=>t(f)).then(h=>{clearTimeout(m),!p&&(p=!0,d(f.accepts_response_payload?h:void 0))},h=>{clearTimeout(m),p||(p=!0,d()),n(`envelope handler failed: ${h?.message||h}`)})}),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 aT=()=>process.env.BOSTRAT_STATE_DIR||au.join(process.env.HOME||m1.tmpdir(),".bostrat"),Sh=()=>au.join(aT(),"slack.json"),su=null,yh=null,bh=Promise.resolve();async function Th(){return su||(yh??=vi.readFile(Sh(),"utf8").then(e=>JSON.parse(e)?.threads??{}).catch(()=>({})).then(e=>su=e).finally(()=>yh=null),yh)}async function oT(){let e=JSON.stringify({threads:su},null,2),t=`${Sh()}.${process.pid}.tmp`;await vi.mkdir(aT(),{recursive:!0}),await vi.writeFile(t,e),await vi.rename(t,Sh())}async function Lt(){bh=bh.then(oT,oT),await bh.catch(()=>{})}async function Eh(e){return(await Th())[e]??null}async function h1(e,t){let n=await Th();for(let[r,o]of Object.entries(n))if(o.channel===e&&o.ts===t)return{trackId:r,rec:o};return null}var ce=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");function Ti(e,t){let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1).trimEnd()}\u2026`}function w1(e,t=500){let n=String(e??"").trim().split(/\n\s*\n/)[0]??"";return Ti(n.replace(/\n+/g," "),t)}function iT(e){let t=`*${ce(e.name)}*${e.archivedAt?" \xB7 _archived_":""}`,n=`${ce(e.repoLabel)} \xB7 \`${ce(e.branch||"?")}\` \xB7 lead *${ce(e.lead)}*`,r=e.kickoff?`> ${ce(Ti(e.kickoff,300))}`:"_no kickoff yet \u2014 reply in this thread to steer the lead_";return[{type:"section",text:{type:"mrkdwn",text:`${t}
567
- ${n}`}},{type:"section",text:{type:"mrkdwn",text:r}},{type:"context",elements:[{type:"mrkdwn",text:`<${nu(e.trackId)}|open the Track> \xB7 reachable on the operator's private network only`}]}]}async function vh(e,t){await ho(e.botToken,{channel:t.channel,ts:t.ts,text:`Track: ${t.name}`,blocks:iT(t)})}async function Sr(e,t,n,r=void 0){return gh(e.botToken,{channel:t.channel,thread_ts:t.ts,text:n,...r?{blocks:r}:{},unfurl_links:!1})}var sT=new Set;function xr(e){sT.add(e),e.catch(()=>{}).finally(()=>sT.delete(e))}var Te=e=>({response_type:"ephemeral",text:e}),g1="*/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._",y1=["claude","cursor","codex"];function kh(e,t){let n=(t||"").toLowerCase(),r=e.filter(s=>!s.archivedAt),o=r.filter(s=>s.name.toLowerCase().startsWith(n));return o.sort((s,a)=>(a.lastResponseAt??a.createdAt??0)-(s.lastResponseAt??s.createdAt??0)),{match:o[0]??null,live:r}}var xh=(e,t)=>Te(`No live Track matches \u201C${ce(t)}\u201D. Live: ${e.map(n=>`\`${ce(n.name)}\``).join(" \xB7 ")||"none"}`);async function cT(e,t,{name:n,repo:r,responseUrl:o}){let s=e.deps;try{let a=(await s.listTracks()).filter(f=>!f.archivedAt);if(a.length>=t.maxConcurrent){await rt(o,{...Te(`At capacity \u2014 ${a.length} live Tracks (limit ${t.maxConcurrent}). Archive or stop something first.`),replace_original:!0});return}if(!t.channel){await rt(o,{...Te("No designated channel configured \u2014 set `slack.channel` in integrations.json."),replace_original:!0});return}let i=await s.createTrack({name:n,...r?{repo:r}:{}}),c=i.workspace||{},l={trackId:i.id,channel:t.channel,name:i.name,branch:c.branch||null,repoLabel:c.repo||(c.base?au.basename(c.base):"fresh workspace"),lead:"claude"},u=await gh(t.botToken,{channel:t.channel,text:`Track started: ${l.name}`,blocks:iT(l),unfurl_links:!1});l.ts=u.ts,(await Th())[i.id]=l,await Lt(),await rt(o,{...Te(`\u2713 *${ce(l.name)}* started \u2014 root message posted.`),replace_original:!0})}catch(a){await rt(o,{...Te(`Start failed: ${a?.message||a}`),replace_original:!0})}}async function b1(e,t,{track:n,responseUrl:r}){let o=e.deps;try{await o.archiveTrack(n.id);let s=await Eh(n.id);s&&(s.archivedAt=Date.now(),await Lt(),await vh(t,s).catch(()=>{})),await rt(r,{...Te(`\u2713 *${ce(n.name)}* archived.`),replace_original:!0})}catch(s){await rt(r,{...Te(`Archive failed: ${s?.message||s}`),replace_original:!0})}}async function k1(e,t,{track:n,agent:r,responseUrl:o}){try{await e.deps.startLeadHandoff(n.id,r),await rt(o,{...Te(`\u2713 Handing *${ce(n.name)}* to ${ce(r)} \u2014 the root message updates when the baton lands.`),replace_original:!0})}catch(s){await rt(o,{...Te(`Handoff failed: ${s?.message||s}`),replace_original:!0})}}async function x1(e,t,{track:n,responseUrl:r}){let o=e.deps;try{await o.interruptLead(n.id);let s=(o.listSubtaskJobs?.(n.id)??[]).filter(a=>!a.finishedAt);for(let a of s)try{o.cancelSubtask(a.id)}catch{}await rt(r,{...Te(`\u2713 Stopped *${ce(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 rt(r,{...Te(`Stop failed: ${s?.message||s}`),replace_original:!0})}}function S1(e,t){let n=[...t.slice(0,99).map(r=>({text:{type:"plain_text",text:Ti(`${r.name} (${r.branch})`,75)},value:r.path})),{text:{type:"plain_text",text:"fresh workspace"},value:"__fresh__"}];return[{type:"section",block_id:JSON.stringify({name:e}),text:{type:"mrkdwn",text:`Repo for *${ce(e)}*:`},accessory:{type:"static_select",action_id:"bostrat-start-repo",placeholder:{type:"plain_text",text:"Choose a repo"},options:n}}]}async function v1(e){let t=await e.listTracks(),n=t.filter(s=>!s.archivedAt);if(n.sort((s,a)=>(a.lastResponseAt??a.createdAt??0)-(s.lastResponseAt??s.createdAt??0)),!n.length)return"No live Tracks.";let r=n.map(s=>{let a=s.workspace||{},i=a.repo||(a.base?au.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 *${ce(s.name)}* \u2014 ${ce(i)}${a.branch?` \`${ce(a.branch)}\``:""} \xB7 lead ${ce(c)} \xB7 ${l}`}),o=t.length-n.length;return r.join(`
571
+ ![${r.name}](${o})`)}else if(r.change==="picked"){let o=(r.siblings??[]).map(s=>`**${s.name}**`).join(", ");await vi(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 vi(n,`**Bostrat** \u2014 live preview **${r.name}**: ${iu(r.slug)}
572
+ _(runs on the Track's branch; reachable on the operator's private network only)_`);break}case"cost.recorded":await v1(e.trackId,n);break;default:break}}catch(o){let s=t?await t(e.trackId).catch(()=>null):null;await qv(e.trackId,s?.cwd??null,o)}}function iT({resolveTrack:e}){st.on("event",t=>{T1(t,{resolveTrack:e}).catch(()=>{})})}async function cT(){if(!Ae())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await Fe("tickets");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Ai(),r=0;for(let[o,s]of Object.entries(n))await tt("tickets",{id:o,updatedAt:Date.now(),...s},{trackId:o}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}Qo();ps();import E1 from"ws";var lT=()=>process.env.BOSTRAT_SLACK_API_BASE||"https://slack.com/api";async function cu(e,t,n={}){let r=await fetch(`${lT()}/${e}`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/json; charset=utf-8"},body:JSON.stringify(n)}),o=await r.json().catch(()=>null);if(!o?.ok)throw new Error(`slack ${e}: ${o?.error||`http ${r.status}`}`);return o}var vh=(e,t)=>cu("chat.postMessage",e,t),ho=(e,t)=>cu("chat.update",e,t);async function rt(e,t){await fetch(e,{method:"POST",headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify(t)}).catch(()=>{})}async function A1(e,t,n={}){let r=await fetch(`${lT()}/${e}`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/x-www-form-urlencoded; charset=utf-8"},body:new URLSearchParams(n).toString()}),o=await r.json().catch(()=>null);if(!o?.ok)throw new Error(`slack ${e}: ${o?.error||`http ${r.status}`}`);return o}async function uT(e,{filename:t,buffer:n,title:r,channelId:o,threadTs:s,initialComment:a}){let{upload_url:i,file_id:c}=await A1("files.getUploadURLExternal",e,{filename:t,length:String(n.length)}),l=await fetch(i,{method:"POST",body:n});if(!l.ok)throw new Error(`slack upload: http ${l.status}`);return cu("files.completeUploadExternal",e,{files:[{id:c,title:r}],channel_id:o,thread_ts:s,...a?{initial_comment:a}:{}})}var _1=2200;function dT({getToken:e,onEnvelope:t,log:n=()=>{}}){let r=!1,o=null,s=null,a=1e3;async function i(){if(r)return;let l;try{let u=await e();if(!u)throw new Error("app token missing");({url:l}=await cu("apps.connections.open",u))}catch(u){return n(`connections.open failed: ${u?.message||u}`),c()}o=new E1(l),o.on("message",u=>{let f;try{f=JSON.parse(u)}catch{return}if(f.type==="hello"){a=1e3,n("socket connected");return}if(f.type==="disconnect"){try{o.close()}catch{}return}if(!f.envelope_id)return;let d=h=>{try{o.send(JSON.stringify(h?{envelope_id:f.envelope_id,payload:h}:{envelope_id:f.envelope_id}))}catch{}},p=!1,m=setTimeout(()=>{p=!0,d()},_1);Promise.resolve().then(()=>t(f)).then(h=>{clearTimeout(m),!p&&(p=!0,d(f.accepts_response_payload?h:void 0))},h=>{clearTimeout(m),p||(p=!0,d()),n(`envelope handler failed: ${h?.message||h}`)})}),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 mT=()=>process.env.BOSTRAT_STATE_DIR||uu.join(process.env.HOME||R1.tmpdir(),".bostrat"),Ih=()=>uu.join(mT(),"slack.json"),lu=null,Th=null,Eh=Promise.resolve();async function $h(){return lu||(Th??=_i.readFile(Ih(),"utf8").then(e=>JSON.parse(e)?.threads??{}).catch(()=>({})).then(e=>lu=e).finally(()=>Th=null),Th)}async function fT(){let e=JSON.stringify({threads:lu},null,2),t=`${Ih()}.${process.pid}.tmp`;await _i.mkdir(mT(),{recursive:!0}),await _i.writeFile(t,e),await _i.rename(t,Ih())}async function Lt(){Eh=Eh.then(fT,fT),await Eh.catch(()=>{})}async function Oh(e){return(await $h())[e]??null}async function $1(e,t){let n=await $h();for(let[r,o]of Object.entries(n))if(o.channel===e&&o.ts===t)return{trackId:r,rec:o};return null}var ce=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");function Ii(e,t){let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1).trimEnd()}\u2026`}function O1(e,t=500){let n=String(e??"").trim().split(/\n\s*\n/)[0]??"";return Ii(n.replace(/\n+/g," "),t)}function hT(e){let t=`*${ce(e.name)}*${e.archivedAt?" \xB7 _archived_":""}`,n=`${ce(e.repoLabel)} \xB7 \`${ce(e.branch||"?")}\` \xB7 lead *${ce(e.lead)}*`,r=e.kickoff?`> ${ce(Ii(e.kickoff,300))}`:"_no kickoff yet \u2014 reply in this thread to steer the lead_";return[{type:"section",text:{type:"mrkdwn",text:`${t}
573
+ ${n}`}},{type:"section",text:{type:"mrkdwn",text:r}},{type:"context",elements:[{type:"mrkdwn",text:`<${au(e.trackId)}|open the Track> \xB7 reachable on the operator's private network only`}]}]}async function Rh(e,t){await ho(e.botToken,{channel:t.channel,ts:t.ts,text:`Track: ${t.name}`,blocks:hT(t)})}async function xr(e,t,n,r=void 0){return vh(e.botToken,{channel:t.channel,thread_ts:t.ts,text:n,...r?{blocks:r}:{},unfurl_links:!1})}var pT=new Set;function kr(e){pT.add(e),e.catch(()=>{}).finally(()=>pT.delete(e))}var Ee=e=>({response_type:"ephemeral",text:e}),C1="*/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._",M1=["claude","cursor","codex"];function Ah(e,t){let n=(t||"").toLowerCase(),r=e.filter(s=>!s.archivedAt),o=r.filter(s=>s.name.toLowerCase().startsWith(n));return o.sort((s,a)=>(a.lastResponseAt??a.createdAt??0)-(s.lastResponseAt??s.createdAt??0)),{match:o[0]??null,live:r}}var _h=(e,t)=>Ee(`No live Track matches \u201C${ce(t)}\u201D. Live: ${e.map(n=>`\`${ce(n.name)}\``).join(" \xB7 ")||"none"}`);async function wT(e,t,{name:n,repo:r,responseUrl:o}){let s=e.deps;try{let a=(await s.listTracks()).filter(f=>!f.archivedAt);if(a.length>=t.maxConcurrent){await rt(o,{...Ee(`At capacity \u2014 ${a.length} live Tracks (limit ${t.maxConcurrent}). Archive or stop something first.`),replace_original:!0});return}if(!t.channel){await rt(o,{...Ee("No designated channel configured \u2014 set `slack.channel` in integrations.json."),replace_original:!0});return}let i=await s.createTrack({name:n,...r?{repo:r}:{}}),c=i.workspace||{},l={trackId:i.id,channel:t.channel,name:i.name,branch:c.branch||null,repoLabel:c.repo||(c.base?uu.basename(c.base):"fresh workspace"),lead:"claude"},u=await vh(t.botToken,{channel:t.channel,text:`Track started: ${l.name}`,blocks:hT(l),unfurl_links:!1});l.ts=u.ts,(await $h())[i.id]=l,await Lt(),await rt(o,{...Ee(`\u2713 *${ce(l.name)}* started \u2014 root message posted.`),replace_original:!0})}catch(a){await rt(o,{...Ee(`Start failed: ${a?.message||a}`),replace_original:!0})}}async function N1(e,t,{track:n,responseUrl:r}){let o=e.deps;try{await o.archiveTrack(n.id);let s=await Oh(n.id);s&&(s.archivedAt=Date.now(),await Lt(),await Rh(t,s).catch(()=>{})),await rt(r,{...Ee(`\u2713 *${ce(n.name)}* archived.`),replace_original:!0})}catch(s){await rt(r,{...Ee(`Archive failed: ${s?.message||s}`),replace_original:!0})}}async function P1(e,t,{track:n,agent:r,responseUrl:o}){try{await e.deps.startLeadHandoff(n.id,r),await rt(o,{...Ee(`\u2713 Handing *${ce(n.name)}* to ${ce(r)} \u2014 the root message updates when the baton lands.`),replace_original:!0})}catch(s){await rt(o,{...Ee(`Handoff failed: ${s?.message||s}`),replace_original:!0})}}async function D1(e,t,{track:n,responseUrl:r}){let o=e.deps;try{await o.interruptLead(n.id);let s=(o.listSubtaskJobs?.(n.id)??[]).filter(a=>!a.finishedAt);for(let a of s)try{o.cancelSubtask(a.id)}catch{}await rt(r,{...Ee(`\u2713 Stopped *${ce(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 rt(r,{...Ee(`Stop failed: ${s?.message||s}`),replace_original:!0})}}function B1(e,t){let n=[...t.slice(0,99).map(r=>({text:{type:"plain_text",text:Ii(`${r.name} (${r.branch})`,75)},value:r.path})),{text:{type:"plain_text",text:"fresh workspace"},value:"__fresh__"}];return[{type:"section",block_id:JSON.stringify({name:e}),text:{type:"mrkdwn",text:`Repo for *${ce(e)}*:`},accessory:{type:"static_select",action_id:"bostrat-start-repo",placeholder:{type:"plain_text",text:"Choose a repo"},options:n}}]}async function j1(e){let t=await e.listTracks(),n=t.filter(s=>!s.archivedAt);if(n.sort((s,a)=>(a.lastResponseAt??a.createdAt??0)-(s.lastResponseAt??s.createdAt??0)),!n.length)return"No live Tracks.";let r=n.map(s=>{let a=s.workspace||{},i=a.repo||(a.base?uu.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 *${ce(s.name)}* \u2014 ${ce(i)}${a.branch?` \`${ce(a.branch)}\``:""} \xB7 lead ${ce(c)} \xB7 ${l}`}),o=t.length-n.length;return r.join(`
568
574
  `)+(o?`
569
- _${o} archived_`:"")}async function T1(e,t){let n=await fo();if(!n)return Te("Slack integration not configured.");let r=e.deps,o=(t.text||"").trim().split(/\s+/).filter(Boolean),s=(o[0]||"help").toLowerCase(),a=o.slice(1);switch(s){case"start":{if(!a.length)return Te("Usage: `/bostrat start <name> [repo]`");let i=await r.listRepos(),c=a[a.length-1]?.toLowerCase(),l=a.length>1?i.find(f=>f.name.toLowerCase()===c):null,u=(l?a.slice(0,-1):a).join(" ");return l?(xr(cT(e,n,{name:u,repo:l.path,responseUrl:t.response_url})),Te(`Starting *${ce(u)}* on ${ce(l.name)}\u2026`)):{response_type:"ephemeral",text:`Pick a repo for \u201C${u}\u201D`,blocks:S1(u,i)}}case"archive":{if(!a.length)return Te("Usage: `/bostrat archive <track>`");let{match:i,live:c}=kh(await r.listTracks(),a.join(" "));return i?(xr(b1(e,n,{track:i,responseUrl:t.response_url})),Te(`Archiving *${ce(i.name)}*\u2026`)):xh(c,a.join(" "))}case"handoff":{let i=r.knownAgents??y1,c=a.at(-1)?.toLowerCase();if(a.length<2||!i.includes(c))return Te(`Usage: \`/bostrat handoff <track> <${i.join("|")}>\``);let l=a.slice(0,-1).join(" "),{match:u,live:f}=kh(await r.listTracks(),l);return u?(xr(k1(e,n,{track:u,agent:c,responseUrl:t.response_url})),Te(`Handing *${ce(u.name)}* to ${ce(c)}\u2026`)):xh(f,l)}case"stop":{if(!a.length)return Te("Usage: `/bostrat stop <track>`");let{match:i,live:c}=kh(await r.listTracks(),a.join(" "));return i?(xr(x1(e,n,{track:i,responseUrl:t.response_url})),Te(`Stopping *${ce(i.name)}*\u2026`)):xh(c,a.join(" "))}case"list":return Te(await v1(r));default:return Te(g1)}}async function E1(e,t,n,r){let{trackId:o,promptId:s,label:a}=r,i=await Eh(o);try{if(await e.deps.answerPrompt(o,{promptId:s,answers:[a]}),i?.prompt?.promptId===s){let{ts:c,question:l}=i.prompt;delete i.prompt,await Lt(),await ho(t.botToken,{channel:i.channel,ts:c,text:`\u2713 ${a}`,blocks:[{type:"section",text:{type:"mrkdwn",text:`~${ce(l||"question")}~
570
- \u2713 *${ce(a)}*`}}]}).catch(()=>{})}}catch(c){await rt(n.response_url,Te(`Couldn't answer: ${c?.message||c}`))}}async function A1(e,t,n,r){let{trackId:o,offerId:s,action:a}=r,i=e.deps;try{let c=await i.resolveTrack(o);if(!c)throw new Error("track not found");let l=await i.readEvents(c),u=l.find(d=>d.type==="pr.offered"&&d.payload?.offerId===s);if(!u)throw new Error("unknown offer");if(l.some(d=>d.type==="pr.offer.answered"&&d.payload?.offerId===s))throw new Error("offer already answered");let f=Array.isArray(r.actions)?zo.filter(d=>r.actions.includes(d)):a==="pr"?["commit","push","pr"]:a==="push"?["commit","push"]:null;if(f?.includes("pr")&&i.divertShip&&await i.divertShip(c,u,{actions:f}))return;f&&await i.sayToLead(c.id,Jo(f,{branch:u.payload.branch,base:u.payload.base}),{kind:f.includes("pr")?"pr-go":"push-go"}),await i.appendEvent({id:c.id,cwd:c.cwd},{type:"pr.offer.answered",actor:"user",source:"orchestrator",boxId:u.boxId,payload:{ts:Date.now(),offerId:s,action:f?a:"dismiss",actions:f}})}catch(c){await rt(n.response_url,Te(`Couldn't act on the offer: ${c?.message||c}`))}}async function _1(e,t,n,r){let{trackId:o,offerId:s,choice:a}=r;try{let i=await e.deps.resolveTrack(o);if(!i)throw new Error("track not found");await e.deps.answerPrExists(i,{offerId:s,choice:a})}catch(i){await rt(n.response_url,Te(`Couldn't act on the offer: ${i?.message||i}`))}}async function I1(e,t){let n=t.actions?.[0];if(!n?.action_id)return;let r=await fo();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 rt(t.response_url,{...Te(`Starting *${ce(s)}*\u2026`),replace_original:!0}),xr(cT(e,r,{name:s,repo:a==="__fresh__"?null:a,responseUrl:t.response_url}));return}let o;try{o=JSON.parse(n.value)}catch{return}n.action_id==="bostrat-prompt"?xr(E1(e,r,t,o)):n.action_id==="bostrat-ship"?xr(A1(e,r,t,o)):n.action_id==="bostrat-pr-exists"&&xr(_1(e,r,t,o))}async function R1(e,t){if(!t||t.type!=="message"||t.bot_id||t.subtype||!t.thread_ts||t.thread_ts===t.ts||!t.text?.trim())return;let n=await h1(t.channel,t.thread_ts);if(!n)return;let r=await fo();if(r)try{await e.deps.sayToLead(n.trackId,t.text.trim())}catch(o){await Sr(r,n.rec,`Couldn't deliver that to the lead: ${o?.message||o}`).catch(()=>{})}}function $1(e){return async t=>{if(t.type==="slash_commands")return T1(e,t.payload);if(t.type==="interactive"){await I1(e,t.payload);return}if(t.type==="events_api"){await R1(e,t.payload?.event);return}}}var O1=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 C1(e,t){let n=[{type:"section",text:{type:"mrkdwn",text:`\u2753 ${ce(t.question||"The lead needs an answer")}`}}],r=(t.options||[]).slice(0,12);return r.length?n.push({type:"actions",elements:r.map(o=>({type:"button",action_id:"bostrat-prompt",text:{type:"plain_text",text:Ti(String(o),75)},value:JSON.stringify({trackId:e,promptId:t.promptId,label:String(o)})}))}):n.push({type:"context",elements:[{type:"mrkdwn",text:"_reply in this thread to answer_"}]}),n}async function M1(e,t,n){let r=n.payload||{};if(!r.promptId||t.prompt?.promptId===r.promptId)return;t.prompt&&await ho(e.botToken,{channel:t.channel,ts:t.prompt.ts,text:"superseded",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${ce(t.prompt.question||"question")}~ _superseded_`}}]}).catch(()=>{});let o=await Sr(e,t,r.question||"The lead needs an answer",C1(n.trackId,r));t.prompt={promptId:r.promptId,ts:o.ts,question:r.question||null},await Lt()}async function N1(e,t,n){let r=n.payload||{};if(!t.prompt||r.promptId&&t.prompt.promptId!==r.promptId)return;let{ts:o,question:s}=t.prompt;delete t.prompt,await Lt(),await ho(e.botToken,{channel:t.channel,ts:o,text:"answered",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${ce(s||"question")}~
571
- \u2713 _answered_`}}]})}async function P1(e,t,n){let r=n.payload||{};if(!r.offerId||t.offers?.[r.offerId])return;let o=(i,c,l,u)=>({type:"button",action_id:"bostrat-ship",text:{type:"plain_text",text:c},value:JSON.stringify({trackId:n.trackId,offerId:r.offerId,action:i,...u?{actions:u}:{}}),...l?{style:l}:{}}),s;if(!Array.isArray(r.available))s=r.toPr?[o("push",`Commit & push${r.toPr.number?` to #${r.toPr.number}`:""}`,"primary"),o("dismiss","Not now")]:[o("pr","Open PR","primary"),o("push","Just push"),o("dismiss","Not now")];else{let i=r.available,c=Array.isArray(r.defaults)&&r.defaults.length?r.defaults:i,l={commit:"Commit",rebase:"rebase",push:"push",pr:r.prState==="open"?"open new PR":"open PR"},u=c.map(f=>l[f]).filter(Boolean).join(" & ");s=[o(c.includes("pr")?"pr":"push",u||"Ship","primary",c)],i.includes("pr")&&!c.includes("pr")&&s.push(o("pr","Open new PR",void 0,["pr"])),s.push(o("dismiss","Not now"))}let a=await Sr(e,t,r.excerpt||"Ship it?",[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${ce(Ti(r.excerpt||"The lead offered to ship.",300))}`}},{type:"actions",elements:s}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await Lt()}async function D1(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await Lt();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 ho(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function B1(e,t,n){let r=n.payload||{};if(!r.offerId||t.offers?.[r.offerId])return;let o=r.pr?.number?`#${r.pr.number}`:"a PR",s=(i,c,l)=>({type:"button",action_id:"bostrat-pr-exists",text:{type:"plain_text",text:c},value:JSON.stringify({trackId:n.trackId,offerId:r.offerId,choice:i}),...l?{style:l}:{}}),a=await Sr(e,t,`PR ${o} already open \u2014 push or new PR?`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${o}${r.branch?` (${ce(r.branch)})`:""} is already open. Push the update to it, or open a new PR?`}},{type:"actions",elements:[s("push",`Push to ${o}`,"primary"),s("new","Open a new PR"),s("dismiss","Not now")]}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await Lt()}async function j1(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await Lt();let s=r.choice==="dismiss"?"dismissed":r.choice==="new"?"\u2713 opening a new PR":"\u2713 pushing to the open PR";await ho(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function L1(e,t,n,r){let o=n.payload||{};if(o.change==="ready"&&o.mockId){let s=await(r.readMockPng??F1)(o.mockId,o.version??null);if(!s)return;let a=(o.version??1)>1?` (v${o.version})`:"";await nT(e.botToken,{filename:s.filename,buffer:s.buffer,title:`${o.name}${a}`,channelId:t.channel,threadTs:t.ts,initialComment:`\u{1F3A8} mock *${ce(o.name)}*${a}${o.group?` (group \`${ce(o.group)}\`)`:""}`})}else if(o.change==="picked"){let s=(o.siblings??[]).map(a=>`*${ce(a.name)}*`).join(", ");await Sr(e,t,`Design decision: ${o.name} picked`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F3A8} design decision: *${ce(o.name)}* picked${s?` over ${s}`:""}`}}])}}async function F1(e,t){let n=await En(e);if(!n)return null;let r=Bt(n,t);if(!r)return null;let o=await vi.readFile(Et(n,r.v).png).catch(()=>null);return o?{filename:`${n.name.replace(/[^\w.-]+/g,"-")}.v${r.v}.png`,buffer:o}:null}async function U1(e,t){if(!O1.has(t.type))return;let n=await Eh(t.trackId);if(!n)return;let r=await fo();if(!r)return;let o=t.payload||{};switch(t.type){case"turn.user":if(n.kickoff||t.actor!=="user"||!o.text)return;n.kickoff=o.text,await Lt(),await vh(r,n);return;case"turn.agent":{if(!o.text)return;let s=w1(o.text);if(!s)return;await Sr(r,n,s,[{type:"section",text:{type:"mrkdwn",text:ce(s)}},{type:"context",elements:[{type:"mrkdwn",text:`<${nu(t.trackId)}|full turn \u2192>`}]}]);return}case"prompt.raised":return M1(r,n,t);case"prompt.answered":return N1(r,n,t);case"pr.offered":return P1(r,n,t);case"pr.offer.answered":return D1(r,n,t);case"pr.exists.offered":return B1(r,n,t);case"pr.exists.answered":return j1(r,n,t);case"pr.state.changed":{if(o.change!=="opened"&&o.change!=="merged")return;let s=o.change==="opened"?"PR opened":"PR merged";await Sr(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 Lt(),await vh(r,n);return;case"view.state.changed":{if(o.change!=="created"||o.restarted||!o.slug)return;await Sr(r,n,`Live preview ${o.name}: ${ru(o.slug)}`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F50D} live preview *${ce(o.name)}*: ${ru(o.slug)}
572
- _runs on the Track's branch; reachable on the operator's private network only_`}}]);return}case"mock.state.changed":return L1(r,n,t,e.deps)}}function lT(e){let t={deps:e};st.on("event",s=>{U1(t,s).catch(()=>{})});let n=null,r=null,o=async()=>{n||!await fo()||(r&&clearInterval(r),r=null,n=rT({getToken:async()=>(await fo())?.appToken,onEnvelope:$1(t),log:s=>console.log(`[slack] ${s}`)}))};return r=setInterval(()=>o().catch(()=>{}),3e4),r.unref?.(),o().catch(()=>{}),()=>{r&&clearInterval(r),n?.()}}Nt();ue();un();ep();xa();import H1 from"node:fs/promises";function W1(e){let t=new Map;for(let n of String(e||"").split(`
573
- `)){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&&t.set(i,{messageId:i,tokens:a,model:o.message?.model||o.model||null})}return[...t.values()]}function q1(e){let t=new Set;for(let n of e)if(n.type==="cost.recorded"){n.payload?.messageId&&t.add(n.payload.messageId);for(let r of n.payload?.messageIds||[])t.add(r)}return t}var K1=new Set(["Write","Edit","NotebookEdit"]),G1=220,V1=160;function z1(e,t){let n=e?.tool_name??null,r={tool:n},o=e?.tool_input;if(!o||typeof o!="object")return r;if(K1.has(n)&&typeof o.file_path=="string"&&o.file_path){let s=o.file_path,a=t?.cwd;a&&s.startsWith(`${a}/`)&&(s=s.slice(a.length+1)),r.path=s.slice(0,G1)}else n==="Bash"&&typeof o.command=="string"&&o.command.trim()&&(r.head=Cr(o.command.trim().replace(/\s+/g," ")).slice(0,V1));return r}function J1(e,t){return e?.transcript_path?e.transcript_path:t?.cwd&&t?.sessionId?Mt(t.cwd,t.sessionId):t?.cwd?cd(t.cwd):null}async function uT(e,t){let n=await t(e?.session_id,e?.cwd);if(!n?.track)return[];let{track:r,box:o}=n,s={boxId:o?.name||null,provider:"claude",source:"hook"},a=[],i=async c=>{a.push(await _(r,{...s,...c}))};switch(e?.hook_event_name){case"SessionStart":await i({type:"session.ready",actor:"system",payload:{sessionId:e.session_id}});break;case"UserPromptSubmit":{let c=String(e.prompt??e.user_prompt??""),l=ll(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:z1(e,o)});break;case"Stop":await Y1(r,o,e,i);break;default:break}return a}async function Y1(e,t,n,r){let o=[],s=J1(n,t);if(s)try{o=W1(await H1.readFile(s,"utf8"))}catch{}let a=o.length?o[o.length-1]:null;if(await r({type:"turn.agent",actor:"agent",payload:{model:a?.model??t?.model??null,messageId:a?.messageId??null}}),!o.length)return;let i=q1(await L(e)),c=o.filter(u=>!i.has(u.messageId));if(c.length){let u=new Map;for(let f of c){let d=f.model||"unknown",p=u.get(d)||{tokens:{input:0,output:0,cacheWrite:0,cacheRead:0},messageIds:[]};for(let m of Object.keys(p.tokens))p.tokens[m]+=f.tokens[m];p.messageIds.push(f.messageId),u.set(d,p)}for(let[f,d]of u)await r({type:"cost.recorded",actor:"system",source:"transcript",payload:{model:f,usd:tr(f,d.tokens),tokens:d.tokens,messageId:d.messageIds[d.messageIds.length-1],messageIds:d.messageIds,apiCalls:d.messageIds.length}})}let l=a.tokens.input+a.tokens.cacheWrite+a.tokens.cacheRead;await r({type:"context.usage",actor:"system",source:"transcript",payload:{model:a.model,occupancy:l,tokens:a.tokens}})}Fs();import X1 from"node:fs";import dT from"node:fs/promises";import Ei from"node:os";import Z1 from"node:path";_p();tt();var Q1=1024*1024,iu=e=>Math.round(e/Q1);async function ej(e){try{let t=await dT.statfs(e),n=t.blocks*t.bsize,r=n-t.bavail*t.bsize;return{diskUsedMb:iu(r),diskTotalMb:iu(n)}}catch{return{diskUsedMb:null,diskTotalMb:null}}}async function tj(){try{return(await Ot()).filter(t=>t.isBostrat).length}catch{return null}}async function nj(){let e=0,t=!1;for(let n of["workspaces","worktrees"])try{let r=await dT.readdir(Z1.join(hi,n),{withFileTypes:!0});e+=r.filter(o=>o.isDirectory()).length,t=!0}catch{}return t?e:null}async function fT({stateDir:e=hi,now:t=Date.now}={}){let n=Ei.totalmem(),[r,o,s,a]=await Promise.all([xl().catch(()=>null),ej(X1.existsSync(e)?e:Ei.tmpdir()),tj(),nj()]),i=Ei.cpus()?.length||null,c=Ei.loadavg()?.[0]??null;return{ts:t(),loadavg1:c!=null?Math.round(c*100)/100:null,cpus:i,cpuPct:c!=null&&i?Math.min(100,Math.round(c/i*100)):null,memUsedMb:r!=null?iu(n-r):null,memTotalMb:iu(n),...o,boxes:s,worktrees:a,procUptimeS:Math.round(process.uptime()),osUptimeS:Math.round(Ei.uptime())}}ue();$d();zs();ue();Fr();function Ah(e){let t={};for(let n of e.boxes||[]){let r=n.role&&n.role!=="lead"?` \xB7 ${n.role}`:"";t[n.name]=`${n.name} (${n.agent||"?"}${r})`}return t}var pT=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),mT=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},cu=e=>Math.round(e*1e4)/1e4;async function hT(e){let t=[],n={},r={},o=0,s=0,a=0,i=0,c=0,l=new Set,u=pT(),f=0,d=[];for(let p of e||[]){let m=await L(p),h=nr(m,{boxLabels:Ah(p)});if(h.turns===0){p.archivedAt?f++:d.push(p.name||p.id);continue}o+=h.totalUsd,s+=h.turns,a+=h.repricedTurns||0,i+=h.asRecordedUsd||0,c+=h.unpricedTurns||0;for(let g of h.unpricedModels||[])l.add(g);mT(u,h.totalTokens);for(let[g,x]of Object.entries(h.byModel))n[g]||={usd:0,events:0,tokens:pT()},n[g].usd=cu(n[g].usd+x.usd),n[g].events+=x.events,mT(n[g].tokens,x.tokens);for(let[g,x]of Object.entries(h.byProvider))r[g]||={usd:0,events:0},r[g].usd=cu(r[g].usd+x.usd),r[g].events+=x.events;t.push({id:p.id,name:p.name,usd:h.totalUsd,rollup:h})}return t.sort((p,m)=>m.usd-p.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",fleet:{totalUsd:cu(o),asRecordedUsd:cu(i),turns:s,repricedTurns:a,unpricedTurns:c,unpricedModels:[...l],totalTokens:u,byModel:n,byProvider:r,tracksWithCost:t.length,tracksSilent:f+d.length,tracksSilentArchived:f,tracksSilentLive:d},tracks:t}}var vr=e=>`$${e.toFixed(4)}`,_s=(e,t)=>String(e).padEnd(t);function wT(e){let{fleet:t,tracks:n}=e,r=[];r.push(`BOSTRAT COST READ-OUT \xB7 ${e.generatedAt}`),e.pricingBasis&&r.push(`basis: ${e.pricingBasis}`);let o=t.tracksSilentLive||[];r.push(`fleet total ${vr(t.totalUsd)} over ${t.turns} turn(s) \xB7 ${t.tracksWithCost} track(s) with cost, ${t.tracksSilentArchived??t.tracksSilent} silent (archived)`+(o.length?`, ${o.length} LIVE with no cost data: ${o.join(", ")}`:"")),t.repricedTurns&&r.push(`${t.repricedTurns} turn(s) priced at current table rates (differs from as-recorded)`),t.asRecordedUsd!=null&&Math.abs(t.asRecordedUsd-t.totalUsd)>=.005&&r.push(`as-recorded total ${vr(t.asRecordedUsd)} \xB7 current-rates total ${vr(t.totalUsd)} (${t.totalUsd>=t.asRecordedUsd?"+":""}${vr(t.totalUsd-t.asRecordedUsd)})`),t.unpricedTurns&&r.push(`\u26A0 ${t.unpricedTurns} turn(s) UNPRICED \u2014 total under-reports. Add PER_MTOK rate(s) for: ${(t.unpricedModels||[]).join(", ")}`),r.push(""),r.push("BY MODEL");let s=Object.entries(t.byModel).sort((a,i)=>i[1].usd-a[1].usd);s.length||r.push(" (no cost events yet \u2014 hooks emit on each turn of a newly started box)");for(let[a,i]of s){let c=i.tokens;r.push(` ${_s(a,26)} ${_s(vr(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(` ${_s(a.name||a.id,30)} ${vr(a.usd)}`);let i=Object.values(a.rollup.byBox).sort((c,l)=>l.usd-c.usd);for(let c of i)if(r.push(` ${_s(c.label,40)} ${_s(vr(c.usd),10)} ${c.models.join(",")||"?"}`),c.epochs)for(let[l,u]of Object.entries(c.epochs).sort((f,d)=>Number(f[0])-Number(d[0])))r.push(` \u21B3 tenure ${l} (${u.provider||"?"})${" ".repeat(Math.max(1,24-String(u.provider||"?").length))}${_s(vr(u.usd),10)} ${u.models.join(",")||"?"}`)}return r.join(`
574
- `)}up();Wc();ue();Nf();import ij from"node:fs/promises";import cj from"node:path";Rd();Fr();var lu=e=>e.payload?.ts??e.ts,rj=12e4,Tr=e=>Math.round(e*1e4)/1e4,oj=()=>({usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},byTrack:new Map});function sj(e,{since:t}){let{track:n,events:r,brief:o}=e,s=k=>lu(k)>=t,a=Lr([wa(n?.name),wa(n?.workspace?.branch),o].filter(Boolean).join(" ")),i=new Map;for(let k of r)if(k.type==="subtask.delegated"&&k.boxId&&k.payload?.task){let E=Lr(k.payload.task);E&&i.set(k.boxId,E)}let c=new Map,l=k=>{let E=k||"unattributed";return c.has(E)||c.set(E,{segments:[u(null)],lastTs:null,provider:null}),c.get(E)},u=k=>({textCat:k,tools:{},usd:0,tokens:{input:0,output:0,cacheRead:0,cacheWrite:0},models:{},provider:null,activeMs:0,turns:0,toolCalls:0}),f=[...r].sort((k,E)=>lu(k)-lu(E)),d=0,p=0,m=0,h={turns:0};for(let k of f){let E=l(k.boxId),I=E.segments[E.segments.length-1],M=lu(k);switch(E.lastTs!=null&&M>E.lastTs&&s(k)&&(I.activeMs+=Math.min(M-E.lastTs,rj)),E.lastTs=M,k.provider&&(E.provider=k.provider),k.type){case"turn.user":{let N=k.payload?.text;if(k.source==="hook"||!String(N||"").trim())break;let C=u(Lr(N));E.segments.push(C),s(k)&&(C.turns+=1);break}case"peer.message":{let N=k.payload?.text;if(!String(N||"").trim())break;let C=u(Lr(N));E.segments.push(C),s(k)&&(C.turns+=1);break}case"tool.called":{if(k.source==="transcript")break;let N=k.payload?.tool;N&&(I.tools[N]=(I.tools[N]||0)+1),s(k)&&(I.toolCalls+=1);break}case"cost.recorded":{if(!s(k))break;let{usd:N,tokens:C,model:T,unpriced:j}=pn(k);j&&(h.turns+=1),I.usd+=N,C&&(I.tokens.input+=C.input,I.tokens.output+=C.output,I.tokens.cacheRead+=C.cacheRead,I.tokens.cacheWrite+=C.cacheWrite),I.models[T]=(I.models[T]||0)+N,k.provider&&(I.provider=k.provider);break}case"handoff.done":s(k)&&(d+=1);break;case"subtask.merged":s(k)&&(p+=1);break;case"error":s(k)&&k.payload?.kind==="subtask-failed"&&(m+=1);break;default:break}}let g=new Map,x=!1;for(let[k,E]of c)for(let I of E.segments){if(!(I.usd>0||I.activeMs>0||I.turns>0||I.toolCalls>0))continue;let N=I.textCat?.category??i.get(k)?.category??Xg(I.tools)?.category??a?.category??"uncategorized";g.has(N)||g.set(N,{usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{}});let C=g.get(N);C.usd+=I.usd,C.activeMs+=I.activeMs,C.turns+=I.turns,C.toolCalls+=I.toolCalls;for(let[j,Z]of Object.entries(I.models))C.models[j]=(C.models[j]||0)+Z;let T=I.provider||E.provider;T&&(C.providers[T]=(C.providers[T]||0)+I.usd),T==="cursor"&&I.usd===0&&(x=!0)}return{perCategory:g,handoffs:d,merged:p,failed:m,sawCursorActivity:x,unpricedTurns:h.turns}}function yT(e,{windowMs:t=null,now:n=Date.now()}={}){let r=t==null?0:n-t,o=new Map,s=[],a=0,i=!1,c=0;for(let h of e||[]){let{track:g,events:x}=h;if(!x?.length){a+=1;continue}let{perCategory:k,handoffs:E,merged:I,failed:M,sawCursorActivity:N,unpricedTurns:C}=sj(h,{since:r});N&&(i=!0),c+=C;let T={trackId:g?.id,name:g?.name||g?.id,archived:!!g?.archivedAt,usd:0,activeMs:0,turns:0,categories:{},models:{},providers:{},handoffs:E,subtasksMerged:I,subtasksFailed:M};for(let[j,Z]of k){T.usd+=Z.usd,T.activeMs+=Z.activeMs,T.turns+=Z.turns,T.categories[j]={usd:Tr(Z.usd),activeMs:Z.activeMs};for(let[D,R]of Object.entries(Z.models))T.models[D]=Tr((T.models[D]||0)+R);for(let[D,R]of Object.entries(Z.providers))T.providers[D]=Tr((T.providers[D]||0)+R);o.has(j)||o.set(j,oj());let fe=o.get(j);fe.usd+=Z.usd,fe.activeMs+=Z.activeMs,fe.turns+=Z.turns,fe.toolCalls+=Z.toolCalls;for(let[D,R]of Object.entries(Z.models))fe.models[D]=(fe.models[D]||0)+R;for(let[D,R]of Object.entries(Z.providers))fe.providers[D]=(fe.providers[D]||0)+R;let ie=fe.byTrack.get(g?.id)||{usd:0,activeMs:0};ie.usd+=Z.usd,ie.activeMs+=Z.activeMs,fe.byTrack.set(g?.id,ie)}(T.usd>0||T.activeMs>0||T.turns>0)&&(T.usd=Tr(T.usd),T.dominantCategory=aj(T.categories),s.push(T))}let l=[...o.values()].reduce((h,g)=>h+g.usd,0),u=[...o.values()].reduce((h,g)=>h+g.activeMs,0),f=l>0?"usd":"time",d=f==="usd"?l:u,p=new Map((e||[]).map(h=>[h.track?.id,h.track?.name||h.track?.id])),m=[...o.entries()].map(([h,g])=>({category:h,sharePct:d>0?Math.round((f==="usd"?g.usd:g.activeMs)/d*100):0,shareBasis:f,usd:Tr(g.usd),activeMs:g.activeMs,turns:g.turns,toolCalls:g.toolCalls,models:gT(g.models),providers:gT(g.providers),topWorkstreams:[...g.byTrack.entries()].sort((x,k)=>k[1].usd-x[1].usd||k[1].activeMs-x[1].activeMs).slice(0,2).map(([x,k])=>({trackId:x,name:p.get(x),usd:Tr(k.usd),activeMs:k.activeMs}))})).sort((h,g)=>g.usd-h.usd||g.activeMs-h.activeMs);return s.sort((h,g)=>g.usd-h.usd||g.activeMs-h.activeMs),{since:r,capturedAt:n,totalUsd:Tr(l),activeMs:u,turns:[...o.values()].reduce((h,g)=>h+g.turns,0),bullets:m,workstreams:s,gaps:{tracksWithoutEvents:a,cursorCostUnknown:i,unpricedTurns:c}}}var aj=e=>{let t=null;for(let[n,r]of Object.entries(e))(!t||r.usd>t.v.usd||r.usd===t.v.usd&&r.activeMs>t.v.activeMs)&&(t={cat:n,v:r});return t?.cat??null},gT=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Tr(n)]));var Is={"24h":24*36e5,"7d":168*36e5,"30d":720*36e5,all:null};function lj(e){let t=String(e||"7d");return t in Is?{key:t,ms:Is[t]}:{key:"7d",ms:Is["7d"]}}function uj(e,t){let n=new Set((t||[]).filter(o=>o.source==="orchestrator").map(o=>`${o.type}|${o.payload?.ts??"?"}`)),r=[...t||[]];for(let o of e?.events||[]){let s=Gc(o);!s||n.has(`${s.type}|${s.payload?.ts??"?"}`)||r.push({trackId:e.id,boxId:s.boxId??null,ts:o.at,type:s.type,actor:s.actor,provider:s.provider??null,source:s.source,payload:s.payload})}return r}async function dj(e){if(!e?.cwd)return null;try{let n=(await ij.readFile(cj.join(e.cwd,".bostrat","handoff","latest.md"),"utf8")).match(/^##\s*Objective\s*\n([\s\S]*?)(?:\n##\s|\n*$)/m);return n?n[1].trim().slice(0,1e3):null}catch{return null}}async function bT(e,{window:t="7d",from:n,to:r,now:o=Date.now()}={}){let s=Number(n),a=Number(r),i=Number.isFinite(s)&&s>0,c=i&&Number.isFinite(a)&&a>s?Math.min(a,o):o,{key:l,ms:u}=i?{key:"custom",ms:c-s}:lj(t),f=[];for(let d of e||[]){let p=await L(d),m=uj(d,p);i&&c<o&&(m=m.filter(h=>(h.ts??0)<=c)),f.push({track:d,events:m,brief:await dj(d)})}return{window:l,...yT(f,{windowMs:u,now:c})}}ue();Fr();var Er=36e5,vT=24*Er,fj=400,pj=12,Rs=e=>Math.round(e*1e4)/1e4;function mj({window:e,from:t,to:n,now:r=Date.now()}={}){let o=Number(t),s=Number(n);if(Number.isFinite(o)&&o>0){let c=Number.isFinite(s)&&s>o?Math.min(s,r):r;return{key:"custom",since:o,until:c}}let a=String(e||"7d")in Is?String(e||"7d"):"7d",i=Is[a];return{key:a,since:i==null?null:r-i,until:r}}var hj=(e,t)=>e!=null&&t-e<=48*Er?Er:vT;function kT(e,t){if(t===Er)return Math.floor(e/Er)*Er;let n=new Date(e);return n.setHours(0,0,0,0),n.getTime()}function wj(e,t){if(t===Er)return e+Er;let n=new Date(e);return n.setDate(n.getDate()+1),n.setHours(0,0,0,0),n.getTime()}var xT=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),ST=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},gj=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Rs(n)]));async function TT(e,t={}){let n=t.now??Date.now(),r=mj({...t,now:n}),o=r.since==null?vT:hj(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=xT(),f=0,d=0,p=0,m=0,h=0,g=new Set,x=new Map,k=[],E=[],I=[],M=null;for(let T of e||[]){let Z=(await L(T)).filter(D=>D.type==="cost.recorded");if(!Z.length){T.archivedAt||I.push(T.name||T.id);continue}let fe=[];for(let D of Z){let R=D.ts??0;s(R)?fe.push(D):i(R)&&(h+=pn(D).usd)}if(!fe.length)continue;let ie=nr(fe,{boxLabels:Ah(T)});f+=ie.totalUsd,d+=ie.turns,p+=ie.repricedTurns||0,m+=ie.unpricedTurns||0;for(let D of ie.unpricedModels||[])g.add(D);ST(u,ie.totalTokens);for(let[D,R]of Object.entries(ie.byModel))c[D]||={usd:0,events:0,tokens:xT()},c[D].usd=Rs(c[D].usd+R.usd),c[D].events+=R.events,ST(c[D].tokens,R.tokens);for(let[D,R]of Object.entries(ie.byProvider))l[D]||={usd:0,events:0},l[D].usd=Rs(l[D].usd+R.usd),l[D].events+=R.events;for(let D of fe){let{usd:R}=pn(D);if(!R)continue;let U=kT(D.ts??0,o),pe=x.get(U)??{t:U,total:0,byProvider:{}};pe.total+=R;let Se=D.provider||"unknown";pe.byProvider[Se]=(pe.byProvider[Se]||0)+R,x.set(U,pe),(M==null||U<M)&&(M=U)}k.push({id:T.id,name:T.name||T.id,archived:!!T.archivedAt,usd:ie.totalUsd,turns:ie.turns,providers:Object.keys(ie.byProvider)});for(let[D,R]of Object.entries(ie.byBox))E.push({trackId:T.id,trackName:T.name||T.id,boxId:D,...R})}let N=r.since!=null?kT(r.since,o):M,C=[];for(let T=N,j=0;T!=null&&T<r.until&&j<fj;T=wj(T,o),j++){let Z=x.get(T);C.push(Z?{t:T,total:Rs(Z.total),byProvider:gj(Z.byProvider)}:{t:T,total:0,byProvider:{}})}return k.sort((T,j)=>j.usd-T.usd),E.sort((T,j)=>j.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:C,fleet:{totalUsd:Rs(f),turns:d,repricedTurns:p,unpricedTurns:m,unpricedModels:[...g],totalTokens:u,byModel:c,byProvider:l,tracksWithCost:k.length,tracksSilentLive:I},prior:a!=null?{totalUsd:Rs(h),since:r.since-a,until:r.since}:null,tracks:k.slice(0,50),boxes:E.slice(0,pj)}}Qe();import $s from"node:fs/promises";import yj from"node:fs";import ze from"node:path";import bj from"node:os";import{execFile as kj}from"node:child_process";import{promisify as xj}from"node:util";var Sj=xj(kj),ET=process.env.BOSTRAT_STATE_DIR||ze.join(process.env.HOME||bj.tmpdir(),".bostrat"),uu=!1,_h=null;async function Ih(e,t){let n=await $s.stat(e).catch(()=>null);if(!n?.isFile())return!1;let r=await $s.stat(t).catch(()=>null);return r&&r.size===n.size&&r.mtimeMs>=n.mtimeMs?!1:(await $s.mkdir(ze.dirname(t),{recursive:!0}),await $s.copyFile(e,t),!0)}var vj=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 du(e,t,{skip:n=null}={}){let r=0,o=await $s.readdir(e,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(vj.has(s.name)||n?.has(s.name))continue;let a=ze.join(e,s.name);s.isDirectory()?r+=await du(a,ze.join(t,s.name)):s.isFile()&&(r+=await Ih(a,ze.join(t,s.name))?1:0)}return r}async function AT({stateDir:e=ET,dest:t=process.env.BOSTRAT_SYNC_DIR||`${ET}-sync`,remote:n=process.env.BOSTRAT_STATE_REMOTE||null,tracks:r=null}={}){try{await $s.mkdir(t,{recursive:!0});let o=0;o+=await Ih(ze.join(e,"tracks.json"),ze.join(t,"tracks.json"))?1:0,o+=await Ih(ze.join(e,"events.jsonl"),ze.join(t,"events.jsonl"))?1:0,o+=await du(ze.join(e,"events"),ze.join(t,"events")),o+=await du(ze.join(e,"memory"),ze.join(t,"memory"));let s=new Set(["mocks"]);for(let u of r||[])!u?.cwd||!u?.id||(o+=await du(ze.join(u.cwd,".bostrat"),ze.join(t,"workspaces",u.id,".bostrat"),{skip:s}));let a=(...u)=>Sj("git",["-C",t,...u]);yj.existsSync(ze.join(t,".git"))||(await a("init","-q"),await a("config","user.email","agent@bostrat.local"),await a("config","user.name","bostrat state sync")),n&&/^https:\/\/github\.com\//i.test(n)&&(await a("config","--get","credential.useHttpPath").then(()=>!0).catch(()=>!1)||await ju(t).catch(()=>{}));let i=!1,{stdout:c}=await a("status","--porcelain");c.trim()&&(await a("add","-A"),await a("commit","-q","-m",`state sync ${new Date().toISOString()}`),i=!0);let l=!1;if(n&&(i||uu))try{await a("push","-q",n,"HEAD:refs/heads/main"),l=!0,uu&&console.log("[state-sync] push recovered \u2014 off-box copy is current again"),uu=!1,_h=null}catch(u){uu=!0;let f=(u?.stderr||u?.message||String(u)).trim().split(`
575
- `).slice(-3).join(" | ").slice(0,300);f!==_h&&(_h=f,console.warn(`[state-sync] PUSH FAILING (retrying each cycle; off-box copy is STALE): ${f}`))}return{staged:o,committed:i,pushed:l}}catch(o){return{staged:0,committed:!1,pushed:!1,error:o?.message||String(o)}}}Gp();Nt();Br();tt();Us();import{execFile as Tj}from"node:child_process";import{promisify as Ej}from"node:util";import{randomUUID as Aj}from"node:crypto";import _j from"node:fs";import Ij from"node:os";import Rj from"node:path";var _r=Ej(Tj),fu=e=>new Promise(t=>setTimeout(t,e)),Ir=nd,Rh=process.env.BOSTRAT_USAGE_PROBE_CWD||Rj.join(Ij.homedir(),".bostrat","usage-probe"),$j=Number(process.env.BOSTRAT_USAGE_IDLE_REAP_MS)||5*6e4,Oj=Number(process.env.BOSTRAT_USAGE_PANEL_TIMEOUT_MS)||15e3,Cj=Number(process.env.BOSTRAT_USAGE_READY_TIMEOUT_MS)||45e3,_T=Number(process.env.BOSTRAT_USAGE_CACHE_MS)||2e4,Ar=null,Ai=null,_i=null;async function Mj(){try{return await _r(F,H("has-session","-t",Ir)),!0}catch{return!1}}function Nj(){Ar&&clearTimeout(Ar),Ar=setTimeout(()=>Pj().catch(()=>{}),$j),Ar.unref&&Ar.unref()}async function Pj(){Ar&&(clearTimeout(Ar),Ar=null);try{await _r(F,H("kill-session","-t",Ir))}catch{}}async function Dj(){let e=Date.now()+Cj;for(;;){let t=await $h().catch(()=>"");if(/for agents|for shortcuts|bypass permissions on/i.test(t)){await fu(500);return}if(Date.now()>e)throw new Error("usage probe didn't reach the prompt (trust/onboarding may be blocking)");await fu(500)}}async function Bj(){if(await Mj())return;if(!await Vn())throw new Error("host tmux server not running \u2014 start globo-tmux.service");_j.mkdirSync(Rh,{recursive:!0}),await Ln(Rh);let e=Aj();await _r(F,H("new-session","-d","-s",Ir,"-c",Rh,"-x","200","-y","60",...na()));let t=`${td} --session-id ${e}`;await _r(F,H("send-keys","-t",Ir,t,"Enter")),await Dj()}async function $h(){let{stdout:e}=await _r(F,H("capture-pane","-t",Ir,"-p"));return e}async function jj(){await Bj(),await _r(F,H("send-keys","-t",Ir,"-l","/usage")),await _r(F,H("send-keys","-t",Ir,"Enter"));let e=Date.now()+Oj,t="";for(;await fu(400),t=await $h(),!(/Current\s+(session|week)/i.test(t)||/\d+%\s*used/i.test(t)||Date.now()>e););return await fu(900),t=await $h(),await _r(F,H("send-keys","-t",Ir,"Escape")).catch(()=>{}),Nj(),t}function Lj(e){let t=String(e||"").split(`
576
- `).map(s=>s.replace(/\s+$/,"").trim()),n=s=>{let a=null,i=null;for(let c=s+1;c<Math.min(s+5,t.length)&&!/^Current\s/i.test(t[c]);c++){let l=t[c].match(/(\d+)%\s*used/i);l&&a===null&&(a=Number(l[1]));let u=t[c].match(/^Resets\s+(.+)$/i);u&&i===null&&(i=u[1].trim())}return a===null?null:{pct:a,resets:i||null}},r=s=>{let a=t.findIndex(i=>s.test(i));return a<0?null:n(a)},o=[];return t.forEach((s,a)=>{let i=s.match(/^Current week \(([^)]+)\)$/i);if(!i||/all models/i.test(i[1]))return;let c=n(a);c&&o.push({model:i[1].trim(),...c})}),{session:r(/^Current session\b/i),week:r(/^Current week \(all models\)/i)||r(/^Current week$/i),weekModels:o.length?o:null}}function Fj(e){let t=String(e||"").split(`
577
- `).map(s=>s.replace(/\s+$/,"")),n=t.findIndex(s=>/What's contributing/i.test(s));if(n<0)return null;let r=/(Usage credits|Esc to cancel|d to day · w to week|^\s*d to day)/i,o=[];for(let s=n+1;s<t.length&&!r.test(t[s]);s++)t[s].trim()&&o.push(t[s].trim());return o.length?o:null}async function IT({fresh:e=!1}={}){return!e&&Ai&&Date.now()-Ai.at<_T?Ai.data:_i||(_i=(async()=>{try{let t=await jj(),n=Lj(t),r={...n,contributors:Fj(t),subscription:!!(n.session||n.week||n.weekModels),capturedAt:Date.now()};return Ai={at:Date.now(),data:r},r}catch(t){let n={session:null,week:null,contributors:null,subscription:!1,error:t?.message||String(t),capturedAt:Date.now()};return Ai={at:Date.now()-(_T-3e3),data:n},n}finally{_i=null}})(),_i)}var Uj=262144;function Hj(e){let t=Number(e);if(!Number.isFinite(t)||t<0)return null;let n=Math.floor(t/3600),r=Math.round(t%3600/60);return n>=48?`in ${Math.round(n/24)}d`:n>0?`in ${n}h ${r}m`:`in ${Math.max(1,r)}m`}var Wj=new Set([300]),qj=new Set([10080]);function Kj(e){let t=Number(e);return!Number.isFinite(t)||t<=0?null:Wj.has(t)?"session":qj.has(t)?"week":"other"}function Gj(e){let t=Number(e);return!Number.isFinite(t)||t<=0?"Window":t%1440===0?`Window \xB7 ${t/1440}d`:t%60===0?`Window \xB7 ${t/60}h`:`Window \xB7 ${t}m`}function Vj(e,t,n){if(!e||typeof e!="object")return null;let r=Number(e.used_percent);if(!Number.isFinite(r))return null;let o=null,s=Number(e.resets_at),a=Number(e.resets_in_seconds);return Number.isFinite(s)&&s>0?o=s*1e3:Number.isFinite(a)&&a>=0&&(o=(Number.isFinite(t)?t:n)+a*1e3),{pct:Math.round(r),resets:o!=null?Hj((o-n)/1e3):null,resetsAt:o}}var Ii=e=>({session:null,week:null,other:null,planType:null,credits:null,limitReached:null,sawTokenCount:e});function zj(e,t=Date.now()){let n=String(e||"").split(`
578
- `),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 Ii(r);if(c.primary||c.secondary){let l=Date.parse(a.timestamp)||null,u=Ii(r);[c.primary,c.secondary].forEach((p,m)=>{let h=Vj(p,l,t);if(!h)return;let g=Kj(p.window_minutes);g===null&&(g=m===0?"session":"week"),g==="session"&&!u.session?u.session=h:g==="week"&&!u.week?u.week=h:(u.other??=[]).push({label:Gj(p.window_minutes),...h})}),u.planType=typeof c.plan_type=="string"?c.plan_type:null;let d=c.credits;return d&&(d.has_credits||d.unlimited)&&(u.credits={balance:String(d.balance??""),unlimited:!!d.unlimited}),u.limitReached=typeof c.rate_limit_reached_type=="string"&&c.rate_limit_reached_type||(c.spend_control_reached?"spend_control":null),u}if(c.primary_used_percent!=null||c.secondary_used_percent!=null){let l=u=>Number.isFinite(Number(u))?{pct:Math.round(Number(u)),resets:null,resetsAt:null}:null;return{...Ii(r),session:l(c.primary_used_percent),week:l(c.secondary_used_percent)}}return Ii(r)}return Ii(r)}async function Oh(e){let t={provider:"codex",supported:!0,contributors:null};try{let n=await Pr(e?.cwd,e?.sessionId);if(!n)return{...t,session:null,week:null,subscription:!1,error:"no codex rollout found for this box yet",capturedAt:Date.now()};let r=await it(n.file,Uj),o=zj(r);return{...t,session:o.session,week:o.week,other:o.other,planType:o.planType,credits:o.credits,limitReached:o.limitReached,subscription:!!(o.session||o.week||o.other?.length),capturedAt:n.mtimeMs||Date.now()}}catch(n){return{...t,session:null,week:null,subscription:!1,error:n?.message||String(n),capturedAt:Date.now()}}}async function RT(e,{fresh:t=!1}={}){let n=new Set;for(let o of e||[])for(let s of o.boxes||[])s.agent&&n.add(s.agent);let r=[];if((n.has("claude")||n.size===0)&&r.push(await pu({agent:"claude"},{fresh:t})),n.has("codex")){let o=[],s=[...e||[]].sort((i,c)=>(i.archivedAt?1:0)-(c.archivedAt?1:0)||(c.createdAt||0)-(i.createdAt||0));for(let i of s)for(let c of i.boxes||[])c.agent==="codex"&&o.push({...c,cwd:c.cwd||i.cwd});let a=null;for(let i of o.slice(0,8)){let c=await Oh(i);if(c.subscription){a=c;break}(!a||a.error&&!c.error)&&(a=c)}r.push(a||await Oh(null))}return n.has("cursor")&&r.push(await pu({agent:"cursor"})),{providers:r,capturedAt:Date.now()}}async function pu(e,{fresh:t=!1}={}){let n=e?.agent||"claude";return n==="codex"?Oh(e):n==="cursor"?{provider:"cursor",supported:!1,subscription:!1,session:null,week:null,contributors:null,capturedAt:Date.now()}:{provider:"claude",supported:!0,...await IT({fresh:t})}}Un();Qe();Qe();function Jj(e=process.env){return!!(ke(e)&&e.BOSTRAT_PLANE_TOKEN)}var Yj=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),mu=(e,t)=>Object.assign(new Error(e),{status:t});async function $T(e,t){if(!Jj(t))throw mu("node is not plane-linked \u2014 Gmail unavailable",503);let n;try{n=await fetch(`${ke(t)}${e}`,{headers:Yj(t)})}catch(o){throw mu(`plane unreachable \u2014 Gmail unavailable (${o?.message||o})`,503)}let r=await n.json().catch(()=>({}));if(!n.ok)throw mu(r?.error||`plane replied ${n.status}`,n.status);return r}async function OT(e,{max:t=10,env:n=process.env}={}){let r=new URLSearchParams({q:e||""});return t&&r.set("max",String(t)),(await $T(`/v1/gmail/messages?${r.toString()}`,n)).messages||[]}async function CT(e,{env:t=process.env}={}){if(!e)throw mu("message id required",400);return(await $T(`/v1/gmail/messages/${encodeURIComponent(e)}`,t)).message}Ca();rl();function Ch(e){let t=e.split(".");if(t.length!==4)return null;let n=0;for(let r of t){let o=Number(r);if(!Number.isInteger(o)||o<0||o>255)return null;n=n*256+o}return n>>>0}function Xj(e){let[t,n]=e.split("/"),r=Ch(t);if(r==null)return null;let o=n==null?32:Number(n);if(!Number.isInteger(o)||o<0||o>32)return null;let s=o===0?0:4294967295<<32-o>>>0;return a=>(a&s)===(r&s)}function MT(e){return(e||"").split(",").map(t=>t.trim()).filter(Boolean).map(Xj).filter(Boolean)}function Zj(e){let t=e.headers["fly-client-ip"];return typeof t=="string"&&t.trim()?t.trim():(e.socket&&e.socket.remoteAddress||"").replace(/^::ffff:/,"")}function NT(e){let t=MT(e),n=String(e||"").trim().toLowerCase()==="open";return{open:n,clientIp:Zj,allowed(r){if(n)return!0;let o=Ch((r||"").replace(/^::ffff:/,""));return o==null?!1:t.some(s=>s(o))}}}function PT(e,t){let n=MT(e);return{active:n.length>0,allows(r){if(!n.length)return!1;let o=(r.socket&&r.socket.remoteAddress||"").replace(/^::ffff:/,""),s=Ch(o);if(s==null||!n.some(i=>i(s)))return!1;let a=t(r);return!!(a&&a.view)}}}import DT from"node:crypto";import hu from"node:fs";import Qj from"node:path";function BT(e=process.env,{stateDir:t=hi,log:n=console}={}){let r=String(e.BOSTRAT_NODE_API_TOKEN||"").trim();if(r)return r;let o=Qj.join(t,"api-token");try{let a=hu.readFileSync(o,"utf8").trim();if(a)return a}catch{}let s=DT.randomBytes(32).toString("base64url");try{hu.mkdirSync(t,{recursive:!0}),hu.writeFileSync(o,s+`
579
- `,{mode:384}),hu.chmodSync(o,384)}catch(a){n.error?.(`[bostrat-agent] could not persist the node API token: ${a?.message||a}`)}return s}function Ri(e){let t=e?.socket?.remoteAddress||"";if(!t)return!1;let n=t.replace(/^::ffff:/,"");return n==="::1"||n==="127.0.0.1"||/^127\./.test(n)}function jT(e,t){if(!e||!t)return!1;let n=Buffer.from(String(e)),r=Buffer.from(String(t));return n.length!==r.length?!1:DT.timingSafeEqual(n,r)}function LT(e,t=null){let n=e?.headers?.["x-bostrat-token"];if(typeof n=="string"&&n.trim())return n.trim();let r=e?.headers?.authorization||"",o=/^Bearer\s+(.+)$/i.exec(r)?.[1];if(o)return o.trim();try{return(t??new URL(e.url,"http://node")).searchParams.get("token")||""}catch{return""}}var eL=[/^\/api\/github\/token\b/,/^\/api\/gmail\b/],tL=e=>eL.some(t=>t.test(e));function FT({token:e,enforce:t=!0,log:n=console}={}){return function(o,s,a){let i=o.path||o.url||"";if(!i.startsWith("/api"))return a();let c=LT(o);return jT(c,e)?a():tL(i)?(n.log?.(`[perimeter] refused ${o.method} ${i} \u2014 sensitive route requires the node API token`),s.status(401).json({error:"this route requires the node API token"})):!t||Ri(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 UT(e,t,{enforce:n=!0}={}){return!n||jT(LT(e),t)?!0:Ri(e)}un();bl();bl();import nL from"node:http";import rL from"node:net";function wu(e){if(!e)return null;let t=String(e).replace(/:\d+$/,"").toLowerCase();if(/^[\d.]+$/.test(t)||t.includes(":"))return null;let n=t.split(".");if(n.length<3)return null;let r=n[0];return/^[a-z0-9-]+$/.test(r)?r:null}function gu(e){let t=wu(e.headers.host);return t?{slug:t,view:Sp(t)}:null}var oL=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;"),sL=e=>{let t=oL(e.name);return`<!doctype html><meta charset="utf-8">
575
+ _${o} archived_`:"")}async function L1(e,t){let n=await fo();if(!n)return Ee("Slack integration not configured.");let r=e.deps,o=(t.text||"").trim().split(/\s+/).filter(Boolean),s=(o[0]||"help").toLowerCase(),a=o.slice(1);switch(s){case"start":{if(!a.length)return Ee("Usage: `/bostrat start <name> [repo]`");let i=await r.listRepos(),c=a[a.length-1]?.toLowerCase(),l=a.length>1?i.find(f=>f.name.toLowerCase()===c):null,u=(l?a.slice(0,-1):a).join(" ");return l?(kr(wT(e,n,{name:u,repo:l.path,responseUrl:t.response_url})),Ee(`Starting *${ce(u)}* on ${ce(l.name)}\u2026`)):{response_type:"ephemeral",text:`Pick a repo for \u201C${u}\u201D`,blocks:B1(u,i)}}case"archive":{if(!a.length)return Ee("Usage: `/bostrat archive <track>`");let{match:i,live:c}=Ah(await r.listTracks(),a.join(" "));return i?(kr(N1(e,n,{track:i,responseUrl:t.response_url})),Ee(`Archiving *${ce(i.name)}*\u2026`)):_h(c,a.join(" "))}case"handoff":{let i=r.knownAgents??M1,c=a.at(-1)?.toLowerCase();if(a.length<2||!i.includes(c))return Ee(`Usage: \`/bostrat handoff <track> <${i.join("|")}>\``);let l=a.slice(0,-1).join(" "),{match:u,live:f}=Ah(await r.listTracks(),l);return u?(kr(P1(e,n,{track:u,agent:c,responseUrl:t.response_url})),Ee(`Handing *${ce(u.name)}* to ${ce(c)}\u2026`)):_h(f,l)}case"stop":{if(!a.length)return Ee("Usage: `/bostrat stop <track>`");let{match:i,live:c}=Ah(await r.listTracks(),a.join(" "));return i?(kr(D1(e,n,{track:i,responseUrl:t.response_url})),Ee(`Stopping *${ce(i.name)}*\u2026`)):_h(c,a.join(" "))}case"list":return Ee(await j1(r));default:return Ee(C1)}}async function F1(e,t,n,r){let{trackId:o,promptId:s,label:a}=r,i=await Oh(o);try{if(await e.deps.answerPrompt(o,{promptId:s,answers:[a]}),i?.prompt?.promptId===s){let{ts:c,question:l}=i.prompt;delete i.prompt,await Lt(),await ho(t.botToken,{channel:i.channel,ts:c,text:`\u2713 ${a}`,blocks:[{type:"section",text:{type:"mrkdwn",text:`~${ce(l||"question")}~
576
+ \u2713 *${ce(a)}*`}}]}).catch(()=>{})}}catch(c){await rt(n.response_url,Ee(`Couldn't answer: ${c?.message||c}`))}}async function U1(e,t,n,r){let{trackId:o,offerId:s,action:a}=r,i=e.deps;try{let c=await i.resolveTrack(o);if(!c)throw new Error("track not found");let l=await i.readEvents(c),u=l.find(d=>d.type==="pr.offered"&&d.payload?.offerId===s);if(!u)throw new Error("unknown offer");if(l.some(d=>d.type==="pr.offer.answered"&&d.payload?.offerId===s))throw new Error("offer already answered");let f=Array.isArray(r.actions)?Yo.filter(d=>r.actions.includes(d)):a==="pr"?["commit","push","pr"]:a==="push"?["commit","push"]:null;if(f?.includes("pr")&&i.divertShip&&await i.divertShip(c,u,{actions:f}))return;f&&await i.sayToLead(c.id,Zo(f,{branch:u.payload.branch,base:u.payload.base}),{kind:f.includes("pr")?"pr-go":"push-go"}),await i.appendEvent({id:c.id,cwd:c.cwd},{type:"pr.offer.answered",actor:"user",source:"orchestrator",boxId:u.boxId,payload:{ts:Date.now(),offerId:s,action:f?a:"dismiss",actions:f}})}catch(c){await rt(n.response_url,Ee(`Couldn't act on the offer: ${c?.message||c}`))}}async function H1(e,t,n,r){let{trackId:o,offerId:s,choice:a}=r;try{let i=await e.deps.resolveTrack(o);if(!i)throw new Error("track not found");await e.deps.answerPrExists(i,{offerId:s,choice:a})}catch(i){await rt(n.response_url,Ee(`Couldn't act on the offer: ${i?.message||i}`))}}async function W1(e,t){let n=t.actions?.[0];if(!n?.action_id)return;let r=await fo();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 rt(t.response_url,{...Ee(`Starting *${ce(s)}*\u2026`),replace_original:!0}),kr(wT(e,r,{name:s,repo:a==="__fresh__"?null:a,responseUrl:t.response_url}));return}let o;try{o=JSON.parse(n.value)}catch{return}n.action_id==="bostrat-prompt"?kr(F1(e,r,t,o)):n.action_id==="bostrat-ship"?kr(U1(e,r,t,o)):n.action_id==="bostrat-pr-exists"&&kr(H1(e,r,t,o))}async function q1(e,t){if(!t||t.type!=="message"||t.bot_id||t.subtype||!t.thread_ts||t.thread_ts===t.ts||!t.text?.trim())return;let n=await $1(t.channel,t.thread_ts);if(!n)return;let r=await fo();if(r)try{await e.deps.sayToLead(n.trackId,t.text.trim())}catch(o){await xr(r,n.rec,`Couldn't deliver that to the lead: ${o?.message||o}`).catch(()=>{})}}function K1(e){return async t=>{if(t.type==="slash_commands")return L1(e,t.payload);if(t.type==="interactive"){await W1(e,t.payload);return}if(t.type==="events_api"){await q1(e,t.payload?.event);return}}}var G1=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 V1(e,t){let n=[{type:"section",text:{type:"mrkdwn",text:`\u2753 ${ce(t.question||"The lead needs an answer")}`}}],r=(t.options||[]).slice(0,12);return r.length?n.push({type:"actions",elements:r.map(o=>({type:"button",action_id:"bostrat-prompt",text:{type:"plain_text",text:Ii(String(o),75)},value:JSON.stringify({trackId:e,promptId:t.promptId,label:String(o)})}))}):n.push({type:"context",elements:[{type:"mrkdwn",text:"_reply in this thread to answer_"}]}),n}async function z1(e,t,n){let r=n.payload||{};if(!r.promptId||t.prompt?.promptId===r.promptId)return;t.prompt&&await ho(e.botToken,{channel:t.channel,ts:t.prompt.ts,text:"superseded",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${ce(t.prompt.question||"question")}~ _superseded_`}}]}).catch(()=>{});let o=await xr(e,t,r.question||"The lead needs an answer",V1(n.trackId,r));t.prompt={promptId:r.promptId,ts:o.ts,question:r.question||null},await Lt()}async function J1(e,t,n){let r=n.payload||{};if(!t.prompt||r.promptId&&t.prompt.promptId!==r.promptId)return;let{ts:o,question:s}=t.prompt;delete t.prompt,await Lt(),await ho(e.botToken,{channel:t.channel,ts:o,text:"answered",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${ce(s||"question")}~
577
+ \u2713 _answered_`}}]})}async function X1(e,t,n){let r=n.payload||{};if(!r.offerId||t.offers?.[r.offerId])return;let o=(i,c,l,u)=>({type:"button",action_id:"bostrat-ship",text:{type:"plain_text",text:c},value:JSON.stringify({trackId:n.trackId,offerId:r.offerId,action:i,...u?{actions:u}:{}}),...l?{style:l}:{}}),s;if(!Array.isArray(r.available))s=r.toPr?[o("push",`Commit & push${r.toPr.number?` to #${r.toPr.number}`:""}`,"primary"),o("dismiss","Not now")]:[o("pr","Open PR","primary"),o("push","Just push"),o("dismiss","Not now")];else{let i=r.available,c=Array.isArray(r.defaults)&&r.defaults.length?r.defaults:i,l={commit:"Commit",rebase:"rebase",push:"push",pr:r.prState==="open"?"open new PR":"open PR"},u=c.map(f=>l[f]).filter(Boolean).join(" & ");s=[o(c.includes("pr")?"pr":"push",u||"Ship","primary",c)],i.includes("pr")&&!c.includes("pr")&&s.push(o("pr","Open new PR",void 0,["pr"])),s.push(o("dismiss","Not now"))}let a=await xr(e,t,r.excerpt||"Ship it?",[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${ce(Ii(r.excerpt||"The lead offered to ship.",300))}`}},{type:"actions",elements:s}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await Lt()}async function Y1(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await Lt();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 ho(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function Z1(e,t,n){let r=n.payload||{};if(!r.offerId||t.offers?.[r.offerId])return;let o=r.pr?.number?`#${r.pr.number}`:"a PR",s=(i,c,l)=>({type:"button",action_id:"bostrat-pr-exists",text:{type:"plain_text",text:c},value:JSON.stringify({trackId:n.trackId,offerId:r.offerId,choice:i}),...l?{style:l}:{}}),a=await xr(e,t,`PR ${o} already open \u2014 push or new PR?`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${o}${r.branch?` (${ce(r.branch)})`:""} is already open. Push the update to it, or open a new PR?`}},{type:"actions",elements:[s("push",`Push to ${o}`,"primary"),s("new","Open a new PR"),s("dismiss","Not now")]}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await Lt()}async function Q1(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await Lt();let s=r.choice==="dismiss"?"dismissed":r.choice==="new"?"\u2713 opening a new PR":"\u2713 pushing to the open PR";await ho(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function ej(e,t,n,r){let o=n.payload||{};if(o.change==="ready"&&o.mockId){let s=await(r.readMockPng??tj)(o.mockId,o.version??null);if(!s)return;let a=(o.version??1)>1?` (v${o.version})`:"";await uT(e.botToken,{filename:s.filename,buffer:s.buffer,title:`${o.name}${a}`,channelId:t.channel,threadTs:t.ts,initialComment:`\u{1F3A8} mock *${ce(o.name)}*${a}${o.group?` (group \`${ce(o.group)}\`)`:""}`})}else if(o.change==="picked"){let s=(o.siblings??[]).map(a=>`*${ce(a.name)}*`).join(", ");await xr(e,t,`Design decision: ${o.name} picked`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F3A8} design decision: *${ce(o.name)}* picked${s?` over ${s}`:""}`}}])}}async function tj(e,t){let n=await An(e);if(!n)return null;let r=Bt(n,t);if(!r)return null;let o=await _i.readFile(Et(n,r.v).png).catch(()=>null);return o?{filename:`${n.name.replace(/[^\w.-]+/g,"-")}.v${r.v}.png`,buffer:o}:null}async function nj(e,t){if(!G1.has(t.type))return;let n=await Oh(t.trackId);if(!n)return;let r=await fo();if(!r)return;let o=t.payload||{};switch(t.type){case"turn.user":if(n.kickoff||t.actor!=="user"||!o.text)return;n.kickoff=o.text,await Lt(),await Rh(r,n);return;case"turn.agent":{if(!o.text)return;let s=O1(o.text);if(!s)return;await xr(r,n,s,[{type:"section",text:{type:"mrkdwn",text:ce(s)}},{type:"context",elements:[{type:"mrkdwn",text:`<${au(t.trackId)}|full turn \u2192>`}]}]);return}case"prompt.raised":return z1(r,n,t);case"prompt.answered":return J1(r,n,t);case"pr.offered":return X1(r,n,t);case"pr.offer.answered":return Y1(r,n,t);case"pr.exists.offered":return Z1(r,n,t);case"pr.exists.answered":return Q1(r,n,t);case"pr.state.changed":{if(o.change!=="opened"&&o.change!=="merged")return;let s=o.change==="opened"?"PR opened":"PR merged";await xr(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 Lt(),await Rh(r,n);return;case"view.state.changed":{if(o.change!=="created"||o.restarted||!o.slug)return;await xr(r,n,`Live preview ${o.name}: ${iu(o.slug)}`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F50D} live preview *${ce(o.name)}*: ${iu(o.slug)}
578
+ _runs on the Track's branch; reachable on the operator's private network only_`}}]);return}case"mock.state.changed":return ej(r,n,t,e.deps)}}function gT(e){let t={deps:e};st.on("event",s=>{nj(t,s).catch(()=>{})});let n=null,r=null,o=async()=>{n||!await fo()||(r&&clearInterval(r),r=null,n=dT({getToken:async()=>(await fo())?.appToken,onEnvelope:K1(t),log:s=>console.log(`[slack] ${s}`)}))};return r=setInterval(()=>o().catch(()=>{}),3e4),r.unref?.(),o().catch(()=>{}),()=>{r&&clearInterval(r),n?.()}}Nt();ue();Gt();ap();Aa();import rj from"node:fs/promises";function oj(e){let t=new Map;for(let n of String(e||"").split(`
579
+ `)){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&&t.set(i,{messageId:i,tokens:a,model:o.message?.model||o.model||null})}return[...t.values()]}function sj(e){let t=new Set;for(let n of e)if(n.type==="cost.recorded"){n.payload?.messageId&&t.add(n.payload.messageId);for(let r of n.payload?.messageIds||[])t.add(r)}return t}var aj=new Set(["Write","Edit","NotebookEdit"]),ij=220,cj=160;function lj(e,t){let n=e?.tool_name??null,r={tool:n},o=e?.tool_input;if(!o||typeof o!="object")return r;if(aj.has(n)&&typeof o.file_path=="string"&&o.file_path){let s=o.file_path,a=t?.cwd;a&&s.startsWith(`${a}/`)&&(s=s.slice(a.length+1)),r.path=s.slice(0,ij)}else n==="Bash"&&typeof o.command=="string"&&o.command.trim()&&(r.head=Or(o.command.trim().replace(/\s+/g," ")).slice(0,cj));return r}function uj(e,t){return e?.transcript_path?e.transcript_path:t?.cwd&&t?.sessionId?Mt(t.cwd,t.sessionId):t?.cwd?fd(t.cwd):null}async function yT(e,t){let n=await t(e?.session_id,e?.cwd);if(!n?.track)return[];let{track:r,box:o}=n,s={boxId:o?.name||null,provider:"claude",source:"hook"},a=[],i=async c=>{a.push(await _(r,{...s,...c}))};switch(e?.hook_event_name){case"SessionStart":await i({type:"session.ready",actor:"system",payload:{sessionId:e.session_id}});break;case"UserPromptSubmit":{let c=String(e.prompt??e.user_prompt??""),l=pl(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:lj(e,o)});break;case"Stop":await dj(r,o,e,i);break;default:break}return a}async function dj(e,t,n,r){let o=[],s=uj(n,t);if(s)try{o=oj(await rj.readFile(s,"utf8"))}catch{}let a=o.length?o[o.length-1]:null;if(await r({type:"turn.agent",actor:"agent",payload:{model:a?.model??t?.model??null,messageId:a?.messageId??null}}),!o.length)return;let i=sj(await L(e)),c=o.filter(u=>!i.has(u.messageId));if(c.length){let u=new Map;for(let f of c){let d=f.model||"unknown",p=u.get(d)||{tokens:{input:0,output:0,cacheWrite:0,cacheRead:0},messageIds:[]};for(let m of Object.keys(p.tokens))p.tokens[m]+=f.tokens[m];p.messageIds.push(f.messageId),u.set(d,p)}for(let[f,d]of u)await r({type:"cost.recorded",actor:"system",source:"transcript",payload:{model:f,usd:tr(f,d.tokens),tokens:d.tokens,messageId:d.messageIds[d.messageIds.length-1],messageIds:d.messageIds,apiCalls:d.messageIds.length}})}let l=a.tokens.input+a.tokens.cacheWrite+a.tokens.cacheRead;await r({type:"context.usage",actor:"system",source:"transcript",payload:{model:a.model,occupancy:l,tokens:a.tokens}})}qs();import fj from"node:fs";import bT from"node:fs/promises";import Ri from"node:os";import pj from"node:path";Mp();Ve();var mj=1024*1024,du=e=>Math.round(e/mj);async function hj(e){try{let t=await bT.statfs(e),n=t.blocks*t.bsize,r=n-t.bavail*t.bsize;return{diskUsedMb:du(r),diskTotalMb:du(n)}}catch{return{diskUsedMb:null,diskTotalMb:null}}}async function wj(){try{return(await Ot()).filter(t=>t.isBostrat).length}catch{return null}}async function gj(){let e=0,t=!1;for(let n of["workspaces","worktrees"])try{let r=await bT.readdir(pj.join(bi,n),{withFileTypes:!0});e+=r.filter(o=>o.isDirectory()).length,t=!0}catch{}return t?e:null}async function kT({stateDir:e=bi,now:t=Date.now}={}){let n=Ri.totalmem(),[r,o,s,a]=await Promise.all([El().catch(()=>null),hj(fj.existsSync(e)?e:Ri.tmpdir()),wj(),gj()]),i=Ri.cpus()?.length||null,c=Ri.loadavg()?.[0]??null;return{ts:t(),loadavg1:c!=null?Math.round(c*100)/100:null,cpus:i,cpuPct:c!=null&&i?Math.min(100,Math.round(c/i*100)):null,memUsedMb:r!=null?du(n-r):null,memTotalMb:du(n),...o,boxes:s,worktrees:a,procUptimeS:Math.round(process.uptime()),osUptimeS:Math.round(Ri.uptime())}}ue();jd();Zs();ue();Lr();function Ch(e){let t={};for(let n of e.boxes||[]){let r=n.role&&n.role!=="lead"?` \xB7 ${n.role}`:"";t[n.name]=`${n.name} (${n.agent||"?"}${r})`}return t}var xT=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),ST=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},fu=e=>Math.round(e*1e4)/1e4;async function vT(e){let t=[],n={},r={},o=0,s=0,a=0,i=0,c=0,l=new Set,u=xT(),f=0,d=[];for(let p of e||[]){let m=await L(p),h=nr(m,{boxLabels:Ch(p)});if(h.turns===0){p.archivedAt?f++:d.push(p.name||p.id);continue}o+=h.totalUsd,s+=h.turns,a+=h.repricedTurns||0,i+=h.asRecordedUsd||0,c+=h.unpricedTurns||0;for(let g of h.unpricedModels||[])l.add(g);ST(u,h.totalTokens);for(let[g,x]of Object.entries(h.byModel))n[g]||={usd:0,events:0,tokens:xT()},n[g].usd=fu(n[g].usd+x.usd),n[g].events+=x.events,ST(n[g].tokens,x.tokens);for(let[g,x]of Object.entries(h.byProvider))r[g]||={usd:0,events:0},r[g].usd=fu(r[g].usd+x.usd),r[g].events+=x.events;t.push({id:p.id,name:p.name,usd:h.totalUsd,rollup:h})}return t.sort((p,m)=>m.usd-p.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",fleet:{totalUsd:fu(o),asRecordedUsd:fu(i),turns:s,repricedTurns:a,unpricedTurns:c,unpricedModels:[...l],totalTokens:u,byModel:n,byProvider:r,tracksWithCost:t.length,tracksSilent:f+d.length,tracksSilentArchived:f,tracksSilentLive:d},tracks:t}}var Sr=e=>`$${e.toFixed(4)}`,Os=(e,t)=>String(e).padEnd(t);function TT(e){let{fleet:t,tracks:n}=e,r=[];r.push(`BOSTRAT COST READ-OUT \xB7 ${e.generatedAt}`),e.pricingBasis&&r.push(`basis: ${e.pricingBasis}`);let o=t.tracksSilentLive||[];r.push(`fleet total ${Sr(t.totalUsd)} over ${t.turns} turn(s) \xB7 ${t.tracksWithCost} track(s) with cost, ${t.tracksSilentArchived??t.tracksSilent} silent (archived)`+(o.length?`, ${o.length} LIVE with no cost data: ${o.join(", ")}`:"")),t.repricedTurns&&r.push(`${t.repricedTurns} turn(s) priced at current table rates (differs from as-recorded)`),t.asRecordedUsd!=null&&Math.abs(t.asRecordedUsd-t.totalUsd)>=.005&&r.push(`as-recorded total ${Sr(t.asRecordedUsd)} \xB7 current-rates total ${Sr(t.totalUsd)} (${t.totalUsd>=t.asRecordedUsd?"+":""}${Sr(t.totalUsd-t.asRecordedUsd)})`),t.unpricedTurns&&r.push(`\u26A0 ${t.unpricedTurns} turn(s) UNPRICED \u2014 total under-reports. Add PER_MTOK rate(s) for: ${(t.unpricedModels||[]).join(", ")}`),r.push(""),r.push("BY MODEL");let s=Object.entries(t.byModel).sort((a,i)=>i[1].usd-a[1].usd);s.length||r.push(" (no cost events yet \u2014 hooks emit on each turn of a newly started box)");for(let[a,i]of s){let c=i.tokens;r.push(` ${Os(a,26)} ${Os(Sr(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(` ${Os(a.name||a.id,30)} ${Sr(a.usd)}`);let i=Object.values(a.rollup.byBox).sort((c,l)=>l.usd-c.usd);for(let c of i)if(r.push(` ${Os(c.label,40)} ${Os(Sr(c.usd),10)} ${c.models.join(",")||"?"}`),c.epochs)for(let[l,u]of Object.entries(c.epochs).sort((f,d)=>Number(f[0])-Number(d[0])))r.push(` \u21B3 tenure ${l} (${u.provider||"?"})${" ".repeat(Math.max(1,24-String(u.provider||"?").length))}${Os(Sr(u.usd),10)} ${u.models.join(",")||"?"}`)}return r.join(`
580
+ `)}wp();Vc();ue();Ff();import Sj from"node:fs/promises";import vj from"node:path";Bd();Lr();var pu=e=>e.payload?.ts??e.ts,yj=12e4,vr=e=>Math.round(e*1e4)/1e4,bj=()=>({usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},byTrack:new Map});function kj(e,{since:t}){let{track:n,events:r,brief:o}=e,s=k=>pu(k)>=t,a=jr([Sa(n?.name),Sa(n?.workspace?.branch),o].filter(Boolean).join(" ")),i=new Map;for(let k of r)if(k.type==="subtask.delegated"&&k.boxId&&k.payload?.task){let E=jr(k.payload.task);E&&i.set(k.boxId,E)}let c=new Map,l=k=>{let E=k||"unattributed";return c.has(E)||c.set(E,{segments:[u(null)],lastTs:null,provider:null}),c.get(E)},u=k=>({textCat:k,tools:{},usd:0,tokens:{input:0,output:0,cacheRead:0,cacheWrite:0},models:{},provider:null,activeMs:0,turns:0,toolCalls:0}),f=[...r].sort((k,E)=>pu(k)-pu(E)),d=0,p=0,m=0,h={turns:0};for(let k of f){let E=l(k.boxId),I=E.segments[E.segments.length-1],M=pu(k);switch(E.lastTs!=null&&M>E.lastTs&&s(k)&&(I.activeMs+=Math.min(M-E.lastTs,yj)),E.lastTs=M,k.provider&&(E.provider=k.provider),k.type){case"turn.user":{let N=k.payload?.text;if(k.source==="hook"||!String(N||"").trim())break;let O=u(jr(N));E.segments.push(O),s(k)&&(O.turns+=1);break}case"peer.message":{let N=k.payload?.text;if(!String(N||"").trim())break;let O=u(jr(N));E.segments.push(O),s(k)&&(O.turns+=1);break}case"tool.called":{if(k.source==="transcript")break;let N=k.payload?.tool;N&&(I.tools[N]=(I.tools[N]||0)+1),s(k)&&(I.toolCalls+=1);break}case"cost.recorded":{if(!s(k))break;let{usd:N,tokens:O,model:T,unpriced:j}=mn(k);j&&(h.turns+=1),I.usd+=N,O&&(I.tokens.input+=O.input,I.tokens.output+=O.output,I.tokens.cacheRead+=O.cacheRead,I.tokens.cacheWrite+=O.cacheWrite),I.models[T]=(I.models[T]||0)+N,k.provider&&(I.provider=k.provider);break}case"handoff.done":s(k)&&(d+=1);break;case"subtask.merged":s(k)&&(p+=1);break;case"error":s(k)&&k.payload?.kind==="subtask-failed"&&(m+=1);break;default:break}}let g=new Map,x=!1;for(let[k,E]of c)for(let I of E.segments){if(!(I.usd>0||I.activeMs>0||I.turns>0||I.toolCalls>0))continue;let N=I.textCat?.category??i.get(k)?.category??iy(I.tools)?.category??a?.category??"uncategorized";g.has(N)||g.set(N,{usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{}});let O=g.get(N);O.usd+=I.usd,O.activeMs+=I.activeMs,O.turns+=I.turns,O.toolCalls+=I.toolCalls;for(let[j,Z]of Object.entries(I.models))O.models[j]=(O.models[j]||0)+Z;let T=I.provider||E.provider;T&&(O.providers[T]=(O.providers[T]||0)+I.usd),T==="cursor"&&I.usd===0&&(x=!0)}return{perCategory:g,handoffs:d,merged:p,failed:m,sawCursorActivity:x,unpricedTurns:h.turns}}function AT(e,{windowMs:t=null,now:n=Date.now()}={}){let r=t==null?0:n-t,o=new Map,s=[],a=0,i=!1,c=0;for(let h of e||[]){let{track:g,events:x}=h;if(!x?.length){a+=1;continue}let{perCategory:k,handoffs:E,merged:I,failed:M,sawCursorActivity:N,unpricedTurns:O}=kj(h,{since:r});N&&(i=!0),c+=O;let T={trackId:g?.id,name:g?.name||g?.id,archived:!!g?.archivedAt,usd:0,activeMs:0,turns:0,categories:{},models:{},providers:{},handoffs:E,subtasksMerged:I,subtasksFailed:M};for(let[j,Z]of k){T.usd+=Z.usd,T.activeMs+=Z.activeMs,T.turns+=Z.turns,T.categories[j]={usd:vr(Z.usd),activeMs:Z.activeMs};for(let[D,R]of Object.entries(Z.models))T.models[D]=vr((T.models[D]||0)+R);for(let[D,R]of Object.entries(Z.providers))T.providers[D]=vr((T.providers[D]||0)+R);o.has(j)||o.set(j,bj());let fe=o.get(j);fe.usd+=Z.usd,fe.activeMs+=Z.activeMs,fe.turns+=Z.turns,fe.toolCalls+=Z.toolCalls;for(let[D,R]of Object.entries(Z.models))fe.models[D]=(fe.models[D]||0)+R;for(let[D,R]of Object.entries(Z.providers))fe.providers[D]=(fe.providers[D]||0)+R;let ie=fe.byTrack.get(g?.id)||{usd:0,activeMs:0};ie.usd+=Z.usd,ie.activeMs+=Z.activeMs,fe.byTrack.set(g?.id,ie)}(T.usd>0||T.activeMs>0||T.turns>0)&&(T.usd=vr(T.usd),T.dominantCategory=xj(T.categories),s.push(T))}let l=[...o.values()].reduce((h,g)=>h+g.usd,0),u=[...o.values()].reduce((h,g)=>h+g.activeMs,0),f=l>0?"usd":"time",d=f==="usd"?l:u,p=new Map((e||[]).map(h=>[h.track?.id,h.track?.name||h.track?.id])),m=[...o.entries()].map(([h,g])=>({category:h,sharePct:d>0?Math.round((f==="usd"?g.usd:g.activeMs)/d*100):0,shareBasis:f,usd:vr(g.usd),activeMs:g.activeMs,turns:g.turns,toolCalls:g.toolCalls,models:ET(g.models),providers:ET(g.providers),topWorkstreams:[...g.byTrack.entries()].sort((x,k)=>k[1].usd-x[1].usd||k[1].activeMs-x[1].activeMs).slice(0,2).map(([x,k])=>({trackId:x,name:p.get(x),usd:vr(k.usd),activeMs:k.activeMs}))})).sort((h,g)=>g.usd-h.usd||g.activeMs-h.activeMs);return s.sort((h,g)=>g.usd-h.usd||g.activeMs-h.activeMs),{since:r,capturedAt:n,totalUsd:vr(l),activeMs:u,turns:[...o.values()].reduce((h,g)=>h+g.turns,0),bullets:m,workstreams:s,gaps:{tracksWithoutEvents:a,cursorCostUnknown:i,unpricedTurns:c}}}var xj=e=>{let t=null;for(let[n,r]of Object.entries(e))(!t||r.usd>t.v.usd||r.usd===t.v.usd&&r.activeMs>t.v.activeMs)&&(t={cat:n,v:r});return t?.cat??null},ET=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,vr(n)]));var Cs={"24h":24*36e5,"7d":168*36e5,"30d":720*36e5,all:null};function Tj(e){let t=String(e||"7d");return t in Cs?{key:t,ms:Cs[t]}:{key:"7d",ms:Cs["7d"]}}function Ej(e,t){let n=new Set((t||[]).filter(o=>o.source==="orchestrator").map(o=>`${o.type}|${o.payload?.ts??"?"}`)),r=[...t||[]];for(let o of e?.events||[]){let s=Xc(o);!s||n.has(`${s.type}|${s.payload?.ts??"?"}`)||r.push({trackId:e.id,boxId:s.boxId??null,ts:o.at,type:s.type,actor:s.actor,provider:s.provider??null,source:s.source,payload:s.payload})}return r}async function Aj(e){if(!e?.cwd)return null;try{let n=(await Sj.readFile(vj.join(e.cwd,".bostrat","handoff","latest.md"),"utf8")).match(/^##\s*Objective\s*\n([\s\S]*?)(?:\n##\s|\n*$)/m);return n?n[1].trim().slice(0,1e3):null}catch{return null}}async function _T(e,{window:t="7d",from:n,to:r,now:o=Date.now()}={}){let s=Number(n),a=Number(r),i=Number.isFinite(s)&&s>0,c=i&&Number.isFinite(a)&&a>s?Math.min(a,o):o,{key:l,ms:u}=i?{key:"custom",ms:c-s}:Tj(t),f=[];for(let d of e||[]){let p=await L(d),m=Ej(d,p);i&&c<o&&(m=m.filter(h=>(h.ts??0)<=c)),f.push({track:d,events:m,brief:await Aj(d)})}return{window:l,...AT(f,{windowMs:u,now:c})}}ue();Lr();var Tr=36e5,OT=24*Tr,_j=400,Ij=12,Ms=e=>Math.round(e*1e4)/1e4;function Rj({window:e,from:t,to:n,now:r=Date.now()}={}){let o=Number(t),s=Number(n);if(Number.isFinite(o)&&o>0){let c=Number.isFinite(s)&&s>o?Math.min(s,r):r;return{key:"custom",since:o,until:c}}let a=String(e||"7d")in Cs?String(e||"7d"):"7d",i=Cs[a];return{key:a,since:i==null?null:r-i,until:r}}var $j=(e,t)=>e!=null&&t-e<=48*Tr?Tr:OT;function IT(e,t){if(t===Tr)return Math.floor(e/Tr)*Tr;let n=new Date(e);return n.setHours(0,0,0,0),n.getTime()}function Oj(e,t){if(t===Tr)return e+Tr;let n=new Date(e);return n.setDate(n.getDate()+1),n.setHours(0,0,0,0),n.getTime()}var RT=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),$T=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},Cj=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Ms(n)]));async function CT(e,t={}){let n=t.now??Date.now(),r=Rj({...t,now:n}),o=r.since==null?OT:$j(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=RT(),f=0,d=0,p=0,m=0,h=0,g=new Set,x=new Map,k=[],E=[],I=[],M=null;for(let T of e||[]){let Z=(await L(T)).filter(D=>D.type==="cost.recorded");if(!Z.length){T.archivedAt||I.push(T.name||T.id);continue}let fe=[];for(let D of Z){let R=D.ts??0;s(R)?fe.push(D):i(R)&&(h+=mn(D).usd)}if(!fe.length)continue;let ie=nr(fe,{boxLabels:Ch(T)});f+=ie.totalUsd,d+=ie.turns,p+=ie.repricedTurns||0,m+=ie.unpricedTurns||0;for(let D of ie.unpricedModels||[])g.add(D);$T(u,ie.totalTokens);for(let[D,R]of Object.entries(ie.byModel))c[D]||={usd:0,events:0,tokens:RT()},c[D].usd=Ms(c[D].usd+R.usd),c[D].events+=R.events,$T(c[D].tokens,R.tokens);for(let[D,R]of Object.entries(ie.byProvider))l[D]||={usd:0,events:0},l[D].usd=Ms(l[D].usd+R.usd),l[D].events+=R.events;for(let D of fe){let{usd:R}=mn(D);if(!R)continue;let U=IT(D.ts??0,o),pe=x.get(U)??{t:U,total:0,byProvider:{}};pe.total+=R;let Se=D.provider||"unknown";pe.byProvider[Se]=(pe.byProvider[Se]||0)+R,x.set(U,pe),(M==null||U<M)&&(M=U)}k.push({id:T.id,name:T.name||T.id,archived:!!T.archivedAt,usd:ie.totalUsd,turns:ie.turns,providers:Object.keys(ie.byProvider)});for(let[D,R]of Object.entries(ie.byBox))E.push({trackId:T.id,trackName:T.name||T.id,boxId:D,...R})}let N=r.since!=null?IT(r.since,o):M,O=[];for(let T=N,j=0;T!=null&&T<r.until&&j<_j;T=Oj(T,o),j++){let Z=x.get(T);O.push(Z?{t:T,total:Ms(Z.total),byProvider:Cj(Z.byProvider)}:{t:T,total:0,byProvider:{}})}return k.sort((T,j)=>j.usd-T.usd),E.sort((T,j)=>j.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:O,fleet:{totalUsd:Ms(f),turns:d,repricedTurns:p,unpricedTurns:m,unpricedModels:[...g],totalTokens:u,byModel:c,byProvider:l,tracksWithCost:k.length,tracksSilentLive:I},prior:a!=null?{totalUsd:Ms(h),since:r.since-a,until:r.since}:null,tracks:k.slice(0,50),boxes:E.slice(0,Ij)}}et();import Ns from"node:fs/promises";import Mj from"node:fs";import Je from"node:path";import Nj from"node:os";import{execFile as Pj}from"node:child_process";import{promisify as Dj}from"node:util";var Bj=Dj(Pj),MT=process.env.BOSTRAT_STATE_DIR||Je.join(process.env.HOME||Nj.tmpdir(),".bostrat"),mu=!1,Mh=null;async function Nh(e,t){let n=await Ns.stat(e).catch(()=>null);if(!n?.isFile())return!1;let r=await Ns.stat(t).catch(()=>null);return r&&r.size===n.size&&r.mtimeMs>=n.mtimeMs?!1:(await Ns.mkdir(Je.dirname(t),{recursive:!0}),await Ns.copyFile(e,t),!0)}var jj=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 hu(e,t,{skip:n=null}={}){let r=0,o=await Ns.readdir(e,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(jj.has(s.name)||n?.has(s.name))continue;let a=Je.join(e,s.name);s.isDirectory()?r+=await hu(a,Je.join(t,s.name)):s.isFile()&&(r+=await Nh(a,Je.join(t,s.name))?1:0)}return r}async function NT({stateDir:e=MT,dest:t=process.env.BOSTRAT_SYNC_DIR||`${MT}-sync`,remote:n=process.env.BOSTRAT_STATE_REMOTE||null,tracks:r=null}={}){try{await Ns.mkdir(t,{recursive:!0});let o=0;o+=await Nh(Je.join(e,"tracks.json"),Je.join(t,"tracks.json"))?1:0,o+=await Nh(Je.join(e,"events.jsonl"),Je.join(t,"events.jsonl"))?1:0,o+=await hu(Je.join(e,"events"),Je.join(t,"events")),o+=await hu(Je.join(e,"memory"),Je.join(t,"memory"));let s=new Set(["mocks"]);for(let u of r||[])!u?.cwd||!u?.id||(o+=await hu(Je.join(u.cwd,".bostrat"),Je.join(t,"workspaces",u.id,".bostrat"),{skip:s}));let a=(...u)=>Bj("git",["-C",t,...u]);Mj.existsSync(Je.join(t,".git"))||(await a("init","-q"),await a("config","user.email","agent@bostrat.local"),await a("config","user.name","bostrat state sync")),n&&/^https:\/\/github\.com\//i.test(n)&&(await a("config","--get","credential.useHttpPath").then(()=>!0).catch(()=>!1)||await Hu(t).catch(()=>{}));let i=!1,{stdout:c}=await a("status","--porcelain");c.trim()&&(await a("add","-A"),await a("commit","-q","-m",`state sync ${new Date().toISOString()}`),i=!0);let l=!1;if(n&&(i||mu))try{await a("push","-q",n,"HEAD:refs/heads/main"),l=!0,mu&&console.log("[state-sync] push recovered \u2014 off-box copy is current again"),mu=!1,Mh=null}catch(u){mu=!0;let f=(u?.stderr||u?.message||String(u)).trim().split(`
581
+ `).slice(-3).join(" | ").slice(0,300);f!==Mh&&(Mh=f,console.warn(`[state-sync] PUSH FAILING (retrying each cycle; off-box copy is STALE): ${f}`))}return{staged:o,committed:i,pushed:l}}catch(o){return{staged:0,committed:!1,pushed:!1,error:o?.message||String(o)}}}Zp();Nt();Dr();Ve();Ks();import{execFile as Lj}from"node:child_process";import{promisify as Fj}from"node:util";import{randomUUID as Uj}from"node:crypto";import Hj from"node:fs";import Wj from"node:os";import qj from"node:path";var Ar=Fj(Lj),wu=e=>new Promise(t=>setTimeout(t,e)),_r=ad,Ph=process.env.BOSTRAT_USAGE_PROBE_CWD||qj.join(Wj.homedir(),".bostrat","usage-probe"),Kj=Number(process.env.BOSTRAT_USAGE_IDLE_REAP_MS)||5*6e4,Gj=Number(process.env.BOSTRAT_USAGE_PANEL_TIMEOUT_MS)||15e3,Vj=Number(process.env.BOSTRAT_USAGE_READY_TIMEOUT_MS)||45e3,PT=Number(process.env.BOSTRAT_USAGE_CACHE_MS)||2e4,Er=null,$i=null,Oi=null;async function zj(){try{return await Ar(F,H("has-session","-t",_r)),!0}catch{return!1}}function Jj(){Er&&clearTimeout(Er),Er=setTimeout(()=>Xj().catch(()=>{}),Kj),Er.unref&&Er.unref()}async function Xj(){Er&&(clearTimeout(Er),Er=null);try{await Ar(F,H("kill-session","-t",_r))}catch{}}async function Yj(){let e=Date.now()+Vj;for(;;){let t=await Dh().catch(()=>"");if(/for agents|for shortcuts|bypass permissions on/i.test(t)){await wu(500);return}if(Date.now()>e)throw new Error("usage probe didn't reach the prompt (trust/onboarding may be blocking)");await wu(500)}}async function Zj(){if(await zj())return;if(!await zn())throw new Error("host tmux server not running \u2014 start globo-tmux.service");Hj.mkdirSync(Ph,{recursive:!0}),await Fn(Ph);let e=Uj();await Ar(F,H("new-session","-d","-s",_r,"-c",Ph,"-x","200","-y","60",...aa()));let t=`${sd} --session-id ${e}`;await Ar(F,H("send-keys","-t",_r,t,"Enter")),await Yj()}async function Dh(){let{stdout:e}=await Ar(F,H("capture-pane","-t",_r,"-p"));return e}async function Qj(){await Zj(),await Ar(F,H("send-keys","-t",_r,"-l","/usage")),await Ar(F,H("send-keys","-t",_r,"Enter"));let e=Date.now()+Gj,t="";for(;await wu(400),t=await Dh(),!(/Current\s+(session|week)/i.test(t)||/\d+%\s*used/i.test(t)||Date.now()>e););return await wu(900),t=await Dh(),await Ar(F,H("send-keys","-t",_r,"Escape")).catch(()=>{}),Jj(),t}function eL(e){let t=String(e||"").split(`
582
+ `).map(s=>s.replace(/\s+$/,"").trim()),n=s=>{let a=null,i=null;for(let c=s+1;c<Math.min(s+5,t.length)&&!/^Current\s/i.test(t[c]);c++){let l=t[c].match(/(\d+)%\s*used/i);l&&a===null&&(a=Number(l[1]));let u=t[c].match(/^Resets\s+(.+)$/i);u&&i===null&&(i=u[1].trim())}return a===null?null:{pct:a,resets:i||null}},r=s=>{let a=t.findIndex(i=>s.test(i));return a<0?null:n(a)},o=[];return t.forEach((s,a)=>{let i=s.match(/^Current week \(([^)]+)\)$/i);if(!i||/all models/i.test(i[1]))return;let c=n(a);c&&o.push({model:i[1].trim(),...c})}),{session:r(/^Current session\b/i),week:r(/^Current week \(all models\)/i)||r(/^Current week$/i),weekModels:o.length?o:null}}function tL(e){let t=String(e||"").split(`
583
+ `).map(s=>s.replace(/\s+$/,"")),n=t.findIndex(s=>/What's contributing/i.test(s));if(n<0)return null;let r=/(Usage credits|Esc to cancel|d to day · w to week|^\s*d to day)/i,o=[];for(let s=n+1;s<t.length&&!r.test(t[s]);s++)t[s].trim()&&o.push(t[s].trim());return o.length?o:null}async function DT({fresh:e=!1}={}){return!e&&$i&&Date.now()-$i.at<PT?$i.data:Oi||(Oi=(async()=>{try{let t=await Qj(),n=eL(t),r={...n,contributors:tL(t),subscription:!!(n.session||n.week||n.weekModels),capturedAt:Date.now()};return $i={at:Date.now(),data:r},r}catch(t){let n={session:null,week:null,contributors:null,subscription:!1,error:t?.message||String(t),capturedAt:Date.now()};return $i={at:Date.now()-(PT-3e3),data:n},n}finally{Oi=null}})(),Oi)}var nL=262144;function rL(e){let t=Number(e);if(!Number.isFinite(t)||t<0)return null;let n=Math.floor(t/3600),r=Math.round(t%3600/60);return n>=48?`in ${Math.round(n/24)}d`:n>0?`in ${n}h ${r}m`:`in ${Math.max(1,r)}m`}var oL=new Set([300]),sL=new Set([10080]);function aL(e){let t=Number(e);return!Number.isFinite(t)||t<=0?null:oL.has(t)?"session":sL.has(t)?"week":"other"}function iL(e){let t=Number(e);return!Number.isFinite(t)||t<=0?"Window":t%1440===0?`Window \xB7 ${t/1440}d`:t%60===0?`Window \xB7 ${t/60}h`:`Window \xB7 ${t}m`}function cL(e,t,n){if(!e||typeof e!="object")return null;let r=Number(e.used_percent);if(!Number.isFinite(r))return null;let o=null,s=Number(e.resets_at),a=Number(e.resets_in_seconds);return Number.isFinite(s)&&s>0?o=s*1e3:Number.isFinite(a)&&a>=0&&(o=(Number.isFinite(t)?t:n)+a*1e3),{pct:Math.round(r),resets:o!=null?rL((o-n)/1e3):null,resetsAt:o}}var Ci=e=>({session:null,week:null,other:null,planType:null,credits:null,limitReached:null,sawTokenCount:e});function lL(e,t=Date.now()){let n=String(e||"").split(`
584
+ `),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 Ci(r);if(c.primary||c.secondary){let l=Date.parse(a.timestamp)||null,u=Ci(r);[c.primary,c.secondary].forEach((p,m)=>{let h=cL(p,l,t);if(!h)return;let g=aL(p.window_minutes);g===null&&(g=m===0?"session":"week"),g==="session"&&!u.session?u.session=h:g==="week"&&!u.week?u.week=h:(u.other??=[]).push({label:iL(p.window_minutes),...h})}),u.planType=typeof c.plan_type=="string"?c.plan_type:null;let d=c.credits;return d&&(d.has_credits||d.unlimited)&&(u.credits={balance:String(d.balance??""),unlimited:!!d.unlimited}),u.limitReached=typeof c.rate_limit_reached_type=="string"&&c.rate_limit_reached_type||(c.spend_control_reached?"spend_control":null),u}if(c.primary_used_percent!=null||c.secondary_used_percent!=null){let l=u=>Number.isFinite(Number(u))?{pct:Math.round(Number(u)),resets:null,resetsAt:null}:null;return{...Ci(r),session:l(c.primary_used_percent),week:l(c.secondary_used_percent)}}return Ci(r)}return Ci(r)}async function Bh(e){let t={provider:"codex",supported:!0,contributors:null};try{let n=await Nr(e?.cwd,e?.sessionId);if(!n)return{...t,session:null,week:null,subscription:!1,error:"no codex rollout found for this box yet",capturedAt:Date.now()};let r=await it(n.file,nL),o=lL(r);return{...t,session:o.session,week:o.week,other:o.other,planType:o.planType,credits:o.credits,limitReached:o.limitReached,subscription:!!(o.session||o.week||o.other?.length),capturedAt:n.mtimeMs||Date.now()}}catch(n){return{...t,session:null,week:null,subscription:!1,error:n?.message||String(n),capturedAt:Date.now()}}}async function BT(e,{fresh:t=!1}={}){let n=new Set;for(let o of e||[])for(let s of o.boxes||[])s.agent&&n.add(s.agent);let r=[];if((n.has("claude")||n.size===0)&&r.push(await gu({agent:"claude"},{fresh:t})),n.has("codex")){let o=[],s=[...e||[]].sort((i,c)=>(i.archivedAt?1:0)-(c.archivedAt?1:0)||(c.createdAt||0)-(i.createdAt||0));for(let i of s)for(let c of i.boxes||[])c.agent==="codex"&&o.push({...c,cwd:c.cwd||i.cwd});let a=null;for(let i of o.slice(0,8)){let c=await Bh(i);if(c.subscription){a=c;break}(!a||a.error&&!c.error)&&(a=c)}r.push(a||await Bh(null))}return n.has("cursor")&&r.push(await gu({agent:"cursor"})),{providers:r,capturedAt:Date.now()}}async function gu(e,{fresh:t=!1}={}){let n=e?.agent||"claude";return n==="codex"?Bh(e):n==="cursor"?{provider:"cursor",supported:!1,subscription:!1,session:null,week:null,contributors:null,capturedAt:Date.now()}:{provider:"claude",supported:!0,...await DT({fresh:t})}}Hn();et();et();function uL(e=process.env){return!!(ke(e)&&e.BOSTRAT_PLANE_TOKEN)}var dL=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),yu=(e,t)=>Object.assign(new Error(e),{status:t});async function jT(e,t){if(!uL(t))throw yu("node is not plane-linked \u2014 Gmail unavailable",503);let n;try{n=await fetch(`${ke(t)}${e}`,{headers:dL(t)})}catch(o){throw yu(`plane unreachable \u2014 Gmail unavailable (${o?.message||o})`,503)}let r=await n.json().catch(()=>({}));if(!n.ok)throw yu(r?.error||`plane replied ${n.status}`,n.status);return r}async function LT(e,{max:t=10,env:n=process.env}={}){let r=new URLSearchParams({q:e||""});return t&&r.set("max",String(t)),(await jT(`/v1/gmail/messages?${r.toString()}`,n)).messages||[]}async function FT(e,{env:t=process.env}={}){if(!e)throw yu("message id required",400);return(await jT(`/v1/gmail/messages/${encodeURIComponent(e)}`,t)).message}Ba();il();function jh(e){let t=e.split(".");if(t.length!==4)return null;let n=0;for(let r of t){let o=Number(r);if(!Number.isInteger(o)||o<0||o>255)return null;n=n*256+o}return n>>>0}function fL(e){let[t,n]=e.split("/"),r=jh(t);if(r==null)return null;let o=n==null?32:Number(n);if(!Number.isInteger(o)||o<0||o>32)return null;let s=o===0?0:4294967295<<32-o>>>0;return a=>(a&s)===(r&s)}function UT(e){return(e||"").split(",").map(t=>t.trim()).filter(Boolean).map(fL).filter(Boolean)}function pL(e){let t=e.headers["fly-client-ip"];return typeof t=="string"&&t.trim()?t.trim():(e.socket&&e.socket.remoteAddress||"").replace(/^::ffff:/,"")}function HT(e){let t=UT(e),n=String(e||"").trim().toLowerCase()==="open";return{open:n,clientIp:pL,allowed(r){if(n)return!0;let o=jh((r||"").replace(/^::ffff:/,""));return o==null?!1:t.some(s=>s(o))}}}function WT(e,t){let n=UT(e);return{active:n.length>0,allows(r){if(!n.length)return!1;let o=(r.socket&&r.socket.remoteAddress||"").replace(/^::ffff:/,""),s=jh(o);if(s==null||!n.some(i=>i(s)))return!1;let a=t(r);return!!(a&&a.view)}}}import qT from"node:crypto";import bu from"node:fs";import mL from"node:path";function KT(e=process.env,{stateDir:t=bi,log:n=console}={}){let r=String(e.BOSTRAT_NODE_API_TOKEN||"").trim();if(r)return r;let o=mL.join(t,"api-token");try{let a=bu.readFileSync(o,"utf8").trim();if(a)return a}catch{}let s=qT.randomBytes(32).toString("base64url");try{bu.mkdirSync(t,{recursive:!0}),bu.writeFileSync(o,s+`
585
+ `,{mode:384}),bu.chmodSync(o,384)}catch(a){n.error?.(`[bostrat-agent] could not persist the node API token: ${a?.message||a}`)}return s}function Mi(e){let t=e?.socket?.remoteAddress||"";if(!t)return!1;let n=t.replace(/^::ffff:/,"");return n==="::1"||n==="127.0.0.1"||/^127\./.test(n)}function GT(e,t){if(!e||!t)return!1;let n=Buffer.from(String(e)),r=Buffer.from(String(t));return n.length!==r.length?!1:qT.timingSafeEqual(n,r)}function VT(e,t=null){let n=e?.headers?.["x-bostrat-token"];if(typeof n=="string"&&n.trim())return n.trim();let r=e?.headers?.authorization||"",o=/^Bearer\s+(.+)$/i.exec(r)?.[1];if(o)return o.trim();try{return(t??new URL(e.url,"http://node")).searchParams.get("token")||""}catch{return""}}var hL=[/^\/api\/github\/token\b/,/^\/api\/gmail\b/],wL=e=>hL.some(t=>t.test(e));function zT({token:e,enforce:t=!0,log:n=console}={}){return function(o,s,a){let i=o.path||o.url||"";if(!i.startsWith("/api"))return a();let c=VT(o);return GT(c,e)?a():wL(i)?(n.log?.(`[perimeter] refused ${o.method} ${i} \u2014 sensitive route requires the node API token`),s.status(401).json({error:"this route requires the node API token"})):!t||Mi(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 JT(e,t,{enforce:n=!0}={}){return!n||GT(VT(e),t)?!0:Mi(e)}Gt();vl();vl();import gL from"node:http";import yL from"node:net";function ku(e){if(!e)return null;let t=String(e).replace(/:\d+$/,"").toLowerCase();if(/^[\d.]+$/.test(t)||t.includes(":"))return null;let n=t.split(".");if(n.length<3)return null;let r=n[0];return/^[a-z0-9-]+$/.test(r)?r:null}function xu(e){let t=ku(e.headers.host);return t?{slug:t,view:Ip(t)}:null}var bL=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;"),kL=e=>{let t=bL(e.name);return`<!doctype html><meta charset="utf-8">
580
586
  <meta http-equiv="refresh" content="3">
581
587
  <title>${t} \u2014 starting</title>
582
588
  <body style="font-family:system-ui;background:#0b0e14;color:#dce3f0;display:grid;place-items:center;height:100vh;margin:0">
583
589
  <div style="text-align:center"><p style="font-size:2rem;margin:0">\u23F3</p>
584
- <p><b>${t}</b> is waking up\u2026</p><p style="opacity:.6">auto-refreshing</p></div>`};function HT(e,t,n){let r=gu(e);if(!r)return n();let{view:o,slug:s}=r;if(!o)return t.statusCode=404,t.setHeader("content-type","text/plain"),t.end(`bostrat: no view named "${s}"`);if(o.state==="starting")return t.statusCode=503,t.setHeader("content-type","text/html"),t.end(sL(o));if(o.state!=="live"&&o.state!=="unhealthy")return t.statusCode=404,t.setHeader("content-type","text/plain"),t.end(`bostrat: view "${s}" is ${o.state} \u2014 restart it from the Views tab`);let a={...e.headers,host:`127.0.0.1:${o.port}`,"x-forwarded-host":e.headers.host,"x-forwarded-proto":e.headers["x-forwarded-proto"]||"http"};delete a.authorization,delete a.cookie;let i=nL.request({host:"127.0.0.1",port:o.port,method:e.method,path:e.url,headers:a},c=>{t.writeHead(c.statusCode||502,c.headers),c.pipe(t)});i.on("error",()=>{t.headersSent?t.destroy():(t.statusCode=502,t.setHeader("content-type","text/plain"),t.end(`bostrat: view "${s}" did not answer on :${o.port}`))}),e.pipe(i),e.on("aborted",()=>i.destroy())}function WT(e,t,n){let r=gu(e);if(!r)return!1;let{view:o,slug:s}=r;if(!o||o.state!=="live"&&o.state!=="unhealthy")return t.write(`HTTP/1.1 404 Not Found\r
590
+ <p><b>${t}</b> is waking up\u2026</p><p style="opacity:.6">auto-refreshing</p></div>`};function XT(e,t,n){let r=xu(e);if(!r)return n();let{view:o,slug:s}=r;if(!o)return t.statusCode=404,t.setHeader("content-type","text/plain"),t.end(`bostrat: no view named "${s}"`);if(o.state==="starting")return t.statusCode=503,t.setHeader("content-type","text/html"),t.end(kL(o));if(o.state!=="live"&&o.state!=="unhealthy")return t.statusCode=404,t.setHeader("content-type","text/plain"),t.end(`bostrat: view "${s}" is ${o.state} \u2014 restart it from the Views tab`);let a={...e.headers,host:`127.0.0.1:${o.port}`,"x-forwarded-host":e.headers.host,"x-forwarded-proto":e.headers["x-forwarded-proto"]||"http"};delete a.authorization,delete a.cookie;let i=gL.request({host:"127.0.0.1",port:o.port,method:e.method,path:e.url,headers:a},c=>{t.writeHead(c.statusCode||502,c.headers),c.pipe(t)});i.on("error",()=>{t.headersSent?t.destroy():(t.statusCode=502,t.setHeader("content-type","text/plain"),t.end(`bostrat: view "${s}" did not answer on :${o.port}`))}),e.pipe(i),e.on("aborted",()=>i.destroy())}function YT(e,t,n){let r=xu(e);if(!r)return!1;let{view:o,slug:s}=r;if(!o||o.state!=="live"&&o.state!=="unhealthy")return t.write(`HTTP/1.1 404 Not Found\r
585
591
  \r
586
592
  bostrat: no live view "${s}"\r
587
- `),t.destroy(),!0;let a=rL.connect(o.port,"127.0.0.1",()=>{let c=[`${e.method} ${e.url} HTTP/1.1`];for(let[l,u]of Object.entries(e.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
593
+ `),t.destroy(),!0;let a=yL.connect(o.port,"127.0.0.1",()=>{let c=[`${e.method} ${e.url} HTTP/1.1`];for(let[l,u]of Object.entries(e.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
588
594
  `)+`\r
589
595
  \r
590
- `),n?.length&&a.write(n),t.pipe(a),a.pipe(t)}),i=()=>{a.destroy(),t.destroy()};return a.on("error",i),t.on("error",i),!0}function qT(e,t){let n=typeof t=="string"?{host:t}:t||{},r=n["x-bostrat-view-base"];return typeof r=="string"&&r?`${n["x-forwarded-proto"]==="https"?"https":"http"}://${e.slug}.${r.replace(/:\d+$/,"")}/`:`http://${e.slug}.${aL(n.host)}/`}function aL(e){if(process.env.BOSTRAT_PUBLIC_HOST)return String(process.env.BOSTRAT_PUBLIC_HOST).replace(/:\d+$/,"");let t=String(e||"").replace(/:\d+$/,"").toLowerCase();if(!t||!t.includes(".")||/^[\d.]+$/.test(t))return"bostrat.globopi";let n=t.split(".");return wu(t)&&Sp(n[0])?n.slice(1).join("."):t}us();Pp();Al();rp();ue();import KT from"node:os";import{randomUUID as iL}from"node:crypto";var cL=(e=process.env)=>({nodeId:e.BOSTRAT_NODE_ID||KT.hostname(),nodeName:e.BOSTRAT_NODE_NAME||KT.hostname()});var GT=32768,VT=120,zT=1e3,JT=new Set(["claude","codex","cursor"]),lL=new Set(["off","transition","nag"]),uL=[[0,59],[0,23],[1,31],[1,12],[0,6]];function dL(e){let t=String(e??"").trim().split(/\s+/);return t.length!==5?!1:t.every((n,r)=>{let[o,s]=uL[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 Dn=e=>String(e??"").trim();function fL(e,t){let n=e&&typeof e=="object"?e:{},r=Dn(n.name);if(!r)throw new Error("a loop plan needs a name");if(r.length>VT)throw new Error(`name is too long (${r.length}); cap is ${VT}`);let o=Dn(n.schedule);if(!o)throw new Error('a loop plan needs a schedule (5-field UTC crontab, e.g. "0 7 * * *")');if(!dL(o))throw new Error(`invalid cron schedule: "${o}" \u2014 5 UTC fields, e.g. "0 7 * * *"`);let s=Dn(n.prompt);if(!s)throw new Error("a loop plan needs a prompt \u2014 it is what the run does");if(s.length>GT)throw new Error(`prompt is too long (${s.length} chars); cap is ${GT}`);let a=Dn(n.expectation)||null;if(a&&a.length>zT)throw new Error(`expectation is too long (${a.length}); cap is ${zT}`);let i=Dn(n.notify)||"off";if(!lL.has(i))throw new Error(`notify must be one of off | transition | nag, got "${n.notify}"`);let c=n.assignment??null,l=Dn(typeof c=="string"?c:c?.provider)||"claude";if(!JT.has(l))throw new Error(`unknown provider "${l}" \u2014 one of ${[...JT].join(", ")}`);let u=typeof c=="object"&&c&&Dn(c.model)||null,f=Dn(t?.workspace?.repo)||Dn(t?.workspace?.base)||null;if(!f)throw new Error("this Track isn't based on a repo, so there's nothing for a loop to run in \u2014 propose from a repo-backed Track");let{nodeId:d,nodeName:p}=cL();return{name:r,schedule:o,prompt:s,expectation:a,notify:i,assignment:u?{provider:l,model:u}:{provider:l},repo:f,nodeId:d||null,nodeName:p||null}}async function YT(e,t){let n=fL(t,e),r=iL();return await _({id:e.id,cwd:e.cwd},{type:"loop.create.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),proposalId:r,...n}}),{proposalId:r,...n}}async function XT(e,t,n,{loopId:r=null,nextFireAt:o=null}={}){if(!t)throw new Error("proposalId required");let s=await L({id:e.id,cwd:e.cwd}),a=s.find(c=>c.type==="loop.create.offered"&&c.payload?.proposalId===t);if(!a)throw new Error("unknown proposal");if(s.some(c=>c.type==="loop.create.answered"&&c.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await _({id:e.id,cwd:e.cwd},{type:"loop.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"dismiss"}}),{proposalId:t,action:"dismiss"};if(!r)throw new Error("loopId required \u2014 the loop is created on the plane before the card is answered");let i=a.payload;return await _({id:e.id,cwd:e.cwd},{type:"loop.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,loopId:String(r),name:i.name,schedule:i.schedule,provider:i.assignment?.provider??"claude",repo:i.repo??null,nodeId:i.nodeId??null,nextFireAt:Number.isFinite(Number(o))?Number(o):null}}),await _({id:e.id,cwd:e.cwd},{type:"loop.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",loopId:String(r)}}),{proposalId:t,action:"created",loopId:String(r)}}Kn();ue();wn();Al();var ZT=10,QT=200,pL=120,mL=24,tE=/^\d{4}-\d{2}-\d{2}$/;function Mh(e=process.env){return(e.CHANGELOG_REPOS||"globocodes/bostrat").split(",").map(t=>t.trim()).filter(Boolean)}var hL=(e=Date.now())=>new Date(e).toISOString().slice(0,10),Je=(e,t="i")=>new RegExp(e,t),wL=[{re:Je("^(business|docs|chore|ci|refactor|test|security|sec)(\\([^)]*\\))?!?:"),reason:"non-product PR prefix"},{re:Je("\\bSPC\\b",""),reason:"business (SPC)"},{re:Je("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),reason:"business"},{re:Je("competitor|cloudcli|\\bkiro\\b"),reason:"competitor research"},{re:Je("\\bReplicas\\b",""),reason:"competitor research"},{re:Je("tenanc|tenant|perimeter|ip[- ]gate|access[- ]code|vulnerab|\\bCVE\\b|audit|hardening|security|\\bsweep\\b"),reason:"security / tenancy"},{re:Je("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),reason:"internal codename"},{re:Je("^track/(business|security|spc|sec)-"),reason:"non-product branch"}],gL=[Je("\\bSPC\\b",""),Je("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),Je("competitor|cloudcli|\\bkiro\\b"),Je("\\bReplicas\\b",""),Je("tenanc|\\btenants?\\b|cross-tenant|perimeter|ip[- ]gate|vulnerab|\\bCVE\\b|hardening|security register|audit finding"),Je("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),Je("(^|[^\\w&])#\\d+\\b"),Je("\\btrack/[\\w.-]+")];function yL({title:e="",headRef:t=""}={}){let n=String(e||""),r=String(t||"");for(let{re:o,reason:s}of wL)if(o.test(n)||o.test(r))return s;return null}function eE(e){let t=String(e||"");for(let n of gL){let r=n.exec(t);if(r)return r[0].trim()}return null}function nE(e,t=Date.now()){if(!e)return t-24*36e5;let n=/^(\d+)\s*([hd])$/.exec(String(e).trim());if(n)return t-Number(n[1])*(n[2]==="h"?36e5:24*36e5);let r=Date.parse(e);if(!Number.isNaN(r))return r;throw new Error(`unparseable since "${e}" \u2014 use 24h, 7d, or an ISO date`)}var bL=/^\*\*([^*]+?)\*\*\s*[:.]?\s*[—–-]?\s*(.*)$/;function kL(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=za(e);if(t.length)throw new Error(`changelog entry appears to contain a secret VALUE (${t.join(", ")}) \u2014 entries ship off-box; never put a credential in one. Replace it and retry.`);let n=null,r=[];for(let o of e.split(`
591
- `)){let s=o.trim();if(!s)continue;if(s.startsWith("#")){n==null&&(n=s.replace(/^#+\s*/,"").trim().slice(0,pL)||null);continue}let a=/^[-*]\s+(.*)$/.exec(s);if(!a)continue;let i=a[1].trim(),c=null,l=new RegExp(`^\\[([^\\]]{1,${mL}})\\]\\s+(.*)$`).exec(i);if(l&&(c=l[1].trim(),i=l[2].trim()),!i)continue;let u=bL.exec(i);if(!u||!u[1].trim()||!u[2].trim())throw new Error(`bullet ${r.length+1} must be \`**Short summary** \u2014 the item, one sentence.\` (bold summary title, em dash, then the change) \u2014 got "${i.slice(0,80)}". Rewrite it and re-publish.`);i=`**${u[1].trim().replace(/[:.]\s*$/,"")}** \u2014 ${u[2].trim()}`;let f=eE(i);if(f)throw new Error(`bullet ${r.length+1} mentions "${f}" \u2014 the product changelog never carries business, security/tenancy or internal-ops items, PR numbers, branch names or codenames; drop the bullet or rewrite it as the user-visible change and re-publish.`);if(i.length>QT)throw new Error(`bullet ${r.length+1} is ${i.length} chars \u2014 over the ${QT}-char cap; a changelog bullet is one line`);r.push({text:i,...c?{area:c}:{}})}if(n){let o=eE(n);if(o)throw new Error(`headline mentions "${o}" \u2014 the product changelog never carries business, security/tenancy or internal-ops items; rewrite it and re-publish.`)}if(!r.length)throw new Error("no `- ` bullets found \u2014 an entry is a bullet list, optionally under a `# headline`");if(r.length>ZT)throw new Error(`${r.length} bullets \u2014 over the ${ZT}-bullet cap; group related changes into one line`);return{title:n||null,bullets:r}}async function xL(e,{repos:t=Mh()}={}){let n=new Set(t);return(await Xr()).filter(r=>r.state==="merged"&&(r.resolvedAt??0)>=e&&n.has(r.repo)).sort((r,o)=>(r.resolvedAt??0)-(o.resolvedAt??0)).map(r=>({repo:r.repo,number:r.number,title:r.title||null,url:r.url||null,headRef:r.headRef||null,mergedAt:r.resolvedAt??null,excluded:yL({title:r.title,headRef:r.headRef})}))}async function rE(e,t){let n=await xL(e,t);return{prs:n.filter(r=>!r.excluded),excluded:n.filter(r=>r.excluded)}}async function oE(e,{md:t,day:n=null}){let r=kL(t),o=n==null||n===""?hL():String(n);if(!tE.test(o)||Number.isNaN(Date.parse(o)))throw new Error(`invalid day "${n}" \u2014 expected YYYY-MM-DD`);let s=await _({id:e.id,cwd:e.cwd},{type:"changelog.published",actor:"agent",source:"orchestrator",boxId:e.leadBox||null,payload:{ts:Date.now(),day:o,title:r.title,bullets:r.bullets}});return{day:o,title:r.title,bullets:r.bullets,eventId:s.id}}async function sE(e,{day:t}){let n=String(t||"");if(!tE.test(n)||Number.isNaN(Date.parse(n)))throw new Error(`invalid day "${t}" \u2014 expected YYYY-MM-DD`);let r=await _({id:e.id,cwd:e.cwd},{type:"changelog.published",actor:"agent",source:"orchestrator",boxId:e.leadBox||null,payload:{ts:Date.now(),day:n,title:null,bullets:[],retract:!0}});return{day:n,retracted:!0,eventId:r.id}}ns();wn();ss();ue();ns();Qe();fr();wn();Ca();rl();Ba();import{execFile as SL}from"node:child_process";import{promisify as vL}from"node:util";var Ph=vL(SL),aE=3e4,TL=30*6e4,EL=aE,AL=10*6e4,_L=10080*6e4,IL=60*6e4,RL=8,$L=1440*6e4,OL=3,iE="number,url,title,headRefName,headRefOid,state,mergedAt,closedAt",Nh=60*6e4,CL=15*6e4,ML=9e4,NL=1440*6e4,yu=new Map,bu=new Map,PL=/could not resolve|not found|no pull requests?/i,DL=e=>PL.test(String(e?.message||e||""));function BL(e,t){return[e.ciFix?.delegatedAt,e.reconcile?.delegatedAt,e.ciFixAwait?.since,e.reconcileAwait?.since].some(n=>n&&t-n<Nh)}var cE={fast:EL,slow:AL,decay:IL};function lE(e,t){return e.armedAt&&t-e.armedAt<TL||BL(e,t)||uE(e,t,{grace:0})?"fast":t-(e.firstSeen||0)>_L?"decay":"slow"}function jL(e,t){return cE[lE(e,t)]}function Oi(e,t,n,r){let o=e.lanes?.get(Q(t.repo,t.number))||{};return nl({change:n,repo:t.repo,number:Number(t.number),githubAt:r||null,lane:o.lane||null,intervalMs:o.intervalMs||null,source:"watch"})}async function LL(e,t){yn("watch");try{let{stdout:n}=await Ph("gh",["pr","view",String(t),"--repo",e,"--json",iE],{timeout:3e4,maxBuffer:4194304,env:{...process.env,...await qt({slug:e})}});return JSON.parse(n||"null")}catch(n){throw lr(n)&&ur(n),n}}async function FL(e){yn("watch");try{let{stdout:t}=await Ph("gh",["pr","list","--repo",e,"--state","all","--limit","100","--json",iE],{timeout:3e4,maxBuffer:8388608,env:{...process.env,...await qt({slug:e})}}),n=new Map;for(let r of JSON.parse(t||"[]"))n.set(Number(r.number),r);return n}catch(t){throw lr(t)&&ur(t),t}}async function UL(){let e=new Map;for(let t of await ae().catch(()=>[]))e.set(t.id,t);return e}async function HL(e,t){await _({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"merged",...t}})}async function WL(e,t){let n=await Qr(e);return n?es(n,t):null}async function qL(e,t,n){let r=await Qr(e);if(!r)throw new Error(`no local checkout for ${e}`);return ts(r,t,{method:n})}async function KL(e,t){let n=await Qr(e);if(!n)throw new Error(`no local checkout for ${e}`);return Pa(n,t)}async function GL(e,t){await _({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"auto-canceled",...t}})}async function Os(e,t,n,r,o){if(!await r.disarm(e.repo,e.number).catch(()=>null))return;let a=n.get(e.trackId);a&&await r.emitDisarmed(a,{number:Number(e.number),url:t?.url||e.url,title:t?.title||e.title,branch:t?.headRefName||e.headRef,repo:e.repo,reason:o}).catch(()=>{})}var VL=10*6e4;async function zL(e,t,n){let r=e.autoMerge?.armedAt||0;if(r&&(n.now??Date.now())-r>$L){await Os(e,null,t,n,"auto-merge expired \u2014 checks never settled within 24h");return}let o=await n.detail(e.repo,e.number).catch(()=>null);if(!o)return;if(o.checks.failed>0){let a=o.checks.failing.map(i=>i.name).join(", ");await Os(e,o,t,n,`check${o.checks.failed===1?"":"s"} failed: ${a}`);return}if(o.mergeable==="CONFLICTING"){await Os(e,o,t,n,`conflicts with ${o.baseRefName}`);return}if(!o.checks.total){let a=Math.max(e.autoMerge?.armedAt||0,Date.parse(o.updatedAt||"")||0);if((n.now??Date.now())-a<VL)return;await Os(e,o,t,n,o.checks.unavailable?"this token can't read the checks":"no CI checks appeared");return}if(o.checks.pending>0||o.mergeable==="UNKNOWN"||o.mergeStateStatus==="UNKNOWN"||o.isDraft)return;let s=await n.lookup(e.repo,e.number).catch(()=>null);if(s?.autoMerge){if(o.mergeStateStatus==="BEHIND"){try{await n.updateBranch(e.repo,e.number)}catch(a){let i=String(a?.message||a).trim();/no new commits|already up.to.date/i.test(i)||await Os(e,o,t,n,i||`couldn't update with ${o.baseRefName}`)}return}try{await n.merge(e.repo,e.number,s.autoMerge.method||"merge")}catch(a){if(/already merged|not open|is closed/i.test(String(a?.message||a)))return;await Os(e,o,t,n,String(a?.message||a).trim()||"merge failed");return}await dE(e,{...o,state:"MERGED"},t,n,{change:"auto-merged",githubAt:o.checks.settledAt||null})}}async function Cs(e,t,n){await _({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:t,...n}})}async function JL(e,t){try{return await Ph("git",["-C",e.cwd,"cat-file","-e",`${t}^{commit}`],{timeout:1e4}),!0}catch{return!1}}async function $i(e,t,n,r=()=>!0){return(await L(e).catch(()=>[])).some(s=>s.type==="pr.state.changed"&&s.payload?.change===t&&s.payload?.number===Number(n)&&r(s))}var Ms=(e,t)=>({number:Number(e.number),url:t?.url||e.url,title:t?.title||e.title,branch:t?.headRefName||e.headRef,repo:e.repo});function uE(e,t,{grace:n=ML}={}){if(e.announced!==!1)return!1;let r=t-(e.firstSeen||0);return r>=n&&r<=NL}async function YL(e,t,n,r){let o=r.now??Date.now();if(!uE(e,o))return!1;let s=n.get(e.trackId)||null;if(!s||s.archivedAt||s.transferredTo)return!1;let a=(s.boxes||[]).find(f=>f.name===s.leadBox);return await(r.midTurn??eo)(s.leadBox,a?.agent).catch(()=>!1)?!1:(await L(s).catch(()=>[])).some(f=>f.type==="pr.state.changed"&&f.payload?.number===Number(e.number))?(await(r.claim??hn)(e.repo,e.number).catch(()=>null),!1):await(r.claim??hn)(e.repo,e.number).catch(()=>null)?(await Cs(s,"opened",{...Ms(e,t),announcedBy:"watch"}).catch(()=>{}),console.log(`[pr-watch] announced passive link ${e.repo}#${e.number} \u2192 track ${s.id} (no active door claimed it)`),!0):!1}async function XL(e,t,n,r){let o=r.now??Date.now(),s=t.headRefOid||null,a=n.get(e.trackId)||null;if(s&&(e.ciFix?.headSha&&s!==e.ciFix.headSha&&await zc(e.repo,e.number,{headSha:s}).catch(()=>{}),e.reconcile?.headSha&&s!==e.reconcile.headSha&&await Yc(e.repo,e.number,{headSha:s}).catch(()=>{})),s&&s!==e.lastHeadSha){let i=!e.lastHeadSha,c=!!(e.ciFix||e.reconcile||e.ciFixAwait||e.reconcileAwait),l=!!e.baseFoldAt&&o-e.baseFoldAt<CL;await qk(e.repo,e.number,s).catch(()=>{}),e.baseFoldAt&&await Wk(e.repo,e.number).catch(()=>{}),!i&&!c&&!l&&a&&!await r.localHasCommit(a,s).catch(()=>!1)&&!await $i(a,"pushed",e.number,f=>f.payload?.sha===s)&&await Cs(a,"pushed",{...Ms(e,t),sha:s}).catch(()=>{})}if(e.ciFixAwait)if(o-(e.ciFixAwait.since||0)>Nh)await Jc(e.repo,e.number).catch(()=>{});else{let i=await r.detail(e.repo,e.number).catch(()=>null);if(i?.checks){if(i.checks.failed>0)await Jc(e.repo,e.number).catch(()=>{});else if(i.checks.total>0&&i.checks.pending===0){let c=Oi(r,e,"ci-fixed",i.checks.settledAt||null),l=e.ciFixAwait.since||0;a&&!await $i(a,"ci-fixed",e.number,u=>(u.payload?.ts||0)>=l)&&await Cs(a,"ci-fixed",{...Ms(e,t),sha:s,delegated:!0,passed:i.checks.passed,githubAt:c.githubAt,latencyMs:c.latencyMs,lane:c.lane}).catch(()=>{}),await Jc(e.repo,e.number).catch(()=>{})}}}if(e.reconcileAwait)if(o-(e.reconcileAwait.since||0)>Nh)await Xc(e.repo,e.number).catch(()=>{});else{let i=await r.detail(e.repo,e.number).catch(()=>null);if(i){if(i.mergeable==="CONFLICTING")await Xc(e.repo,e.number).catch(()=>{});else if(i.mergeable==="MERGEABLE"){Oi(r,e,"reconciled",null);let c=e.reconcileAwait.since||0;a&&!await $i(a,"reconciled",e.number,l=>(l.payload?.ts||0)>=c)&&await Cs(a,"reconciled",{...Ms(e,t),sha:s,delegated:!0,base:i.baseRefName||null}).catch(()=>{}),await Xc(e.repo,e.number).catch(()=>{})}}}}async function ZL(e,t,n,r){let o=Oi(r,e,"closed",Date.parse(t?.closedAt||"")||null),s=n.get(e.trackId);s&&!await $i(s,"closed",e.number)&&await Cs(s,"closed",{...Ms(e,t),githubAt:o.githubAt,latencyMs:o.latencyMs,lane:o.lane}).catch(()=>{}),await r.notifyIfResolved(e.repo,e.number,"closed").catch(()=>{}),await r.mark(e.repo,e.number,"closed").catch(()=>{})}async function QL(e,t,n){Oi(n,e,"lost",null);let r=t.get(e.trackId);r&&!await $i(r,"lost",e.number)&&await Cs(r,"lost",Ms(e,null)).catch(()=>{}),await n.notifyIfResolved(e.repo,e.number,"lost").catch(()=>{}),await n.mark(e.repo,e.number,"lost").catch(()=>{})}async function dE(e,t,n,r,o={}){let s=Oi(r,e,o.change||"merged",o.githubAt??(Date.parse(t.mergedAt||"")||null)),a=n.get(e.trackId);a&&((await L(a).catch(()=>[])).some(l=>l.type==="pr.state.changed"&&l.payload?.change==="merged"&&l.payload?.number===Number(e.number))||await r.emitMerged(a,{number:Number(e.number),url:t.url||e.url,title:t.title||e.title,branch:t.headRefName||e.headRef,repo:e.repo,githubAt:s.githubAt,latencyMs:s.latencyMs,lane:s.lane}).catch(()=>{})),await r.notifyIfArmed(e.repo,e.number).catch(()=>{}),await r.archiveIfArmed(e.repo,e.number).catch(()=>{}),await r.mark(e.repo,e.number,"merged").catch(()=>{})}async function eF(e={}){let{now:t=Date.now(),auth:n=Wf,view:r=LL,list:o=FL,links:s=Vk,trackMap:a=UL,emitMerged:i=HL,mark:c=ir,archiveIfArmed:l=kn,notifyIfArmed:u=xn,notifyIfResolved:f=Bl,batchThreshold:d=OL,detail:p=WL,merge:m=qL,updateBranch:h=KL,lookup:g=qe,disarm:x=Oa,emitDisarmed:k=GL,localHasCommit:E=JL,claim:I=hn,midTurn:M=eo}=e;if(!(await n().catch(()=>null))?.authenticated||el()>0)return 0;let T=(await s().catch(()=>[])).filter(U=>t-(yu.get(Q(U.repo,U.number))||0)>=jL(U,t));if(!T.length)return 0;let j=Date.now(),Z=new Map,fe=new Map;for(let U of T){let pe=lE(U,t);Z.set(Q(U.repo,U.number),{lane:pe,intervalMs:cE[pe]}),yu.set(Q(U.repo,U.number),t),fe.has(U.repo)||fe.set(U.repo,[]),fe.get(U.repo).push(U)}let ie=await a().catch(()=>new Map),D={now:t,lanes:Z,emitMerged:i,mark:c,archiveIfArmed:l,notifyIfArmed:u,notifyIfResolved:f,detail:p,merge:m,updateBranch:h,lookup:g,disarm:x,emitDisarmed:k,localHasCommit:E,claim:I,midTurn:M};for(let[U,pe]of fe){let Se,He=new Set;if(pe.length>d)Se=await o(U).catch(()=>null);else{Se=new Map;for(let le of pe)try{let q=await r(U,le.number);q?.number!=null&&Se.set(Number(q.number),q)}catch(q){DL(q)&&He.add(Q(le.repo,le.number))}}if(Se)for(let le of pe){let q=Q(le.repo,le.number),J=Se.get(Number(le.number));if(!J){if(He.has(q)){let ee=(bu.get(q)||0)+1;bu.set(q,ee),ee>=RL&&(await QL(le,ie,D),bu.delete(q),yu.delete(q))}continue}bu.delete(q),J.state==="MERGED"||J.state==="CLOSED"?(J.state==="MERGED"?await dE(le,J,ie,D):await ZL(le,J,ie,D),yu.delete(q)):(await YL(le,J,ie,D).catch(()=>{}),await XL(le,J,ie,D).catch(()=>{}),le.autoMerge&&await zL(le,ie,D).catch(()=>{}))}}let R={};for(let{lane:U}of Z.values())R[U]=(R[U]||0)+1;return console.log(`[pr-watch] probed ${T.length} link(s) (${Object.entries(R).map(([U,pe])=>`${U} ${pe}`).join(", ")}) in ${Date.now()-j}ms`),T.length}function fE(){let e=!1;setInterval(async()=>{if(!e){e=!0;try{await eF()}catch{}finally{e=!1}}},aE)}ue();wn();Un();fr();function pE(e){return(e?.checks?.failed??0)>0?"red":e?.mergeable==="CONFLICTING"?"conflict":e?.mergeStateStatus==="BEHIND"?"behind":null}function tF(e){return!(!e?.checks||e.checks.pending>0||e.mergeabilityPending||e.mergeable==="UNKNOWN"||e.mergeStateStatus==="UNKNOWN")}var nF=new Set(["merged","closed","lost"]);function rF(e,t){if(!e?.blocked)return null;let n=pE(t);if(e.blocked==="red")return t.checks.failed===0&&t.checks.total>0?{change:"ci-fixed",reason:"red"}:null;if(e.blocked==="conflict")return t.mergeable==="MERGEABLE"&&n!=="red"?{change:"reconciled",reason:"conflict"}:null;if(e.blocked==="behind"){let r=t.headSha??null;return n===null&&r&&e.sha&&r!==e.sha?{change:"reconciled",reason:"behind"}:null}return null}function oF(e,t){return e.autoMerge?!0:t==="ci-fixed"?!!(e.ciFix||e.ciFixAwait):t==="reconciled"?!!(e.reconcile||e.reconcileAwait):!1}async function sF(e,t,n,r,o){return(await L(e).catch(()=>[])).some(a=>{if(a.type!=="pr.state.changed"||a.payload?.number!==Number(n))return!1;let i=a.payload?.change;return i===t?a.payload?.sha&&r?a.payload.sha===r:(a.payload?.ts||0)>=o:i==="pushed"&&!!r&&a.payload?.sha===r})}async function aF(e,t,n){await _({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:t,...n}})}async function mE(e,t={}){let{now:n=Date.now(),slugOf:r=me,lookup:o=qe,note:s=Kk,tracks:a=async()=>(await ae()).filter(f=>!f.archivedAt&&!f.transferredTo),asked:i=sF,emitChange:c=aF}=t,l=[],u=null;for(let f of e??[]){if(!f?.prs?.length)continue;let d=await r(f.path).catch(()=>null);if(d)for(let p of f.prs)try{if(!tF(p))continue;let m=await o(d,p.number).catch(()=>null);if(!m?.trackId||nF.has(m.state))continue;let{prev:h}=await s(d,p.number,{blocked:pE(p),sha:p.headSha??null,at:n});if(!h)continue;let g=rF(h,p);if(!g||oF(m,g.change))continue;u??=new Map((await a()).map(I=>[I.id,I]));let x=u.get(m.trackId);if(!x)continue;let k=p.headSha??null;if(await i(x,g.change,p.number,k,h.at||0))continue;let E={number:Number(p.number),url:p.url||m.url,title:p.title||m.title,branch:p.headRefName||m.headRef,repo:d,sha:k,delegated:!1,reason:g.reason};g.change==="ci-fixed"?E.passed=p.checks.passed:E.base=p.baseRefName||null,await c(x,g.change,E),l.push({change:g.change,number:p.number,reason:g.reason})}catch{}}return l}tt();ue();fr();import{randomUUID as iF}from"node:crypto";var cF=2e4,hE=3,Ns=new Map,Dh=new Set;async function wE(e,t,n){let r=await n(e).catch(()=>[]),o=null;for(let s of r)s.type==="box.fullscreen.detected"&&s.boxId===t?o=s.payload?.offerId||null:s.type==="box.fullscreen.answered"&&o&&s.payload?.offerId===o&&(o=null);return o}async function lF(e={}){let{sessions:t=null,tracks:n=null,append:r=_,read:o=L,now:s=Date.now()}=e;if(process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1")return;let a,i;try{a=t??await Ot(),i=n??await ae()}catch{return}let c=new Map(a.map(u=>[u.name,u])),l=new Set;for(let u of i){if(u.archivedAt||u.transferredTo||!u.leadBox)continue;let f=(u.boxes||[]).find(p=>p.name===u.leadBox);if(!f||f.agent!=="claude"||f.state!=="live")continue;let d=c.get(f.name);if(d)if(l.add(f.name),d.alternateOn){let p=(Ns.get(f.name)||0)+1;Ns.set(f.name,p),p===hE&&(Dh.add(f.name),await wE(u,f.name,o)||await r(u,{type:"box.fullscreen.detected",actor:"system",source:"orchestrator",boxId:f.name,provider:f.agent,payload:{ts:s,offerId:iF(),box:f.name,agent:f.agent}}).catch(()=>{}))}else{let p=(Ns.get(f.name)||0)>=hE;if(Ns.delete(f.name),p||!Dh.has(f.name)){Dh.add(f.name);let m=await wE(u,f.name,o);m&&await r(u,{type:"box.fullscreen.answered",actor:"system",source:"orchestrator",boxId:f.name,provider:f.agent,payload:{ts:s,offerId:m,action:"cleared"}}).catch(()=>{})}}}for(let u of[...Ns.keys()])l.has(u)||Ns.delete(u)}var Ci=null,Bh=!1;function gE(){return Ci?()=>{}:(Ci=setInterval(()=>{Bh||(Bh=!0,lF().catch(()=>{}).finally(()=>{Bh=!1}))},cF),Ci.unref?.(),()=>{clearInterval(Ci),Ci=null})}Yo();Ep();ue();ns();ss();Yo();import{randomUUID as uF}from"node:crypto";async function dF(){let e=await Promise.resolve().then(()=>(fr(),cv));return{sayToLead:e.sayToLead,queueShipCompleteNotify:e.queueShipCompleteNotify}}var jh={listRepoPrs:Vt,readEvents:L,appendEvent:_,sayDeps:dF,currentBranch:rs};async function fF(e,t=jh,{branch:n=null}={}){if(!e?.cwd)return null;let r=n||await(t.currentBranch??rs)(e.workspace?.kind==="multi"?null:e.cwd).catch(()=>null)||e?.workspace?.branch;if(!r)return null;let o;try{o=await t.listRepoPrs(e.cwd,{caller:"pr-exists"})}catch{return null}let s=(o||[]).find(a=>a.headRefName===r);return s?{number:s.number,url:s.url??null,title:s.title??null}:null}async function Lh(e,t,{actions:n,notify:r=!1}={},o=jh){let s=t?.payload||{};if(!Array.isArray(n)||!n.includes("pr")||s.toPr||Array.isArray(s.repos)&&s.repos.length||!s.branch)return null;let a=await fF(e,o,{branch:s.branch});if(!a)return null;let i={id:e.id,cwd:e.cwd};await o.appendEvent(i,{type:"pr.offer.answered",actor:"user",source:"orchestrator",boxId:t.boxId,payload:{ts:Date.now(),offerId:s.offerId,action:"pr-exists",actions:n,...r?{notify:!0}:{},existingPr:{number:a.number}}});let c=uF();return await o.appendEvent(i,{type:"pr.exists.offered",actor:"system",source:"orchestrator",boxId:t.boxId,payload:{ts:Date.now(),offerId:c,srcOfferId:s.offerId??null,branch:s.branch,base:s.base??null,pr:a,actions:n,...r?{notify:!0}:{},offeredRebase:Array.isArray(s.offered)&&s.offered.includes("rebase")}}),{offerId:c,pr:a}}async function Fh(e,{offerId:t,choice:n}={},r=jh){if(!t)throw new Error("offerId required");if(!["push","new","dismiss"].includes(n))throw new Error('choice "push" | "new" | "dismiss" required');let o=await r.readEvents(e),s=o.find(u=>u.type==="pr.exists.offered"&&u.payload?.offerId===t);if(!s)throw new Error("unknown offer");if(o.some(u=>u.type==="pr.exists.answered"&&u.payload?.offerId===t))throw new Error("offer already answered");let a=s.payload||{},i=Array.isArray(a.actions)&&a.actions.length?a.actions:["commit","push","pr"],c=null,l=null;if(n==="push"){let{sayToLead:u}=await r.sayDeps();l=zo.filter(f=>f!=="pr"&&(i.includes(f)||f==="push")),c=await u(e.id,Jo(l,{branch:a.branch??null,base:a.base??null,toPr:{number:a.pr?.number??null},offeredRebase:a.offeredRebase===!0}),{kind:"push-go"})}else if(n==="new"){let{sayToLead:u}=await r.sayDeps();l=i,c=await u(e.id,Mk(i,{branch:a.branch??null,base:a.base??null,prNumber:a.pr?.number??null,offeredRebase:a.offeredRebase===!0}),{kind:"pr-go"})}if(await r.appendEvent({id:e.id,cwd:e.cwd},{type:"pr.exists.answered",actor:"user",source:"orchestrator",boxId:s.boxId,payload:{ts:Date.now(),offerId:t,choice:n}}),n!=="dismiss"&&a.notify===!0){let{queueShipCompleteNotify:u}=await r.sayDeps();u(e.id,{actions:l})}return{say:c,choice:n}}import Bn from"node:fs/promises";import Ps from"node:path";import TE from"node:os";import yE from"node:fs/promises";import ku from"node:path";import{execFile as pF}from"node:child_process";import{promisify as mF}from"node:util";import{fileURLToPath as hF}from"node:url";var wF=mF(pF),kE=ku.dirname(hF(import.meta.url)),gF=ku.resolve(kE,"..","..","client","dist"),yF="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",bF=new Map([...yF].map((e,t)=>[e,t]));function kF(e){let t=[],n=0,r=0;for(let o of e){let s=bF.get(o);if(s===void 0)return t;n+=(s&31)<<r,s&32?r+=5:(t.push(n&1?-(n>>>1):n>>>1),n=0,r=0)}return t}function xF(e){let t=[],n=0,r=0,o=0;for(let s of e.split(";")){let a=[],i=0;if(s)for(let c of s.split(",")){let l=kF(c);l.length!==0&&(i+=l[0],l.length>=4&&(n+=l[1],r+=l[2],o+=l[3],a.push([i,n,r,o])))}t.push(a)}return t}function SF(e,t){if(!e||e.length===0||e[0][0]>t)return null;let n=0,r=e.length-1;for(;n<r;){let o=n+r+1>>1;e[o][0]<=t?n=o:r=o-1}return e[n]}var bE=new Map;async function vF(e){let t;try{t=await yE.stat(e)}catch{return null}let n=bE.get(e);if(n&&n.mtimeMs===t.mtimeMs)return n;try{let r=JSON.parse(await yE.readFile(e,"utf8")),o={mtimeMs:t.mtimeMs,sources:r.sources||[],lines:xF(r.mappings||"")};return bE.set(e,o),o}catch{return null}}var Uh=null;function TF(){return Uh||(Uh=process.env.BOSTRAT_RELEASE?Promise.resolve(process.env.BOSTRAT_RELEASE):wF("git",["rev-parse","--short","HEAD"],{cwd:ku.resolve(kE,"..","..")}).then(e=>e.stdout.trim()).catch(()=>null)),Uh}var EF=/(?:https?:\/\/[^\s()]*)?\/assets\/([^\s()/]+\.js):(\d+):(\d+)/g;async function AF(e,{distDir:t=gF}={}){let n=[],r=0,o=!1;for(let s of e.matchAll(EF)){let[a,i,c,l]=s,u=await vF(ku.join(t,"assets",`${i}.map`)),f=u?SF(u.lines[Number(c)-1],Number(l)-1):null;if(n.push(e.slice(r,s.index)),f&&u.sources[f[1]]){let d=u.sources[f[1]].replace(/^(\.\.\/)+/,"");n.push(`${d}:${f[2]+1}:${f[3]+1}`),o=!0}else n.push(a);r=s.index+a.length}return n.push(e.slice(r)),{stack:n.join(""),symbolicated:o}}async function xE(e,t={}){try{if(!e?.error?.stack||!e.release||e.release==="unknown")return e;let n=t.release??await TF();if(!n||e.release!==n)return e;let{stack:r,symbolicated:o}=await AF(e.error.stack,t);o&&(e.error.stack=r,e.error.symbolicated=!0)}catch{}return e}var _F=()=>process.env.BOSTRAT_STATE_DIR||Ps.join(process.env.HOME||TE.tmpdir(),".bostrat"),Rr=()=>Ps.join(_F(),"telemetry"),EE=()=>Ps.join(Rr(),".relay-offsets.json"),IF=50,RF=14,$F=3e4,SE=500,bt=(e,t)=>typeof e=="string"?e.slice(0,t):"";function OF(e,t){if(!e||typeof e!="object")return null;let n=bt(e.name,64);if(!n)return null;let r=Number.isFinite(e.ts)?e.ts:t,o={name:n,ts:Math.abs(r-t)<168*3600*1e3?r:t,receivedAt:t,anonId:bt(e.anonId,64),sessionId:bt(e.sessionId,64),userId:bt(e.userId,64),release:bt(e.release,64),appVersion:bt(e.appVersion,32),route:bt(e.route,128),deviceClass:e.deviceClass==="phone"||e.deviceClass==="desktop"?e.deviceClass:""};return e.props&&typeof e.props=="object"&&!Array.isArray(e.props)&&(JSON.stringify(e.props).length<=8192?o.props=e.props:o.props={clamped:!0}),e.error&&typeof e.error=="object"&&(o.error={kind:bt(e.error.kind,256),message:bt(e.error.message,8192),stack:bt(e.error.stack,32768),fingerprint:bt(e.error.fingerprint,64)}),Array.isArray(e.breadcrumbs)&&(o.breadcrumbs=e.breadcrumbs.slice(-50).map(s=>({t:Number.isFinite(s?.t)?s.t:0,n:bt(s?.n,64),r:bt(s?.r,128)}))),o}var AE=e=>new Date(e).toISOString().slice(0,10),vE=0;async function _E(e,t=Date.now()){let r=(Array.isArray(e?.events)?e.events.slice(0,IF):[]).map(s=>OF(s,t)).filter(Boolean);if(!r.length)return 0;for(let s of r)s.error?.stack&&await xE(s);await Bn.mkdir(Rr(),{recursive:!0});let o=Ps.join(Rr(),`${AE(t)}.ndjson`);return await Bn.appendFile(o,r.map(s=>JSON.stringify(s)+`
592
- `).join(""),"utf8"),t-vE>6*3600*1e3&&(vE=t,CF(t).catch(()=>{})),r.length}async function CF(e=Date.now()){let t=AE(e-RF*24*3600*1e3),n=[];try{n=await Bn.readdir(Rr())}catch{return}let r=n.filter(s=>s.endsWith(".ndjson")&&s.slice(0,10)<t);if(!r.length)return;for(let s of r)await Bn.rm(Ps.join(Rr(),s),{force:!0});let o=await RE();for(let s of r)delete o[s];await $E(o)}var xu=new Map;function IE(e,t=Date.now()){let n=e||"unknown",r=xu.get(n);return r||(xu.size>512&&xu.clear(),r={tokens:40,at:t},xu.set(n,r)),r.tokens=Math.min(40,r.tokens+(t-r.at)/6e4*20),r.at=t,r.tokens<1?!1:(r.tokens-=1,!0)}async function RE(){try{return JSON.parse(await Bn.readFile(EE(),"utf8"))||{}}catch{return{}}}async function $E(e){await Bn.mkdir(Rr(),{recursive:!0}),await Bn.writeFile(EE(),JSON.stringify(e),"utf8")}function MF(e,{env:t,host:n}={}){let r=e.name==="app.error"&&e.error,o={};for(let[a,i]of[["event",e.name],["route",e.route],["session",e.sessionId],["anon",e.anonId],["user",e.userId],["release",e.release],["appVersion",e.appVersion],["device",e.deviceClass]])i&&(o[a]=i);let s={timestamp:new Date(e.ts).toISOString(),service:"bostrat-client",source:"treetop-js",env:t||process.env.BOSTRAT_ENV||"pi",host:n||TE.hostname(),level:r?"error":"info",message:r?`${e.error.kind||"Error"}: ${e.error.message||"(no message)"}`.slice(0,8192):e.name,tags:o,attributes:{...e.props?{props:e.props}:{},receivedAt:e.receivedAt}};return r&&(s.error={kind:e.error.kind,message:e.error.message,stack:e.error.stack},e.error.fingerprint&&(s.fingerprint=e.error.fingerprint),e.error.symbolicated&&(s.attributes.symbolicated=!0),e.breadcrumbs&&(s.attributes.breadcrumbs=e.breadcrumbs)),s}async function NF({fetchImpl:e=fetch}={}){let t=await Iv();if(!t)return{sent:0,disabled:!0};let n;try{n=(await Bn.readdir(Rr())).filter(s=>s.endsWith(".ndjson")).sort()}catch{return{sent:0,disabled:!1}}let r=await RE(),o=0;for(let s of n){let a=Ps.join(Rr(),s),i=r[s]||0,c;try{let d=await Bn.open(a,"r");try{let p=(await d.stat()).size;if(p<=i)continue;c=Buffer.alloc(p-i),await d.read(c,0,c.length,i)}finally{await d.close()}}catch{continue}let l=c.lastIndexOf(10);if(l<0)continue;let u=c.toString("utf8",0,l+1).split(`
593
- `).filter(Boolean),f=[];for(let d of u)try{f.push(JSON.parse(d))}catch{}for(let d=0;d<f.length;d+=SE){let p=f.slice(d,d+SE).map(h=>MF(h)),m=await e(`${t.url.replace(/\/$/,"")}/v1/logs`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${t.ingestKey}`},body:JSON.stringify({events:p})}).catch(()=>null);if(!m||!m.ok)return{sent:o,disabled:!1};o+=p.length}r[s]=i+l+1,await $E(r)}return{sent:o,disabled:!1}}var Hh=null,Wh=!1;function OE(){Hh||(Hh=setInterval(async()=>{if(!Wh){Wh=!0;try{await NF()}catch(e){console.error("[telemetry] relay failed:",e?.message||e)}finally{Wh=!1}}},$F),Hh.unref?.())}import vu from"node:fs/promises";import DE from"node:path";import PF from"node:os";var BE=()=>process.env.BOSTRAT_STATE_DIR||DE.join(process.env.HOME||PF.tmpdir(),".bostrat"),jE=()=>DE.join(BE(),"dictation-glossary.json"),DF=100,BF=500,jF=["bostrat","globopi","codex","tmux","worktree","Deepgram","Linear","Firecracker","Tigris","WireGuard","misous","postyx","cedar","gerbil","Anthropic","Opus","Haiku","Sonnet","keyterm","monorepo","dogfood"],Tu=null,qh=null,Kh=Promise.resolve();function CE(){let e={},t=Date.now();for(let n of jF)e[n.toLowerCase()]={term:n,count:1,lastUsed:t,source:"seed"};return e}async function LE(){return Tu||(qh??=vu.readFile(jE(),"utf8").then(e=>JSON.parse(e)?.terms??CE()).catch(()=>CE()).then(e=>Tu=e).finally(()=>qh=null),qh)}async function ME(){let e=JSON.stringify({terms:Tu},null,2),t=jE(),n=`${t}.${process.pid}.tmp`;await vu.mkdir(BE(),{recursive:!0}),await vu.writeFile(n,e),await vu.rename(n,t)}function LF(){return Kh=Kh.then(ME,ME),Kh.catch(()=>{})}async function Gh(){return Object.values(await LE()).sort((t,n)=>n.count-t.count||n.lastUsed-t.lastUsed)}var FF=e=>Math.max(1,Math.ceil(e.length/4));async function UF(){let e=[],t=0;for(let{term:n}of await Gh()){let r=FF(n);if(!(t+r>BF)&&(e.push(n),t+=r,e.length>=DF))break}return e}async function HF(e,t){let n=await LE(),r=e.toLowerCase(),o=n[r];n[r]={term:e,count:(o?.count??0)+1,lastUsed:Date.now(),source:o?.source??t}}var NE=e=>(e||"").split(/\s+/).map(t=>t.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"")).filter(Boolean),Su=e=>e.toLowerCase();function PE(e){return!new RegExp("\\p{L}","u").test(e)||e.length<3?!1:/^[a-z]+$/.test(e)?e.length>=4:!0}async function FE(e,t){let n=NE(e),r=NE(t);if(!n.length||!r.length)return[];let o=n.length,s=r.length,a=Array.from({length:o+1},()=>new Array(s+1).fill(0));for(let u=o-1;u>=0;u--)for(let f=s-1;f>=0;f--)a[u][f]=Su(n[u])===Su(r[f])?a[u+1][f+1]+1:Math.max(a[u+1][f],a[u][f+1]);let i=new Set,c=0,l=0;for(;c<o&&l<s;)Su(n[c])===Su(r[l])?(c++,l++):a[c+1][l]>=a[c][l+1]?c++:(PE(r[l])&&i.add(r[l]),l++);for(;l<s;l++)PE(r[l])&&i.add(r[l]);if(!i.size)return[];for(let u of i)await HF(u,"learned");return await LF(),[...i]}var Mi=null;function WF(e,t){let n=null;try{n=JSON.parse(t)}catch{}let r=n?.err_code||n?.error_code||n?.category||"";return e===402||/PAYMENT_REQUIRED/i.test(r)?{status:402,code:"credits_exhausted",persistent:!0,message:"Deepgram credits are exhausted \u2014 dictation is down until you top up at console.deepgram.com or drop a new key into ~/.bostrat/integrations.json."}:e===401||e===403?{status:502,code:"key_invalid",persistent:!0,message:"Deepgram rejected the API key (revoked, or missing ASR scope) \u2014 replace it in ~/.bostrat/integrations.json."}:{status:502,code:"transcription_failed",persistent:!1,message:`Deepgram error ${e}: ${t.slice(0,300)}`}}async function UE(){if(!Mi)return null;let e=await yi();if(!e||e.apiKey.slice(-6)!==Mi.keyTail)return null;let{keyTail:t,...n}=Mi;return n}async function HE(e,t){let n=await yi();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 UF())r.searchParams.append("keyterm",i);let o=await fetch(r,{method:"POST",headers:{Authorization:`Token ${n.apiKey}`,"Content-Type":t||"application/octet-stream"},body:e});if(!o.ok){let i=await o.text().catch(()=>""),c=WF(o.status,i);c.persistent&&(Mi={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 Mi=null,{transcript:(await o.json())?.results?.channels?.[0]?.alternatives?.[0]?.transcript??""}}ue();var Vh={"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 qF(e){if(!e)return null;let t=String(e).trim();if(Vh[t])return t;let n=null;for(let r of Object.keys(Vh))t.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function KF(e,t={}){let n=Vh[qF(e)];if(!n)return 0;let r=0;for(let o of Object.keys(n))r+=(Number(t[o])||0)*n[o];return r/1e6}function GF(e,t){let n=null;try{n=JSON.parse(t)}catch{}let r=n?.error?.code||n?.error?.type||"";return e===429&&/insufficient_quota/i.test(r)?{status:402,code:"credits_exhausted",persistent:!0,message:"The OpenAI account is out of credit \u2014 voice chat is down until you top up at platform.openai.com or drop a new key into ~/.bostrat/integrations.json."}:e===401||e===403?{status:502,code:"key_invalid",persistent:!0,message:"OpenAI rejected the API key (revoked, or missing Realtime access) \u2014 replace it in ~/.bostrat/integrations.json."}:{status:502,code:"mint_failed",persistent:!1,message:`OpenAI realtime session mint failed (${e}): ${t.slice(0,300)}`}}var Ni=null;async function VF(){if(!Ni)return null;let e=await tu();if(!e||e.apiKey.slice(-6)!==Ni.keyTail)return null;let{keyTail:t,...n}=Ni;return n}async function zF(e){let t=await fetch("https://api.openai.com/v1/realtime/client_secrets",{method:"POST",headers:{Authorization:`Bearer ${e.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify({session:{type:"realtime",model:e.model,audio:{output:{voice:e.voice}}}})});if(!t.ok){let o=await t.text().catch(()=>""),s=GF(t.status,o);s.persistent&&(Ni={code:s.code,message:s.message,at:Date.now(),keyTail:e.apiKey.slice(-6)});let a=new Error(s.message);throw a.status=s.status,a.code=s.code,a}Ni=null;let n=await t.json(),r=n?.value??n?.client_secret?.value;if(!r){let o=new Error("OpenAI returned no client secret");throw o.status=502,o.code="mint_failed",o}return{clientSecret:{value:r,expiresAt:n?.expires_at??n?.client_secret?.expires_at??null}}}var JF={openai:zF};async function WE(){let e=await tu();return e?{configured:!0,provider:e.provider,model:e.model,voice:e.voice,problem:await VF()}:{configured:!1}}async function qE(){let e=await tu();if(!e){let n=new Error("Voice chat is not configured \u2014 add openai.apiKey to ~/.bostrat/integrations.json");throw n.status=503,n.code="not_configured",n}let t=await JF[e.provider](e);return{provider:e.provider,model:e.model,voice:e.voice,...t}}async function KE(e,{model:t,usage:n={},seconds:r}={}){let o=c=>Math.max(0,Math.round(Number(c)||0)),s={textIn:o(n.textIn),textInCached:o(n.textInCached),textOut:o(n.textOut),audioIn:o(n.audioIn),audioInCached:o(n.audioInCached),audioOut:o(n.audioOut)},a=KF(t,s),i=await _(e,{type:"cost.recorded",actor:"user",provider:"openai-realtime",payload:{model:t||"unknown",usd:a,tokens:{input:s.textIn+s.audioIn,output:s.textOut+s.audioOut,cacheRead:s.textInCached+s.audioInCached,cacheWrite:0},voice:s,seconds:Math.max(0,Math.round(Number(r)||0)),source:"voice-chat"}});return{usd:a,seq:i.seq}}var XE=ge.dirname(XF(import.meta.url)),GE=Number(process.env.PORT)||3362,Au=Gm(process.env),ZE=Number(process.env.BOSTRAT_AUTO_TRIGGER_PCT)||80,Ds=NT(process.env.BOSTRAT_ALLOW_IPS),Zh=PT(process.env.BOSTRAT_VIEW_FRONT_CIDRS,gu),QE=BT(),eA=process.env.BOSTRAT_ALLOW_LAN_TOKENLESS!=="1",S=Rt();S.disable("x-powered-by");S.use((e,t,n)=>{t.setHeader("x-content-type-options","nosniff"),wu(e.headers.host)||(t.setHeader("x-frame-options","DENY"),t.setHeader("referrer-policy","strict-origin-when-cross-origin")),n()});S.use((e,t,n)=>{if(Ri(e)||Ds.allowed(Ds.clientIp(e))||Zh.allows(e))return n();t.status(403).type("text/plain").send("bostrat: access restricted to the allowlist")});S.use(HT);S.use(FT({token:QE,enforce:eA}));S.use("/api/mocks",Rt.json({limit:"1mb"}));S.use("/api/mocks",Rt.raw({type:"image/png",limit:"24mb"}));S.use("/api/mocks",Rt.raw({type:["video/mp4","video/webm"],limit:"105mb"}));S.use("/api/runbooks",Rt.json({limit:"1mb"}));S.use("/api/tracks/adopt",Rt.json({limit:"1mb"}));S.use("/api/telemetry",Rt.json({limit:"256kb"}));S.use("/api/hook",Rt.json({limit:"2mb"}));S.use("/api/dictation",Rt.raw({type:["audio/*","video/mp4","application/octet-stream"],limit:"32mb"}));S.use("/api/tracks/:id/upload",Rt.raw({type:()=>!0,limit:"25mb"}));S.use(Rt.json({limit:"64kb"}));S.get("/api/health",async(e,t)=>{t.json({ok:!0,tmuxSocket:ft,hostTmuxAlive:await Vn(),autoTriggerPct:ZE})});S.get("/api/sessions",async(e,t)=>{t.json({sessions:await Ot()})});S.post("/api/sessions",async(e,t)=>{let{displayName:n,cwd:r}=e.body||{};if(typeof n!="string")return t.status(400).json({error:"displayName (string) required"});try{let o=await zn(n,r||void 0);t.json({ok:!0,...o})}catch(o){let s=o?.message||String(o),a=/already exists/i.test(s)?409:/must be|invalid/i.test(s)?400:500;t.status(a).json({error:s})}});S.delete("/api/sessions/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!_e(n))return t.status(400).json({error:"invalid session name"});if(!await se(n))return t.status(404).json({error:"session not found"});try{await Ct(n),t.json({ok:!0})}catch(r){t.status(500).json({error:`failed to kill: ${r?.message||r}`})}});S.get("/api/context/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!_e(n))return t.status(400).json({error:"invalid session name"});let r=await se(n);if(!r)return t.status(404).json({error:"session not found"});let o=await aa(r.cwd,r.sessionId);if(!o)return t.json({available:!1,cwd:r.cwd,sessionId:r.sessionId||null});t.json({available:!0,...o})});S.post("/api/handoff/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!_e(n))return t.status(400).json({error:"invalid session name"});try{let r=await Yy(n);t.json({ok:!0,step:r.step,file:r.file,startedAt:r.startedAt})}catch(r){t.status(409).json({error:r?.message||String(r)})}});S.get("/api/handoff/:name",(e,t)=>{let n=decodeURIComponent(e.params.name),r=Mc(n);if(!r)return t.json({running:!1});t.json({running:!r.finishedAt,step:r.step,error:r.error,file:r.file,startedAt:r.startedAt,finishedAt:r.finishedAt})});var VE=10;S.get("/api/idle-guard",async(e,t)=>{try{t.json(Km({tracks:await ae(),views:await yl(),queuedOf:n=>ao(n)}))}catch{t.status(500).json({busy:!0,reasons:["error"]})}});var Ft=lo(),nU=gv({kind:Ft}),Pi=null,ut=()=>Pi&&["auto","prompt","off"].includes(Pi)?Pi:nU,Eu=null;async function rU(e){let t=ut();Pi=e??null;let n=ut();if(t!==n){if(console.log(`[self-update] policy ${t} \u2192 ${n} (${e?"plane row":"node default"})`),n!=="auto"){Bs.cancel();return}Eu&&!gi(await Ss())&&Bs.arm({to:Eu.latest,from:Eu.current,kind:Ft})}}var oU=(()=>{try{return tU(import.meta.url)("../package.json").version||null}catch{return null}})(),Bs=bv({isBusy:async()=>Km({tracks:await ae(),views:await yl(),queuedOf:e=>ao(e)}).busy,onStuck:({to:e,from:t})=>on({current:t,latest:e,installKind:Ft,policy:ut(),status:"stuck"}).catch(()=>{}),onStarted:({to:e,from:t,result:n})=>(n?.ok?on({current:t,latest:e,installKind:Ft,policy:ut(),status:"updating",reason:"auto"}):on({current:t,latest:e,installKind:Ft,policy:ut(),status:"failed",error:n?.reason})).catch(()=>{})});S.get("/api/node/self-update",async(e,t)=>{t.json({installKind:Ft,policy:ut(),policySource:Pi?"plane":"node",current:oU,status:await Ss(),armed:Bs.armed})});S.post("/api/node/self-update",async(e,t)=>{let n=typeof e.body?.to=="string"?e.body.to.trim():"";if(!/^\d+\.\d+\.\d+$/.test(n))return t.status(400).json({error:"body.to must be a release version (X.Y.Z)"});let r=await Jl({to:n,kind:Ft,reason:"manual"});if(r.ok)return Bs.cancel(),on({current:r.from,latest:n,installKind:Ft,policy:ut(),status:"updating",reason:"manual"}).catch(()=>{}),t.json({ok:!0,...r});t.status(409).json({ok:!1,error:r.reason,status:r.status??null})});async function tA(){try{let e=await yv();e&&await on({current:e.from,latest:e.to,installKind:e.kind||Ft,policy:ut(),status:e.status,error:e.error,reason:e.reason})}catch{}}tA();setInterval(tA,3e4).unref();S.get("/api/tracks",async(e,t)=>{let n=(await ae()).filter(s=>!s.transferredTo),r=n.filter(s=>s.archivedAt&&!s.archiving),o=n;if(e.query.archived!=="all"&&r.length>VE){let s=new Set([...r].sort((a,i)=>(i.archivedAt||0)-(a.archivedAt||0)).slice(0,VE).map(a=>a.id));o=n.filter(a=>!a.archivedAt||a.archiving||s.has(a.id))}t.json({tracks:o,archivedTotal:r.length,agents:ii,agentAvailability:await Ol(),tickets:await Hv()})});S.get("/api/cost",async(e,t)=>{try{let n=await ae();e.query.track&&(n=n.filter(o=>o.id===e.query.track));let r=await hT(n);if(r.cursorUsage=lp(),e.query.format==="text")return t.type("text/plain").send(wT(r));t.json(r)}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/usage/roundup",async(e,t)=>{try{t.json(await bT(await ae(),{window:e.query.window,from:e.query.from,to:e.query.to}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/usage/spend",async(e,t)=>{try{let n=await TT(await ae(),{window:e.query.window,from:e.query.from,to:e.query.to});n.cursorUsage=lp(),n.subscriptionMonthlyUsd=Number(process.env.BOSTRAT_SUBSCRIPTION_MONTHLY_USD)||null,n.caps=_a(),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/usage/caps",(e,t)=>{t.json(_a())});S.post("/api/usage/caps",async(e,t)=>{try{t.json(await Hc(e.body?.caps??{},{source:"local"}))}catch(n){t.status(400).json({error:n?.message||String(n)})}});S.get("/api/usage/limits",async(e,t)=>{try{let n=e.query.fresh==="1"||e.query.fresh==="true";t.json(await RT(await ae(),{fresh:n}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.post("/api/hook",async(e,t)=>{try{let{mode:n,target:r}=await nw(e.get(Fi),{byToken:dm,legacy:()=>La(e.body?.session_id,e.body?.cwd)});if(n==="refused")return Ls("refused",{reason:"unknown-token",hook:e.body?.hook_event_name}),t.json({ok:!1,error:"unknown hook token"});if(n==="legacy-denied")return Ls("legacy-denied",{reason:"tokenless-denied",hook:e.body?.hook_event_name}),t.status(401).json({ok:!1,error:"tokenless hook ingest is disabled (BOSTRAT_HOOK_LEGACY_DENY)"});n==="token"&&e.body?.session_id&&r.box?.sessionId&&e.body.session_id!==r.box.sessionId&&Ls("mismatch",{track:r.track.id,box:r.box.name}),Ls(n,{track:r?.track?.id,hook:e.body?.hook_event_name,...n==="legacy"?{reason:"tokenless-body-resolved",deny_with:"BOSTRAT_HOOK_LEGACY_DENY=1"}:{}});let o=await uT(e.body||{},()=>r);e.body?.hook_event_name==="Stop"&&r?.box?.cwd&&tc(r.box.cwd),t.json({ok:!0,events:o.length})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});S.post("/api/telemetry",async(e,t)=>{try{if(!IE(Ds.clientIp(e)))return t.json({ok:!0,dropped:!0});let n=await _E(e.body||{});t.json({ok:!0,events:n})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});S.get("/api/repos",async(e,t)=>{try{let n=await cn(),r=new Set((await Promise.all(n.map(a=>me(a.path)))).filter(Boolean).map(a=>a.toLowerCase())),s=((await qs()).repos||[]).filter(a=>!r.has(String(a.slug).toLowerCase())).map(a=>({slug:a.slug,name:a.slug.split("/")[1],branch:a.defaultBranch||null,private:!!a.private,remote:!0}));t.json({repos:[...n,...s]})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/github/token",async(e,t)=>{try{t.json(await Gi(String(e.query.repo||"")))}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});S.get("/api/github/status",(e,t)=>{t.json({configured:Ki(),calls:r0(),latency:i0()})});S.post("/api/github/refresh",(e,t)=>{fw(),t.json({ok:!0})});S.get("/api/gmail/search",async(e,t)=>{try{let n=await OT(String(e.query.q||""),{max:Number(e.query.max)||10});t.json({messages:n})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});S.get("/api/gmail/messages/:id",async(e,t)=>{try{t.json({message:await CT(String(e.params.id))})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});function Qh(e,t,n){let r=e.workspace;return r?.kind==="multi"?(r.repos??[]).some(o=>t&&o?.base===t||n&&o?.repo===n):!r?.base||!t||r.base===t||n&&r.repo===n}async function _u({repo:e=null,number:t=null,branch:n=null}){let r=e?await me(e):null;if(r&&t!=null){let s=await qe(r,t),a=s&&await ne(s.trackId);if(a)return a}if(!n)return null;let o=await ae();return cl(o,n,s=>Qh(s,e,r))}async function nA({repo:e=null,number:t=null,branch:n=null}){let r=await _u({repo:e,number:t,branch:n}).catch(()=>null);if(r&&!r.archivedAt&&!r.transferredTo)return r;if(!n)return null;let o=e?await me(e).catch(()=>null):null,s=await ae();return cl(s,n,a=>!a.archivedAt&&!a.transferredTo&&Qh(a,e,o))}async function Ut(e,{number:t,url:n=null,title:r=null,branch:o=null,repo:s=null,track:a=null,extra:i={}}){let c=a||await _u({repo:s,number:t,branch:o}).catch(()=>null);if(!c)return;let l=i.repo??(s?await me(s).catch(()=>null):null);await _({id:c.id,cwd:c.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",payload:{ts:Date.now(),change:e,number:t,url:n,title:r,branch:o??c.workspace?.branch??null,...l?{repo:l}:{},...i}}).catch(()=>{})}async function sU(e){let t=(await ae()).filter(n=>!n.archivedAt&&!n.transferredTo);for(let n of e??[]){if(!n.prs?.length)continue;let r=await me(n.path);if(r)for(let o of n.prs){if(await qe(r,o.number))continue;let s=await cl(t,o.headRefName,a=>Qh(a,n.path,r));s&&await mt({repo:r,number:o.number,trackId:s.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"})}}}S.get("/api/git/prs",async(e,t)=>{try{let n=await m0();await sU(n.repos).catch(()=>{}),await mE(n.repos).catch(()=>{}),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.post("/api/git/prs/merge",async(e,t)=>{let{repo:n,number:r,method:o,auto:s,update:a,archive:i,notify:c,headRefName:l,title:u,url:f}=e.body||{};try{if(s){let h=o||"merge";if(!Na.has(h))throw new Error(`invalid merge method: ${h}`);let g=Number(r);if(!Number.isInteger(g)||g<=0)throw new Error("invalid PR number");let x=await me((await bn(n)).path);if(!x)throw new Error("repo has no GitHub remote");let k=await _u({repo:n,number:g,branch:l}).catch(()=>null);if(!k)throw new Error("auto-merge needs a Track to watch this PR \u2014 none owns it");if(a&&await Pa(n,g),await mt({repo:x,number:g,trackId:k.id,url:f,headRef:l,title:u,source:"matched"}).catch(()=>{}),!await Ra(x,g,{merge:{method:h}}))throw new Error("couldn't record the auto-merge arm");return await Yr(x,g,i===!0),await $a(x,g,c===!0&&i!==!0),Jt(),await Ut("auto-armed",{number:g,url:f,title:u,branch:l,repo:n,track:k,...a?{extra:{updated:!0}}:{}}),t.json({ok:!0,number:g,auto:!0})}let d=await ts(n,r,{method:o||"squash"});await Ut("merged",{number:d.number,url:f,title:u,branch:l,repo:n});let p=await me(n).catch(()=>null),m=!1;if(p&&(i===!0&&await Yr(p,d.number,!0).catch(()=>{}),c===!0&&i!==!0&&await $a(p,d.number,!0).catch(()=>{}),await xn(p,d.number).catch(()=>{}),m=await kn(p,d.number).catch(()=>!1),await ir(p,d.number,"merged").catch(()=>{})),i===!0&&!m){let h=await _u({repo:n,number:d.number,branch:l}).catch(()=>null);h&&!h.archivedAt&&await io(h.id).catch(()=>{})}t.json(d)}catch(d){let p=d?.message||String(d),m=/invalid|unknown repo|required|needs a Track|no GitHub remote/i.test(p)?400:502;t.status(m).json({error:p})}});S.post("/api/git/prs/disarm-auto",async(e,t)=>{let{repo:n,number:r,headRefName:o,title:s,url:a}=e.body||{};try{let i=Number(r);if(!Number.isInteger(i)||i<=0)throw new Error("invalid PR number");let c=await me((await bn(n)).path).catch(()=>null),l=c?await Oa(c,i).catch(()=>null):null;try{await Gf(n,i)}catch(u){if(!l)throw u}Jt(),await Ut("auto-canceled",{number:i,url:a,title:s,branch:o,repo:n}),t.json({ok:!0,number:i})}catch(i){let c=i?.message||String(i),l=/invalid|unknown repo|required/i.test(c)?400:502;t.status(l).json({error:c})}});S.post("/api/git/prs/merge-all",async(e,t)=>{let{repo:n,method:r}=e.body||{};try{let o=await me(n).catch(()=>null),s=await y0(n,{method:r||"merge",onMerged:a=>{Ut("merged",{number:a.number,url:a.url,title:a.title,branch:a.headRefName,repo:n}),o&&xn(o,a.number).catch(()=>{}).then(()=>kn(o,a.number)).catch(()=>{}).then(()=>ir(o,a.number,"merged")).catch(()=>{})}});t.json(s)}catch(o){let s=o?.message||String(o),a=/already running/i.test(s)?409:/invalid|unknown repo|no PRs ready/i.test(s)?400:502;t.status(a).json({error:s})}});S.get("/api/git/prs/merge-all",(e,t)=>{t.json({jobs:g0()})});S.post("/api/git/prs/merge-track",async(e,t)=>{let{trackId:n,update:r,archive:o,notify:s,method:a}=e.body||{};try{let i=a||"merge";if(!Na.has(i))throw new Error(`invalid merge method: ${i}`);if(!n)return t.status(400).json({error:"trackId required"});let c=await ne(n);if(!c)return t.status(404).json({error:`Track ${n} isn't on this node`});let l=(await Xr()).filter(d=>d.trackId===c.id&&d.state!=="merged"&&d.state!=="closed");if(!l.length)return t.status(409).json({error:"no open PRs on this Track"});for(let d of l)await Yr(d.repo,d.number,o===!0).catch(()=>{}),await $a(d.repo,d.number,s===!0&&o!==!0).catch(()=>{});let u=[],f=[];for(let d of l){let p={repo:d.repo,number:d.number,ok:!0,action:"armed"};u.push(p);try{let m=await Qr(d.repo);if(!m)throw new Error(`no local checkout for ${d.repo}`);let h=await es(m,d.number);f.push({r:p,l:d,repoPath:m,pr:h,plan:h0(h,{update:r!==!1})})}catch(m){p.ok=!1,p.action="failed",p.reason=m?.message||String(m)}}for(let{r:d,l:p,repoPath:m,pr:h,plan:g}of w0(f))try{if(g.action==="skip")d.action="skipped",d.reason=g.reason;else if(g.action==="merge")await ts(m,p.number,{method:i}),await Ut("merged",{number:p.number,url:h.url,title:h.title,branch:h.headRefName,repo:m,track:c}),await xn(p.repo,p.number).catch(()=>{}),await kn(p.repo,p.number).catch(()=>{}),await ir(p.repo,p.number,"merged").catch(()=>{}),d.action="merged";else{if(g.action==="update-arm"&&(await Pa(m,p.number).catch(()=>{}),d.action="updated-armed"),!await Ra(p.repo,p.number,{merge:{method:i}}))throw new Error("couldn't record the auto-merge arm");await Ut("auto-armed",{number:p.number,url:h.url,title:h.title,branch:h.headRefName,repo:m,track:c,...d.action==="updated-armed"?{extra:{updated:!0}}:{}})}}catch(x){d.ok=!1,d.action="failed",d.reason=x?.message||String(x)}if(Jt(),!u.some(d=>d.ok)){if(o===!0)for(let d of l)await Yr(d.repo,d.number,!1).catch(()=>{});if(s===!0&&o!==!0)for(let d of l)await $a(d.repo,d.number,!1).catch(()=>{});return t.status(502).json({error:u.map(d=>`${d.repo}#${d.number}: ${d.reason}`).join("; "),results:u})}t.json({ok:!0,trackId:c.id,results:u})}catch(i){let c=i?.message||String(i),l=/invalid|required/i.test(c)?400:502;t.status(l).json({error:c})}});S.post("/api/git/prs/disarm-track",async(e,t)=>{let{trackId:n}=e.body||{};try{if(!n)return t.status(400).json({error:"trackId required"});let r=await ne(n);if(!r)return t.status(404).json({error:`Track ${n} isn't on this node`});let o=(await Xr()).filter(a=>a.trackId===r.id&&a.state!=="merged"&&a.state!=="closed"),s=[];for(let a of o){let i=await Oa(a.repo,a.number).catch(()=>null),c=await Qr(a.repo).catch(()=>null);c&&await Gf(c,a.number).catch(()=>{}),i&&(await Ut("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}))}Jt(),t.json({ok:!0,trackId:r.id,canceled:s})}catch(r){let o=r?.message||String(r),s=/invalid|required/i.test(o)?400:502;t.status(s).json({error:o})}});S.post("/api/git/prs/open",async(e,t)=>{let{trackId:n,title:r,body:o,base:s,repos:a}=e.body||{};try{if(!n)return t.status(400).json({error:"trackId required"});let i=await ne(n);if(!i)return t.status(404).json({error:`Track ${n} isn't on this node`});if(i.workspace?.kind==="multi"){let u=gt(i.workspace),f,d=Array.isArray(a)?a.filter(Boolean):[];if(d.length)f=d.map(h=>{let g=u.find(x=>x.name===h||x.repo===h||x.base===h||x.dir===h);if(!g)throw new Error(`invalid repo "${h}" \u2014 not tagged on this Track`);return g});else if(f=await as(i),!f.length)return t.status(409).json({error:"no tagged repo has work to ship"});let p=[];for(let h of f)try{let g=await zf(h.dir,{title:r,body:o,base:s}),x=h.repo||await me(h.dir).catch(()=>null);x&&g.number&&await mt({repo:x,number:g.number,trackId:i.id,url:g.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await Ut("opened",{number:g.number,url:g.url,title:r,track:i,branch:i.workspace?.branch,extra:{repo:x??h.name}}),p.push({repo:h.name,slug:x??null,ok:!0,url:g.url,number:g.number})}catch(g){p.push({repo:h.name,slug:h.repo??null,ok:!1,error:g?.message||String(g)})}let m=p.filter(h=>h.ok);return m.length?t.json({ok:!0,multi:!0,results:p,url:m[0].url,number:m[0].number}):t.status(502).json({error:p.map(h=>`${h.repo}: ${h.error}`).join("; "),results:p})}let c=await zf(i.cwd,{title:r,body:o,base:s}),l=await me(i.cwd).catch(()=>null);l&&c.number&&await mt({repo:l,number:c.number,trackId:i.id,url:c.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await Ut("opened",{number:c.number,url:c.url,title:r,track:i,branch:i.workspace?.branch,extra:{...l?{repo:l}:{}}}),t.json(c)}catch(i){let c=i?.message||String(i),l=/required|invalid/i.test(c)?400:502;t.status(l).json({error:c})}});S.get("/api/tracks/:id/repos",async(e,t)=>{try{let n=await ne(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await as(n),o=new Map(r.map(a=>[a.base,a])),s=gt(n.workspace).map(a=>{let i=o.get(a.base);return{name:a.name,base:a.base,baseRef:a.baseRef??null,repo:a.repo??null,dirty:i?.dirty??!1,ahead:i?.ahead??0,changed:!!i}});t.json({repos:s,branch:n.workspace?.branch??null,kind:n.workspace?.kind??null})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.post("/api/tracks/:id/repos",async(e,t)=>{let{repo:n}=e.body||{};try{if(!n||typeof n!="string")return t.status(400).json({error:"repo (path or owner/name) required"});let r=await Sm(e.params.id,n);t.json({ok:!0,added:{name:r.name,base:r.base,baseRef:r.baseRef??null,repo:r.repo??null}})}catch(r){let o=r?.message||String(r),s=/not found/i.test(o)?404:/already tagged|needs a multi|not a usable|archived|required/i.test(o)?400:502;t.status(s).json({error:o})}});S.delete("/api/tracks/:id/repos/:name",async(e,t)=>{try{let n=await vm(e.params.id,e.params.name);t.json({ok:!0,...n})}catch(n){let r=n?.message||String(n),o=/track .* not found/i.test(r)?404:/has work|still running|last repo/i.test(r)?409:/needs a multi|not tagged/i.test(r)?400:502;t.status(o).json({error:r})}});S.post("/api/git/prs/fix",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await es(n,r),s=await me(n).catch(()=>null),a=await nA({repo:n,number:r,branch:o.headRefName});if(!a)return t.status(404).json({error:`no active Track owns PR #${o.number} (branch "${o.headRefName}")`});let i=gt(a.workspace).find(x=>x.base===n||s&&x.repo===s)??null,c=a.workspace?.kind==="multi",l=await b0(n,o.number);if(!l.length)return t.status(409).json({error:"no failing checks on this PR"});let u=c&&i?ge.join("ci",i.name):"ci",f=ge.join(a.cwd,".bostrat",u),d=ge.join(".bostrat",u,`pr-${o.number}-fail.log`);await Ye.promises.mkdir(f,{recursive:!0}),await Ye.promises.writeFile(ge.join(a.cwd,d),l.map(x=>`\u2550\u2550\u2550\u2550 ${x.name}${x.link?` \xB7 ${x.link}`:""} \u2550\u2550\u2550\u2550
596
+ `),n?.length&&a.write(n),t.pipe(a),a.pipe(t)}),i=()=>{a.destroy(),t.destroy()};return a.on("error",i),t.on("error",i),!0}function ZT(e,t){let n=typeof t=="string"?{host:t}:t||{},r=n["x-bostrat-view-base"];return typeof r=="string"&&r?`${n["x-forwarded-proto"]==="https"?"https":"http"}://${e.slug}.${r.replace(/:\d+$/,"")}/`:`http://${e.slug}.${xL(n.host)}/`}function xL(e){if(process.env.BOSTRAT_PUBLIC_HOST)return String(process.env.BOSTRAT_PUBLIC_HOST).replace(/:\d+$/,"");let t=String(e||"").replace(/:\d+$/,"").toLowerCase();if(!t||!t.includes(".")||/^[\d.]+$/.test(t))return"bostrat.globopi";let n=t.split(".");return ku(t)&&Ip(n[0])?n.slice(1).join("."):t}ps();Up();$l();lp();ue();import QT from"node:os";import{randomUUID as SL}from"node:crypto";var vL=(e=process.env)=>({nodeId:e.BOSTRAT_NODE_ID||QT.hostname(),nodeName:e.BOSTRAT_NODE_NAME||QT.hostname()});var eE=32768,tE=120,nE=1e3,rE=new Set(["claude","codex","cursor"]),TL=new Set(["off","transition","nag"]),EL=[[0,59],[0,23],[1,31],[1,12],[0,6]];function AL(e){let t=String(e??"").trim().split(/\s+/);return t.length!==5?!1:t.every((n,r)=>{let[o,s]=EL[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 Bn=e=>String(e??"").trim();function _L(e,t){let n=e&&typeof e=="object"?e:{},r=Bn(n.name);if(!r)throw new Error("a loop plan needs a name");if(r.length>tE)throw new Error(`name is too long (${r.length}); cap is ${tE}`);let o=Bn(n.schedule);if(!o)throw new Error('a loop plan needs a schedule (5-field UTC crontab, e.g. "0 7 * * *")');if(!AL(o))throw new Error(`invalid cron schedule: "${o}" \u2014 5 UTC fields, e.g. "0 7 * * *"`);let s=Bn(n.prompt);if(!s)throw new Error("a loop plan needs a prompt \u2014 it is what the run does");if(s.length>eE)throw new Error(`prompt is too long (${s.length} chars); cap is ${eE}`);let a=Bn(n.expectation)||null;if(a&&a.length>nE)throw new Error(`expectation is too long (${a.length}); cap is ${nE}`);let i=Bn(n.notify)||"off";if(!TL.has(i))throw new Error(`notify must be one of off | transition | nag, got "${n.notify}"`);let c=n.assignment??null,l=Bn(typeof c=="string"?c:c?.provider)||"claude";if(!rE.has(l))throw new Error(`unknown provider "${l}" \u2014 one of ${[...rE].join(", ")}`);let u=typeof c=="object"&&c&&Bn(c.model)||null,f=Bn(t?.workspace?.repo)||Bn(t?.workspace?.base)||null;if(!f)throw new Error("this Track isn't based on a repo, so there's nothing for a loop to run in \u2014 propose from a repo-backed Track");let{nodeId:d,nodeName:p}=vL();return{name:r,schedule:o,prompt:s,expectation:a,notify:i,assignment:u?{provider:l,model:u}:{provider:l},repo:f,nodeId:d||null,nodeName:p||null}}async function oE(e,t){let n=_L(t,e),r=SL();return await _({id:e.id,cwd:e.cwd},{type:"loop.create.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),proposalId:r,...n}}),{proposalId:r,...n}}async function sE(e,t,n,{loopId:r=null,nextFireAt:o=null}={}){if(!t)throw new Error("proposalId required");let s=await L({id:e.id,cwd:e.cwd}),a=s.find(c=>c.type==="loop.create.offered"&&c.payload?.proposalId===t);if(!a)throw new Error("unknown proposal");if(s.some(c=>c.type==="loop.create.answered"&&c.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await _({id:e.id,cwd:e.cwd},{type:"loop.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"dismiss"}}),{proposalId:t,action:"dismiss"};if(!r)throw new Error("loopId required \u2014 the loop is created on the plane before the card is answered");let i=a.payload;return await _({id:e.id,cwd:e.cwd},{type:"loop.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,loopId:String(r),name:i.name,schedule:i.schedule,provider:i.assignment?.provider??"claude",repo:i.repo??null,nodeId:i.nodeId??null,nextFireAt:Number.isFinite(Number(o))?Number(o):null}}),await _({id:e.id,cwd:e.cwd},{type:"loop.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",loopId:String(r)}}),{proposalId:t,action:"created",loopId:String(r)}}Gn();ue();gn();$l();var aE=10,iE=200,IL=120,RL=24,lE=/^\d{4}-\d{2}-\d{2}$/;function Lh(e=process.env){return(e.CHANGELOG_REPOS||"globocodes/bostrat").split(",").map(t=>t.trim()).filter(Boolean)}var $L=(e=Date.now())=>new Date(e).toISOString().slice(0,10),Xe=(e,t="i")=>new RegExp(e,t),OL=[{re:Xe("^(business|docs|chore|ci|refactor|test|security|sec)(\\([^)]*\\))?!?:"),reason:"non-product PR prefix"},{re:Xe("\\bSPC\\b",""),reason:"business (SPC)"},{re:Xe("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),reason:"business"},{re:Xe("competitor|cloudcli|\\bkiro\\b"),reason:"competitor research"},{re:Xe("\\bReplicas\\b",""),reason:"competitor research"},{re:Xe("tenanc|tenant|perimeter|ip[- ]gate|access[- ]code|vulnerab|\\bCVE\\b|audit|hardening|security|\\bsweep\\b"),reason:"security / tenancy"},{re:Xe("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),reason:"internal codename"},{re:Xe("^track/(business|security|spc|sec)-"),reason:"non-product branch"}],CL=[Xe("\\bSPC\\b",""),Xe("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),Xe("competitor|cloudcli|\\bkiro\\b"),Xe("\\bReplicas\\b",""),Xe("tenanc|\\btenants?\\b|cross-tenant|perimeter|ip[- ]gate|vulnerab|\\bCVE\\b|hardening|security register|audit finding"),Xe("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),Xe("(^|[^\\w&])#\\d+\\b"),Xe("\\btrack/[\\w.-]+")];function ML({title:e="",headRef:t=""}={}){let n=String(e||""),r=String(t||"");for(let{re:o,reason:s}of OL)if(o.test(n)||o.test(r))return s;return null}function cE(e){let t=String(e||"");for(let n of CL){let r=n.exec(t);if(r)return r[0].trim()}return null}function uE(e,t=Date.now()){if(!e)return t-24*36e5;let n=/^(\d+)\s*([hd])$/.exec(String(e).trim());if(n)return t-Number(n[1])*(n[2]==="h"?36e5:24*36e5);let r=Date.parse(e);if(!Number.isNaN(r))return r;throw new Error(`unparseable since "${e}" \u2014 use 24h, 7d, or an ISO date`)}var NL=/^\*\*([^*]+?)\*\*\s*[:.]?\s*[—–-]?\s*(.*)$/;function PL(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Qa(e);if(t.length)throw new Error(`changelog entry appears to contain a secret VALUE (${t.join(", ")}) \u2014 entries ship off-box; never put a credential in one. Replace it and retry.`);let n=null,r=[];for(let o of e.split(`
597
+ `)){let s=o.trim();if(!s)continue;if(s.startsWith("#")){n==null&&(n=s.replace(/^#+\s*/,"").trim().slice(0,IL)||null);continue}let a=/^[-*]\s+(.*)$/.exec(s);if(!a)continue;let i=a[1].trim(),c=null,l=new RegExp(`^\\[([^\\]]{1,${RL}})\\]\\s+(.*)$`).exec(i);if(l&&(c=l[1].trim(),i=l[2].trim()),!i)continue;let u=NL.exec(i);if(!u||!u[1].trim()||!u[2].trim())throw new Error(`bullet ${r.length+1} must be \`**Short summary** \u2014 the item, one sentence.\` (bold summary title, em dash, then the change) \u2014 got "${i.slice(0,80)}". Rewrite it and re-publish.`);i=`**${u[1].trim().replace(/[:.]\s*$/,"")}** \u2014 ${u[2].trim()}`;let f=cE(i);if(f)throw new Error(`bullet ${r.length+1} mentions "${f}" \u2014 the product changelog never carries business, security/tenancy or internal-ops items, PR numbers, branch names or codenames; drop the bullet or rewrite it as the user-visible change and re-publish.`);if(i.length>iE)throw new Error(`bullet ${r.length+1} is ${i.length} chars \u2014 over the ${iE}-char cap; a changelog bullet is one line`);r.push({text:i,...c?{area:c}:{}})}if(n){let o=cE(n);if(o)throw new Error(`headline mentions "${o}" \u2014 the product changelog never carries business, security/tenancy or internal-ops items; rewrite it and re-publish.`)}if(!r.length)throw new Error("no `- ` bullets found \u2014 an entry is a bullet list, optionally under a `# headline`");if(r.length>aE)throw new Error(`${r.length} bullets \u2014 over the ${aE}-bullet cap; group related changes into one line`);return{title:n||null,bullets:r}}async function DL(e,{repos:t=Lh()}={}){let n=new Set(t);return(await Xr()).filter(r=>r.state==="merged"&&(r.resolvedAt??0)>=e&&n.has(r.repo)).sort((r,o)=>(r.resolvedAt??0)-(o.resolvedAt??0)).map(r=>({repo:r.repo,number:r.number,title:r.title||null,url:r.url||null,headRef:r.headRef||null,mergedAt:r.resolvedAt??null,excluded:ML({title:r.title,headRef:r.headRef})}))}async function dE(e,t){let n=await DL(e,t);return{prs:n.filter(r=>!r.excluded),excluded:n.filter(r=>r.excluded)}}async function fE(e,{md:t,day:n=null}){let r=PL(t),o=n==null||n===""?$L():String(n);if(!lE.test(o)||Number.isNaN(Date.parse(o)))throw new Error(`invalid day "${n}" \u2014 expected YYYY-MM-DD`);let s=await _({id:e.id,cwd:e.cwd},{type:"changelog.published",actor:"agent",source:"orchestrator",boxId:e.leadBox||null,payload:{ts:Date.now(),day:o,title:r.title,bullets:r.bullets}});return{day:o,title:r.title,bullets:r.bullets,eventId:s.id}}async function pE(e,{day:t}){let n=String(t||"");if(!lE.test(n)||Number.isNaN(Date.parse(n)))throw new Error(`invalid day "${t}" \u2014 expected YYYY-MM-DD`);let r=await _({id:e.id,cwd:e.cwd},{type:"changelog.published",actor:"agent",source:"orchestrator",boxId:e.leadBox||null,payload:{ts:Date.now(),day:n,title:null,bullets:[],retract:!0}});return{day:n,retracted:!0,eventId:r.id}}ss();gn();cs();ue();ss();et();fr();gn();Ba();il();Ha();import{execFile as BL}from"node:child_process";import{promisify as jL}from"node:util";var Uh=jL(BL),mE=3e4,LL=30*6e4,FL=mE,UL=10*6e4,HL=10080*6e4,WL=60*6e4,qL=8,KL=1440*6e4,GL=3,hE="number,url,title,headRefName,headRefOid,state,mergedAt,closedAt",Fh=60*6e4,VL=15*6e4,zL=9e4,JL=1440*6e4,Su=new Map,vu=new Map,XL=/could not resolve|not found|no pull requests?/i,YL=e=>XL.test(String(e?.message||e||""));function ZL(e,t){return[e.ciFix?.delegatedAt,e.reconcile?.delegatedAt,e.ciFixAwait?.since,e.reconcileAwait?.since].some(n=>n&&t-n<Fh)}var wE={fast:FL,slow:UL,decay:WL};function gE(e,t){return e.armedAt&&t-e.armedAt<LL||ZL(e,t)||yE(e,t,{grace:0})?"fast":t-(e.firstSeen||0)>HL?"decay":"slow"}function QL(e,t){return wE[gE(e,t)]}function Pi(e,t,n,r){let o=e.lanes?.get(Q(t.repo,t.number))||{};return al({change:n,repo:t.repo,number:Number(t.number),githubAt:r||null,lane:o.lane||null,intervalMs:o.intervalMs||null,source:"watch"})}async function eF(e,t){bn("watch");try{let{stdout:n}=await Uh("gh",["pr","view",String(t),"--repo",e,"--json",hE],{timeout:3e4,maxBuffer:4194304,env:{...process.env,...await qt({slug:e})}});return JSON.parse(n||"null")}catch(n){throw lr(n)&&ur(n),n}}async function tF(e){bn("watch");try{let{stdout:t}=await Uh("gh",["pr","list","--repo",e,"--state","all","--limit","100","--json",hE],{timeout:3e4,maxBuffer:8388608,env:{...process.env,...await qt({slug:e})}}),n=new Map;for(let r of JSON.parse(t||"[]"))n.set(Number(r.number),r);return n}catch(t){throw lr(t)&&ur(t),t}}async function nF(){let e=new Map;for(let t of await ae().catch(()=>[]))e.set(t.id,t);return e}async function rF(e,t){await _({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"merged",...t}})}async function oF(e,t){let n=await Zr(e);return n?rs(n,t):null}async function sF(e,t,n){let r=await Zr(e);if(!r)throw new Error(`no local checkout for ${e}`);return os(r,t,{method:n})}async function aF(e,t){let n=await Zr(e);if(!n)throw new Error(`no local checkout for ${e}`);return Fa(n,t)}async function iF(e,t){await _({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"auto-canceled",...t}})}async function Ps(e,t,n,r,o){if(!await r.disarm(e.repo,e.number).catch(()=>null))return;let a=n.get(e.trackId);a&&await r.emitDisarmed(a,{number:Number(e.number),url:t?.url||e.url,title:t?.title||e.title,branch:t?.headRefName||e.headRef,repo:e.repo,reason:o}).catch(()=>{})}var cF=10*6e4;async function lF(e,t,n){let r=e.autoMerge?.armedAt||0;if(r&&(n.now??Date.now())-r>KL){await Ps(e,null,t,n,"auto-merge expired \u2014 checks never settled within 24h");return}let o=await n.detail(e.repo,e.number).catch(()=>null);if(!o)return;if(o.checks.failed>0){let a=o.checks.failing.map(i=>i.name).join(", ");await Ps(e,o,t,n,`check${o.checks.failed===1?"":"s"} failed: ${a}`);return}if(o.mergeable==="CONFLICTING"){await Ps(e,o,t,n,`conflicts with ${o.baseRefName}`);return}if(!o.checks.total){let a=Math.max(e.autoMerge?.armedAt||0,Date.parse(o.updatedAt||"")||0);if((n.now??Date.now())-a<cF)return;await Ps(e,o,t,n,o.checks.unavailable?"this token can't read the checks":"no CI checks appeared");return}if(o.checks.pending>0||o.mergeable==="UNKNOWN"||o.mergeStateStatus==="UNKNOWN"||o.isDraft)return;let s=await n.lookup(e.repo,e.number).catch(()=>null);if(s?.autoMerge){if(o.mergeStateStatus==="BEHIND"){try{await n.updateBranch(e.repo,e.number)}catch(a){let i=String(a?.message||a).trim();/no new commits|already up.to.date/i.test(i)||await Ps(e,o,t,n,i||`couldn't update with ${o.baseRefName}`)}return}try{await n.merge(e.repo,e.number,s.autoMerge.method||"merge")}catch(a){if(/already merged|not open|is closed/i.test(String(a?.message||a)))return;await Ps(e,o,t,n,String(a?.message||a).trim()||"merge failed");return}await bE(e,{...o,state:"MERGED"},t,n,{change:"auto-merged",githubAt:o.checks.settledAt||null})}}async function Ds(e,t,n){await _({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:t,...n}})}async function uF(e,t){try{return await Uh("git",["-C",e.cwd,"cat-file","-e",`${t}^{commit}`],{timeout:1e4}),!0}catch{return!1}}async function Ni(e,t,n,r=()=>!0){return(await L(e).catch(()=>[])).some(s=>s.type==="pr.state.changed"&&s.payload?.change===t&&s.payload?.number===Number(n)&&r(s))}var Bs=(e,t)=>({number:Number(e.number),url:t?.url||e.url,title:t?.title||e.title,branch:t?.headRefName||e.headRef,repo:e.repo});function yE(e,t,{grace:n=zL}={}){if(e.announced!==!1)return!1;let r=t-(e.firstSeen||0);return r>=n&&r<=JL}async function dF(e,t,n,r){let o=r.now??Date.now();if(!yE(e,o))return!1;let s=n.get(e.trackId)||null;if(!s||s.archivedAt||s.transferredTo)return!1;let a=(s.boxes||[]).find(f=>f.name===s.leadBox);return await(r.midTurn??Qr)(s.leadBox,a?.agent).catch(()=>!1)?!1:(await L(s).catch(()=>[])).some(f=>f.type==="pr.state.changed"&&f.payload?.number===Number(e.number))?(await(r.claim??wn)(e.repo,e.number).catch(()=>null),!1):await(r.claim??wn)(e.repo,e.number).catch(()=>null)?(await Ds(s,"opened",{...Bs(e,t),announcedBy:"watch"}).catch(()=>{}),console.log(`[pr-watch] announced passive link ${e.repo}#${e.number} \u2192 track ${s.id} (no active door claimed it)`),!0):!1}async function fF(e,t,n,r){let o=r.now??Date.now(),s=t.headRefOid||null,a=n.get(e.trackId)||null;if(s&&(e.ciFix?.headSha&&s!==e.ciFix.headSha&&await Zc(e.repo,e.number,{headSha:s}).catch(()=>{}),e.reconcile?.headSha&&s!==e.reconcile.headSha&&await el(e.repo,e.number,{headSha:s}).catch(()=>{})),s&&s!==e.lastHeadSha){let i=!e.lastHeadSha,c=!!(e.ciFix||e.reconcile||e.ciFixAwait||e.reconcileAwait),l=!!e.baseFoldAt&&o-e.baseFoldAt<VL;await Yk(e.repo,e.number,s).catch(()=>{}),e.baseFoldAt&&await Xk(e.repo,e.number).catch(()=>{}),!i&&!c&&!l&&a&&!await r.localHasCommit(a,s).catch(()=>!1)&&!await Ni(a,"pushed",e.number,f=>f.payload?.sha===s)&&await Ds(a,"pushed",{...Bs(e,t),sha:s}).catch(()=>{})}if(e.ciFixAwait)if(o-(e.ciFixAwait.since||0)>Fh)await Qc(e.repo,e.number).catch(()=>{});else{let i=await r.detail(e.repo,e.number).catch(()=>null);if(i?.checks){if(i.checks.failed>0)await Qc(e.repo,e.number).catch(()=>{});else if(i.checks.total>0&&i.checks.pending===0){let c=Pi(r,e,"ci-fixed",i.checks.settledAt||null),l=e.ciFixAwait.since||0;a&&!await Ni(a,"ci-fixed",e.number,u=>(u.payload?.ts||0)>=l)&&await Ds(a,"ci-fixed",{...Bs(e,t),sha:s,delegated:!0,passed:i.checks.passed,githubAt:c.githubAt,latencyMs:c.latencyMs,lane:c.lane}).catch(()=>{}),await Qc(e.repo,e.number).catch(()=>{})}}}if(e.reconcileAwait)if(o-(e.reconcileAwait.since||0)>Fh)await tl(e.repo,e.number).catch(()=>{});else{let i=await r.detail(e.repo,e.number).catch(()=>null);if(i){if(i.mergeable==="CONFLICTING")await tl(e.repo,e.number).catch(()=>{});else if(i.mergeable==="MERGEABLE"){Pi(r,e,"reconciled",null);let c=e.reconcileAwait.since||0;a&&!await Ni(a,"reconciled",e.number,l=>(l.payload?.ts||0)>=c)&&await Ds(a,"reconciled",{...Bs(e,t),sha:s,delegated:!0,base:i.baseRefName||null}).catch(()=>{}),await tl(e.repo,e.number).catch(()=>{})}}}}async function pF(e,t,n,r){let o=Pi(r,e,"closed",Date.parse(t?.closedAt||"")||null),s=n.get(e.trackId);s&&!await Ni(s,"closed",e.number)&&await Ds(s,"closed",{...Bs(e,t),githubAt:o.githubAt,latencyMs:o.latencyMs,lane:o.lane}).catch(()=>{}),await r.notifyIfResolved(e.repo,e.number,"closed").catch(()=>{}),await r.mark(e.repo,e.number,"closed").catch(()=>{})}async function mF(e,t,n){Pi(n,e,"lost",null);let r=t.get(e.trackId);r&&!await Ni(r,"lost",e.number)&&await Ds(r,"lost",Bs(e,null)).catch(()=>{}),await n.notifyIfResolved(e.repo,e.number,"lost").catch(()=>{}),await n.mark(e.repo,e.number,"lost").catch(()=>{})}async function bE(e,t,n,r,o={}){let s=Pi(r,e,o.change||"merged",o.githubAt??(Date.parse(t.mergedAt||"")||null)),a=n.get(e.trackId);a&&((await L(a).catch(()=>[])).some(l=>l.type==="pr.state.changed"&&l.payload?.change==="merged"&&l.payload?.number===Number(e.number))||await r.emitMerged(a,{number:Number(e.number),url:t.url||e.url,title:t.title||e.title,branch:t.headRefName||e.headRef,repo:e.repo,githubAt:s.githubAt,latencyMs:s.latencyMs,lane:s.lane}).catch(()=>{})),await r.notifyIfArmed(e.repo,e.number).catch(()=>{}),await r.archiveIfArmed(e.repo,e.number).catch(()=>{}),await r.mark(e.repo,e.number,"merged").catch(()=>{})}async function hF(e={}){let{now:t=Date.now(),auth:n=Jf,view:r=eF,list:o=tF,links:s=ex,trackMap:a=nF,emitMerged:i=rF,mark:c=ir,archiveIfArmed:l=xn,notifyIfArmed:u=Sn,notifyIfResolved:f=Ul,batchThreshold:d=GL,detail:p=oF,merge:m=sF,updateBranch:h=aF,lookup:g=qe,disarm:x=Da,emitDisarmed:k=iF,localHasCommit:E=uF,claim:I=wn,midTurn:M=Qr}=e;if(!(await n().catch(()=>null))?.authenticated||ol()>0)return 0;let T=(await s().catch(()=>[])).filter(U=>t-(Su.get(Q(U.repo,U.number))||0)>=QL(U,t));if(!T.length)return 0;let j=Date.now(),Z=new Map,fe=new Map;for(let U of T){let pe=gE(U,t);Z.set(Q(U.repo,U.number),{lane:pe,intervalMs:wE[pe]}),Su.set(Q(U.repo,U.number),t),fe.has(U.repo)||fe.set(U.repo,[]),fe.get(U.repo).push(U)}let ie=await a().catch(()=>new Map),D={now:t,lanes:Z,emitMerged:i,mark:c,archiveIfArmed:l,notifyIfArmed:u,notifyIfResolved:f,detail:p,merge:m,updateBranch:h,lookup:g,disarm:x,emitDisarmed:k,localHasCommit:E,claim:I,midTurn:M};for(let[U,pe]of fe){let Se,He=new Set;if(pe.length>d)Se=await o(U).catch(()=>null);else{Se=new Map;for(let le of pe)try{let q=await r(U,le.number);q?.number!=null&&Se.set(Number(q.number),q)}catch(q){YL(q)&&He.add(Q(le.repo,le.number))}}if(Se)for(let le of pe){let q=Q(le.repo,le.number),J=Se.get(Number(le.number));if(!J){if(He.has(q)){let ee=(vu.get(q)||0)+1;vu.set(q,ee),ee>=qL&&(await mF(le,ie,D),vu.delete(q),Su.delete(q))}continue}vu.delete(q),J.state==="MERGED"||J.state==="CLOSED"?(J.state==="MERGED"?await bE(le,J,ie,D):await pF(le,J,ie,D),Su.delete(q)):(await dF(le,J,ie,D).catch(()=>{}),await fF(le,J,ie,D).catch(()=>{}),le.autoMerge&&await lF(le,ie,D).catch(()=>{}))}}let R={};for(let{lane:U}of Z.values())R[U]=(R[U]||0)+1;return console.log(`[pr-watch] probed ${T.length} link(s) (${Object.entries(R).map(([U,pe])=>`${U} ${pe}`).join(", ")}) in ${Date.now()-j}ms`),T.length}function kE(){let e=!1;setInterval(async()=>{if(!e){e=!0;try{await hF()}catch{}finally{e=!1}}},mE)}ue();gn();Hn();fr();function xE(e){return(e?.checks?.failed??0)>0?"red":e?.mergeable==="CONFLICTING"?"conflict":e?.mergeStateStatus==="BEHIND"?"behind":null}function wF(e){return!(!e?.checks||e.checks.pending>0||e.mergeabilityPending||e.mergeable==="UNKNOWN"||e.mergeStateStatus==="UNKNOWN")}var gF=new Set(["merged","closed","lost"]);function yF(e,t){if(!e?.blocked)return null;let n=xE(t);if(e.blocked==="red")return t.checks.failed===0&&t.checks.total>0?{change:"ci-fixed",reason:"red"}:null;if(e.blocked==="conflict")return t.mergeable==="MERGEABLE"&&n!=="red"?{change:"reconciled",reason:"conflict"}:null;if(e.blocked==="behind"){let r=t.headSha??null;return n===null&&r&&e.sha&&r!==e.sha?{change:"reconciled",reason:"behind"}:null}return null}function bF(e,t){return e.autoMerge?!0:t==="ci-fixed"?!!(e.ciFix||e.ciFixAwait):t==="reconciled"?!!(e.reconcile||e.reconcileAwait):!1}async function kF(e,t,n,r,o){return(await L(e).catch(()=>[])).some(a=>{if(a.type!=="pr.state.changed"||a.payload?.number!==Number(n))return!1;let i=a.payload?.change;return i===t?a.payload?.sha&&r?a.payload.sha===r:(a.payload?.ts||0)>=o:i==="pushed"&&!!r&&a.payload?.sha===r})}async function xF(e,t,n){await _({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:t,...n}})}async function SE(e,t={}){let{now:n=Date.now(),slugOf:r=me,lookup:o=qe,note:s=Zk,tracks:a=async()=>(await ae()).filter(f=>!f.archivedAt&&!f.transferredTo),asked:i=kF,emitChange:c=xF}=t,l=[],u=null;for(let f of e??[]){if(!f?.prs?.length)continue;let d=await r(f.path).catch(()=>null);if(d)for(let p of f.prs)try{if(!wF(p))continue;let m=await o(d,p.number).catch(()=>null);if(!m?.trackId||gF.has(m.state))continue;let{prev:h}=await s(d,p.number,{blocked:xE(p),sha:p.headSha??null,at:n});if(!h)continue;let g=yF(h,p);if(!g||bF(m,g.change))continue;u??=new Map((await a()).map(I=>[I.id,I]));let x=u.get(m.trackId);if(!x)continue;let k=p.headSha??null;if(await i(x,g.change,p.number,k,h.at||0))continue;let E={number:Number(p.number),url:p.url||m.url,title:p.title||m.title,branch:p.headRefName||m.headRef,repo:d,sha:k,delegated:!1,reason:g.reason};g.change==="ci-fixed"?E.passed=p.checks.passed:E.base=p.baseRefName||null,await c(x,g.change,E),l.push({change:g.change,number:p.number,reason:g.reason})}catch{}}return l}Ve();ue();fr();import{randomUUID as SF}from"node:crypto";var vF=2e4,vE=3,js=new Map,Hh=new Set;async function TE(e,t,n){let r=await n(e).catch(()=>[]),o=null;for(let s of r)s.type==="box.fullscreen.detected"&&s.boxId===t?o=s.payload?.offerId||null:s.type==="box.fullscreen.answered"&&o&&s.payload?.offerId===o&&(o=null);return o}async function TF(e={}){let{sessions:t=null,tracks:n=null,append:r=_,read:o=L,now:s=Date.now()}=e;if(process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1")return;let a,i;try{a=t??await Ot(),i=n??await ae()}catch{return}let c=new Map(a.map(u=>[u.name,u])),l=new Set;for(let u of i){if(u.archivedAt||u.transferredTo||!u.leadBox)continue;let f=(u.boxes||[]).find(p=>p.name===u.leadBox);if(!f||f.agent!=="claude"||f.state!=="live")continue;let d=c.get(f.name);if(d)if(l.add(f.name),d.alternateOn){let p=(js.get(f.name)||0)+1;js.set(f.name,p),p===vE&&(Hh.add(f.name),await TE(u,f.name,o)||await r(u,{type:"box.fullscreen.detected",actor:"system",source:"orchestrator",boxId:f.name,provider:f.agent,payload:{ts:s,offerId:SF(),box:f.name,agent:f.agent}}).catch(()=>{}))}else{let p=(js.get(f.name)||0)>=vE;if(js.delete(f.name),p||!Hh.has(f.name)){Hh.add(f.name);let m=await TE(u,f.name,o);m&&await r(u,{type:"box.fullscreen.answered",actor:"system",source:"orchestrator",boxId:f.name,provider:f.agent,payload:{ts:s,offerId:m,action:"cleared"}}).catch(()=>{})}}}for(let u of[...js.keys()])l.has(u)||js.delete(u)}var Di=null,Wh=!1;function EE(){return Di?()=>{}:(Di=setInterval(()=>{Wh||(Wh=!0,TF().catch(()=>{}).finally(()=>{Wh=!1}))},vF),Di.unref?.(),()=>{clearInterval(Di),Di=null})}Qo();Op();ue();ss();cs();Qo();import{randomUUID as EF}from"node:crypto";async function AF(){let e=await Promise.resolve().then(()=>(fr(),hv));return{sayToLead:e.sayToLead,queueShipCompleteNotify:e.queueShipCompleteNotify}}var qh={listRepoPrs:Jt,readEvents:L,appendEvent:_,sayDeps:AF,currentBranch:as};async function _F(e,t=qh,{branch:n=null}={}){if(!e?.cwd)return null;let r=n||await(t.currentBranch??as)(e.workspace?.kind==="multi"?null:e.cwd).catch(()=>null)||e?.workspace?.branch;if(!r)return null;let o;try{o=await t.listRepoPrs(e.cwd,{caller:"pr-exists"})}catch{return null}let s=(o||[]).find(a=>a.headRefName===r);return s?{number:s.number,url:s.url??null,title:s.title??null}:null}async function Kh(e,t,{actions:n,notify:r=!1}={},o=qh){let s=t?.payload||{};if(!Array.isArray(n)||!n.includes("pr")||s.toPr||Array.isArray(s.repos)&&s.repos.length||!s.branch)return null;let a=await _F(e,o,{branch:s.branch});if(!a)return null;let i={id:e.id,cwd:e.cwd};await o.appendEvent(i,{type:"pr.offer.answered",actor:"user",source:"orchestrator",boxId:t.boxId,payload:{ts:Date.now(),offerId:s.offerId,action:"pr-exists",actions:n,...r?{notify:!0}:{},existingPr:{number:a.number}}});let c=EF();return await o.appendEvent(i,{type:"pr.exists.offered",actor:"system",source:"orchestrator",boxId:t.boxId,payload:{ts:Date.now(),offerId:c,srcOfferId:s.offerId??null,branch:s.branch,base:s.base??null,pr:a,actions:n,...r?{notify:!0}:{},offeredRebase:Array.isArray(s.offered)&&s.offered.includes("rebase")}}),{offerId:c,pr:a}}async function Gh(e,{offerId:t,choice:n}={},r=qh){if(!t)throw new Error("offerId required");if(!["push","new","dismiss"].includes(n))throw new Error('choice "push" | "new" | "dismiss" required');let o=await r.readEvents(e),s=o.find(u=>u.type==="pr.exists.offered"&&u.payload?.offerId===t);if(!s)throw new Error("unknown offer");if(o.some(u=>u.type==="pr.exists.answered"&&u.payload?.offerId===t))throw new Error("offer already answered");let a=s.payload||{},i=Array.isArray(a.actions)&&a.actions.length?a.actions:["commit","push","pr"],c=null,l=null;if(n==="push"){let{sayToLead:u}=await r.sayDeps();l=Yo.filter(f=>f!=="pr"&&(i.includes(f)||f==="push")),c=await u(e.id,Zo(l,{branch:a.branch??null,base:a.base??null,toPr:{number:a.pr?.number??null},offeredRebase:a.offeredRebase===!0}),{kind:"push-go"})}else if(n==="new"){let{sayToLead:u}=await r.sayDeps();l=i,c=await u(e.id,Fk(i,{branch:a.branch??null,base:a.base??null,prNumber:a.pr?.number??null,offeredRebase:a.offeredRebase===!0}),{kind:"pr-go"})}if(await r.appendEvent({id:e.id,cwd:e.cwd},{type:"pr.exists.answered",actor:"user",source:"orchestrator",boxId:s.boxId,payload:{ts:Date.now(),offerId:t,choice:n}}),n!=="dismiss"&&a.notify===!0){let{queueShipCompleteNotify:u}=await r.sayDeps();u(e.id,{actions:l})}return{say:c,choice:n}}import jn from"node:fs/promises";import Ls from"node:path";import CE from"node:os";import AE from"node:fs/promises";import Tu from"node:path";import{execFile as IF}from"node:child_process";import{promisify as RF}from"node:util";import{fileURLToPath as $F}from"node:url";var OF=RF(IF),IE=Tu.dirname($F(import.meta.url)),CF=Tu.resolve(IE,"..","..","client","dist"),MF="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",NF=new Map([...MF].map((e,t)=>[e,t]));function PF(e){let t=[],n=0,r=0;for(let o of e){let s=NF.get(o);if(s===void 0)return t;n+=(s&31)<<r,s&32?r+=5:(t.push(n&1?-(n>>>1):n>>>1),n=0,r=0)}return t}function DF(e){let t=[],n=0,r=0,o=0;for(let s of e.split(";")){let a=[],i=0;if(s)for(let c of s.split(",")){let l=PF(c);l.length!==0&&(i+=l[0],l.length>=4&&(n+=l[1],r+=l[2],o+=l[3],a.push([i,n,r,o])))}t.push(a)}return t}function BF(e,t){if(!e||e.length===0||e[0][0]>t)return null;let n=0,r=e.length-1;for(;n<r;){let o=n+r+1>>1;e[o][0]<=t?n=o:r=o-1}return e[n]}var _E=new Map;async function jF(e){let t;try{t=await AE.stat(e)}catch{return null}let n=_E.get(e);if(n&&n.mtimeMs===t.mtimeMs)return n;try{let r=JSON.parse(await AE.readFile(e,"utf8")),o={mtimeMs:t.mtimeMs,sources:r.sources||[],lines:DF(r.mappings||"")};return _E.set(e,o),o}catch{return null}}var Vh=null;function LF(){return Vh||(Vh=process.env.BOSTRAT_RELEASE?Promise.resolve(process.env.BOSTRAT_RELEASE):OF("git",["rev-parse","--short","HEAD"],{cwd:Tu.resolve(IE,"..","..")}).then(e=>e.stdout.trim()).catch(()=>null)),Vh}var FF=/(?:https?:\/\/[^\s()]*)?\/assets\/([^\s()/]+\.js):(\d+):(\d+)/g;async function UF(e,{distDir:t=CF}={}){let n=[],r=0,o=!1;for(let s of e.matchAll(FF)){let[a,i,c,l]=s,u=await jF(Tu.join(t,"assets",`${i}.map`)),f=u?BF(u.lines[Number(c)-1],Number(l)-1):null;if(n.push(e.slice(r,s.index)),f&&u.sources[f[1]]){let d=u.sources[f[1]].replace(/^(\.\.\/)+/,"");n.push(`${d}:${f[2]+1}:${f[3]+1}`),o=!0}else n.push(a);r=s.index+a.length}return n.push(e.slice(r)),{stack:n.join(""),symbolicated:o}}async function RE(e,t={}){try{if(!e?.error?.stack||!e.release||e.release==="unknown")return e;let n=t.release??await LF();if(!n||e.release!==n)return e;let{stack:r,symbolicated:o}=await UF(e.error.stack,t);o&&(e.error.stack=r,e.error.symbolicated=!0)}catch{}return e}var HF=()=>process.env.BOSTRAT_STATE_DIR||Ls.join(process.env.HOME||CE.tmpdir(),".bostrat"),Ir=()=>Ls.join(HF(),"telemetry"),ME=()=>Ls.join(Ir(),".relay-offsets.json"),WF=50,qF=14,KF=3e4,$E=500,bt=(e,t)=>typeof e=="string"?e.slice(0,t):"";function GF(e,t){if(!e||typeof e!="object")return null;let n=bt(e.name,64);if(!n)return null;let r=Number.isFinite(e.ts)?e.ts:t,o={name:n,ts:Math.abs(r-t)<168*3600*1e3?r:t,receivedAt:t,anonId:bt(e.anonId,64),sessionId:bt(e.sessionId,64),userId:bt(e.userId,64),release:bt(e.release,64),appVersion:bt(e.appVersion,32),route:bt(e.route,128),deviceClass:e.deviceClass==="phone"||e.deviceClass==="desktop"?e.deviceClass:""};return e.props&&typeof e.props=="object"&&!Array.isArray(e.props)&&(JSON.stringify(e.props).length<=8192?o.props=e.props:o.props={clamped:!0}),e.error&&typeof e.error=="object"&&(o.error={kind:bt(e.error.kind,256),message:bt(e.error.message,8192),stack:bt(e.error.stack,32768),fingerprint:bt(e.error.fingerprint,64)}),Array.isArray(e.breadcrumbs)&&(o.breadcrumbs=e.breadcrumbs.slice(-50).map(s=>({t:Number.isFinite(s?.t)?s.t:0,n:bt(s?.n,64),r:bt(s?.r,128)}))),o}var NE=e=>new Date(e).toISOString().slice(0,10),OE=0;async function PE(e,t=Date.now()){let r=(Array.isArray(e?.events)?e.events.slice(0,WF):[]).map(s=>GF(s,t)).filter(Boolean);if(!r.length)return 0;for(let s of r)s.error?.stack&&await RE(s);await jn.mkdir(Ir(),{recursive:!0});let o=Ls.join(Ir(),`${NE(t)}.ndjson`);return await jn.appendFile(o,r.map(s=>JSON.stringify(s)+`
598
+ `).join(""),"utf8"),t-OE>6*3600*1e3&&(OE=t,VF(t).catch(()=>{})),r.length}async function VF(e=Date.now()){let t=NE(e-qF*24*3600*1e3),n=[];try{n=await jn.readdir(Ir())}catch{return}let r=n.filter(s=>s.endsWith(".ndjson")&&s.slice(0,10)<t);if(!r.length)return;for(let s of r)await jn.rm(Ls.join(Ir(),s),{force:!0});let o=await BE();for(let s of r)delete o[s];await jE(o)}var Eu=new Map;function DE(e,t=Date.now()){let n=e||"unknown",r=Eu.get(n);return r||(Eu.size>512&&Eu.clear(),r={tokens:40,at:t},Eu.set(n,r)),r.tokens=Math.min(40,r.tokens+(t-r.at)/6e4*20),r.at=t,r.tokens<1?!1:(r.tokens-=1,!0)}async function BE(){try{return JSON.parse(await jn.readFile(ME(),"utf8"))||{}}catch{return{}}}async function jE(e){await jn.mkdir(Ir(),{recursive:!0}),await jn.writeFile(ME(),JSON.stringify(e),"utf8")}function zF(e,{env:t,host:n}={}){let r=e.name==="app.error"&&e.error,o={};for(let[a,i]of[["event",e.name],["route",e.route],["session",e.sessionId],["anon",e.anonId],["user",e.userId],["release",e.release],["appVersion",e.appVersion],["device",e.deviceClass]])i&&(o[a]=i);let s={timestamp:new Date(e.ts).toISOString(),service:"bostrat-client",source:"treetop-js",env:t||process.env.BOSTRAT_ENV||"pi",host:n||CE.hostname(),level:r?"error":"info",message:r?`${e.error.kind||"Error"}: ${e.error.message||"(no message)"}`.slice(0,8192):e.name,tags:o,attributes:{...e.props?{props:e.props}:{},receivedAt:e.receivedAt}};return r&&(s.error={kind:e.error.kind,message:e.error.message,stack:e.error.stack},e.error.fingerprint&&(s.fingerprint=e.error.fingerprint),e.error.symbolicated&&(s.attributes.symbolicated=!0),e.breadcrumbs&&(s.attributes.breadcrumbs=e.breadcrumbs)),s}async function JF({fetchImpl:e=fetch}={}){let t=await Dv();if(!t)return{sent:0,disabled:!0};let n;try{n=(await jn.readdir(Ir())).filter(s=>s.endsWith(".ndjson")).sort()}catch{return{sent:0,disabled:!1}}let r=await BE(),o=0;for(let s of n){let a=Ls.join(Ir(),s),i=r[s]||0,c;try{let d=await jn.open(a,"r");try{let p=(await d.stat()).size;if(p<=i)continue;c=Buffer.alloc(p-i),await d.read(c,0,c.length,i)}finally{await d.close()}}catch{continue}let l=c.lastIndexOf(10);if(l<0)continue;let u=c.toString("utf8",0,l+1).split(`
599
+ `).filter(Boolean),f=[];for(let d of u)try{f.push(JSON.parse(d))}catch{}for(let d=0;d<f.length;d+=$E){let p=f.slice(d,d+$E).map(h=>zF(h)),m=await e(`${t.url.replace(/\/$/,"")}/v1/logs`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${t.ingestKey}`},body:JSON.stringify({events:p})}).catch(()=>null);if(!m||!m.ok)return{sent:o,disabled:!1};o+=p.length}r[s]=i+l+1,await jE(r)}return{sent:o,disabled:!1}}var zh=null,Jh=!1;function LE(){zh||(zh=setInterval(async()=>{if(!Jh){Jh=!0;try{await JF()}catch(e){console.error("[telemetry] relay failed:",e?.message||e)}finally{Jh=!1}}},KF),zh.unref?.())}import _u from"node:fs/promises";import qE from"node:path";import XF from"node:os";var KE=()=>process.env.BOSTRAT_STATE_DIR||qE.join(process.env.HOME||XF.tmpdir(),".bostrat"),GE=()=>qE.join(KE(),"dictation-glossary.json"),YF=100,ZF=500,QF=["bostrat","globopi","codex","tmux","worktree","Deepgram","Linear","Firecracker","Tigris","WireGuard","misous","postyx","cedar","gerbil","Anthropic","Opus","Haiku","Sonnet","keyterm","monorepo","dogfood"],Iu=null,Xh=null,Yh=Promise.resolve();function FE(){let e={},t=Date.now();for(let n of QF)e[n.toLowerCase()]={term:n,count:1,lastUsed:t,source:"seed"};return e}async function VE(){return Iu||(Xh??=_u.readFile(GE(),"utf8").then(e=>JSON.parse(e)?.terms??FE()).catch(()=>FE()).then(e=>Iu=e).finally(()=>Xh=null),Xh)}async function UE(){let e=JSON.stringify({terms:Iu},null,2),t=GE(),n=`${t}.${process.pid}.tmp`;await _u.mkdir(KE(),{recursive:!0}),await _u.writeFile(n,e),await _u.rename(n,t)}function eU(){return Yh=Yh.then(UE,UE),Yh.catch(()=>{})}async function Zh(){return Object.values(await VE()).sort((t,n)=>n.count-t.count||n.lastUsed-t.lastUsed)}var tU=e=>Math.max(1,Math.ceil(e.length/4));async function nU(){let e=[],t=0;for(let{term:n}of await Zh()){let r=tU(n);if(!(t+r>ZF)&&(e.push(n),t+=r,e.length>=YF))break}return e}async function rU(e,t){let n=await VE(),r=e.toLowerCase(),o=n[r];n[r]={term:e,count:(o?.count??0)+1,lastUsed:Date.now(),source:o?.source??t}}var HE=e=>(e||"").split(/\s+/).map(t=>t.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"")).filter(Boolean),Au=e=>e.toLowerCase();function WE(e){return!new RegExp("\\p{L}","u").test(e)||e.length<3?!1:/^[a-z]+$/.test(e)?e.length>=4:!0}async function zE(e,t){let n=HE(e),r=HE(t);if(!n.length||!r.length)return[];let o=n.length,s=r.length,a=Array.from({length:o+1},()=>new Array(s+1).fill(0));for(let u=o-1;u>=0;u--)for(let f=s-1;f>=0;f--)a[u][f]=Au(n[u])===Au(r[f])?a[u+1][f+1]+1:Math.max(a[u+1][f],a[u][f+1]);let i=new Set,c=0,l=0;for(;c<o&&l<s;)Au(n[c])===Au(r[l])?(c++,l++):a[c+1][l]>=a[c][l+1]?c++:(WE(r[l])&&i.add(r[l]),l++);for(;l<s;l++)WE(r[l])&&i.add(r[l]);if(!i.size)return[];for(let u of i)await rU(u,"learned");return await eU(),[...i]}var Bi=null;function oU(e,t){let n=null;try{n=JSON.parse(t)}catch{}let r=n?.err_code||n?.error_code||n?.category||"";return e===402||/PAYMENT_REQUIRED/i.test(r)?{status:402,code:"credits_exhausted",persistent:!0,message:"Deepgram credits are exhausted \u2014 dictation is down until you top up at console.deepgram.com or drop a new key into ~/.bostrat/integrations.json."}:e===401||e===403?{status:502,code:"key_invalid",persistent:!0,message:"Deepgram rejected the API key (revoked, or missing ASR scope) \u2014 replace it in ~/.bostrat/integrations.json."}:{status:502,code:"transcription_failed",persistent:!1,message:`Deepgram error ${e}: ${t.slice(0,300)}`}}async function JE(){if(!Bi)return null;let e=await Si();if(!e||e.apiKey.slice(-6)!==Bi.keyTail)return null;let{keyTail:t,...n}=Bi;return n}async function XE(e,t){let n=await Si();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 nU())r.searchParams.append("keyterm",i);let o=await fetch(r,{method:"POST",headers:{Authorization:`Token ${n.apiKey}`,"Content-Type":t||"application/octet-stream"},body:e});if(!o.ok){let i=await o.text().catch(()=>""),c=oU(o.status,i);c.persistent&&(Bi={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 Bi=null,{transcript:(await o.json())?.results?.channels?.[0]?.alternatives?.[0]?.transcript??""}}ue();var Qh={"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 sU(e){if(!e)return null;let t=String(e).trim();if(Qh[t])return t;let n=null;for(let r of Object.keys(Qh))t.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function aU(e,t={}){let n=Qh[sU(e)];if(!n)return 0;let r=0;for(let o of Object.keys(n))r+=(Number(t[o])||0)*n[o];return r/1e6}function iU(e,t){let n=null;try{n=JSON.parse(t)}catch{}let r=n?.error?.code||n?.error?.type||"";return e===429&&/insufficient_quota/i.test(r)?{status:402,code:"credits_exhausted",persistent:!0,message:"The OpenAI account is out of credit \u2014 voice chat is down until you top up at platform.openai.com or drop a new key into ~/.bostrat/integrations.json."}:e===401||e===403?{status:502,code:"key_invalid",persistent:!0,message:"OpenAI rejected the API key (revoked, or missing Realtime access) \u2014 replace it in ~/.bostrat/integrations.json."}:{status:502,code:"mint_failed",persistent:!1,message:`OpenAI realtime session mint failed (${e}): ${t.slice(0,300)}`}}var ji=null;async function cU(){if(!ji)return null;let e=await su();if(!e||e.apiKey.slice(-6)!==ji.keyTail)return null;let{keyTail:t,...n}=ji;return n}async function lU(e){let t=await fetch("https://api.openai.com/v1/realtime/client_secrets",{method:"POST",headers:{Authorization:`Bearer ${e.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify({session:{type:"realtime",model:e.model,audio:{output:{voice:e.voice}}}})});if(!t.ok){let o=await t.text().catch(()=>""),s=iU(t.status,o);s.persistent&&(ji={code:s.code,message:s.message,at:Date.now(),keyTail:e.apiKey.slice(-6)});let a=new Error(s.message);throw a.status=s.status,a.code=s.code,a}ji=null;let n=await t.json(),r=n?.value??n?.client_secret?.value;if(!r){let o=new Error("OpenAI returned no client secret");throw o.status=502,o.code="mint_failed",o}return{clientSecret:{value:r,expiresAt:n?.expires_at??n?.client_secret?.expires_at??null}}}var uU={openai:lU};async function YE(){let e=await su();return e?{configured:!0,provider:e.provider,model:e.model,voice:e.voice,problem:await cU()}:{configured:!1}}async function ZE(){let e=await su();if(!e){let n=new Error("Voice chat is not configured \u2014 add openai.apiKey to ~/.bostrat/integrations.json");throw n.status=503,n.code="not_configured",n}let t=await uU[e.provider](e);return{provider:e.provider,model:e.model,voice:e.voice,...t}}async function QE(e,{model:t,usage:n={},seconds:r}={}){let o=c=>Math.max(0,Math.round(Number(c)||0)),s={textIn:o(n.textIn),textInCached:o(n.textInCached),textOut:o(n.textOut),audioIn:o(n.audioIn),audioInCached:o(n.audioInCached),audioOut:o(n.audioOut)},a=aU(t,s),i=await _(e,{type:"cost.recorded",actor:"user",provider:"openai-realtime",payload:{model:t||"unknown",usd:a,tokens:{input:s.textIn+s.audioIn,output:s.textOut+s.audioOut,cacheRead:s.textInCached+s.audioInCached,cacheWrite:0},voice:s,seconds:Math.max(0,Math.round(Number(r)||0)),source:"voice-chat"}});return{usd:a,seq:i.seq}}var sA=ge.dirname(fU(import.meta.url)),eA=Number(process.env.PORT)||3362,$u=Ym(process.env),aA=Number(process.env.BOSTRAT_AUTO_TRIGGER_PCT)||80,Fs=HT(process.env.BOSTRAT_ALLOW_IPS),ow=WT(process.env.BOSTRAT_VIEW_FRONT_CIDRS,xu),iA=KT(),cA=process.env.BOSTRAT_ALLOW_LAN_TOKENLESS!=="1",S=Rt();S.disable("x-powered-by");S.use((e,t,n)=>{t.setHeader("x-content-type-options","nosniff"),ku(e.headers.host)||(t.setHeader("x-frame-options","DENY"),t.setHeader("referrer-policy","strict-origin-when-cross-origin")),n()});S.use((e,t,n)=>{if(Mi(e)||Fs.allowed(Fs.clientIp(e))||ow.allows(e))return n();t.status(403).type("text/plain").send("bostrat: access restricted to the allowlist")});S.use(XT);S.use(zT({token:iA,enforce:cA}));S.use("/api/mocks",Rt.json({limit:"1mb"}));S.use("/api/mocks",Rt.raw({type:"image/png",limit:"24mb"}));S.use("/api/mocks",Rt.raw({type:["video/mp4","video/webm"],limit:"105mb"}));S.use("/api/runbooks",Rt.json({limit:"1mb"}));S.use("/api/tracks/adopt",Rt.json({limit:"1mb"}));S.use("/api/telemetry",Rt.json({limit:"256kb"}));S.use("/api/hook",Rt.json({limit:"2mb"}));S.use("/api/dictation",Rt.raw({type:["audio/*","video/mp4","application/octet-stream"],limit:"32mb"}));S.use("/api/tracks/:id/upload",Rt.raw({type:()=>!0,limit:"25mb"}));S.use(Rt.json({limit:"64kb"}));S.get("/api/health",async(e,t)=>{t.json({ok:!0,tmuxSocket:ft,hostTmuxAlive:await zn(),autoTriggerPct:aA})});S.get("/api/sessions",async(e,t)=>{t.json({sessions:await Ot()})});S.post("/api/sessions",async(e,t)=>{let{displayName:n,cwd:r}=e.body||{};if(typeof n!="string")return t.status(400).json({error:"displayName (string) required"});try{let o=await Jn(n,r||void 0);t.json({ok:!0,...o})}catch(o){let s=o?.message||String(o),a=/already exists/i.test(s)?409:/must be|invalid/i.test(s)?400:500;t.status(a).json({error:s})}});S.delete("/api/sessions/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!_e(n))return t.status(400).json({error:"invalid session name"});if(!await se(n))return t.status(404).json({error:"session not found"});try{await Ct(n),t.json({ok:!0})}catch(r){t.status(500).json({error:`failed to kill: ${r?.message||r}`})}});S.get("/api/context/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!_e(n))return t.status(400).json({error:"invalid session name"});let r=await se(n);if(!r)return t.status(404).json({error:"session not found"});let o=await ua(r.cwd,r.sessionId);if(!o)return t.json({available:!1,cwd:r.cwd,sessionId:r.sessionId||null});t.json({available:!0,...o})});S.post("/api/handoff/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!_e(n))return t.status(400).json({error:"invalid session name"});try{let r=await rb(n);t.json({ok:!0,step:r.step,file:r.file,startedAt:r.startedAt})}catch(r){t.status(409).json({error:r?.message||String(r)})}});S.get("/api/handoff/:name",(e,t)=>{let n=decodeURIComponent(e.params.name),r=Bc(n);if(!r)return t.json({running:!1});t.json({running:!r.finishedAt,step:r.step,error:r.error,file:r.file,startedAt:r.startedAt,finishedAt:r.finishedAt})});var tA=10;S.get("/api/idle-guard",async(e,t)=>{try{t.json(Xm({tracks:await ae(),views:await Sl(),queuedOf:n=>so(n)}))}catch{t.status(500).json({busy:!0,reasons:["error"]})}});var Ft=lo(),gU=Tv({kind:Ft}),Li=null,ut=()=>Li&&["auto","prompt","off"].includes(Li)?Li:gU,Ru=null;async function yU(e){let t=ut();Li=e??null;let n=ut();if(t!==n){if(console.log(`[self-update] policy ${t} \u2192 ${n} (${e?"plane row":"node default"})`),n!=="auto"){Us.cancel();return}Ru&&!xi(await As())&&Us.arm({to:Ru.latest,from:Ru.current,kind:Ft})}}var bU=(()=>{try{return wU(import.meta.url)("../package.json").version||null}catch{return null}})(),Us=Av({isBusy:async()=>Xm({tracks:await ae(),views:await Sl(),queuedOf:e=>so(e)}).busy,onStuck:({to:e,from:t})=>an({current:t,latest:e,installKind:Ft,policy:ut(),status:"stuck"}).catch(()=>{}),onStarted:({to:e,from:t,result:n})=>(n?.ok?an({current:t,latest:e,installKind:Ft,policy:ut(),status:"updating",reason:"auto"}):an({current:t,latest:e,installKind:Ft,policy:ut(),status:"failed",error:n?.reason})).catch(()=>{})});S.get("/api/node/self-update",async(e,t)=>{t.json({installKind:Ft,policy:ut(),policySource:Li?"plane":"node",current:bU,status:await As(),armed:Us.armed})});S.post("/api/node/self-update",async(e,t)=>{let n=typeof e.body?.to=="string"?e.body.to.trim():"";if(!/^\d+\.\d+\.\d+$/.test(n))return t.status(400).json({error:"body.to must be a release version (X.Y.Z)"});let r=await Ql({to:n,kind:Ft,reason:"manual"});if(r.ok)return Us.cancel(),an({current:r.from,latest:n,installKind:Ft,policy:ut(),status:"updating",reason:"manual"}).catch(()=>{}),t.json({ok:!0,...r});t.status(409).json({ok:!1,error:r.reason,status:r.status??null})});async function lA(){try{let e=await Ev();e&&await an({current:e.from,latest:e.to,installKind:e.kind||Ft,policy:ut(),status:e.status,error:e.error,reason:e.reason})}catch{}}lA();setInterval(lA,3e4).unref();S.get("/api/tracks",async(e,t)=>{let n=(await ae()).filter(s=>!s.transferredTo),r=n.filter(s=>s.archivedAt&&!s.archiving),o=n;if(e.query.archived!=="all"&&r.length>tA){let s=new Set([...r].sort((a,i)=>(i.archivedAt||0)-(a.archivedAt||0)).slice(0,tA).map(a=>a.id));o=n.filter(a=>!a.archivedAt||a.archiving||s.has(a.id))}t.json({tracks:o,archivedTotal:r.length,agents:fi,agentAvailability:await Pl(),tickets:await Xv()})});S.get("/api/cost",async(e,t)=>{try{let n=await ae();e.query.track&&(n=n.filter(o=>o.id===e.query.track));let r=await vT(n);if(r.cursorUsage=hp(),e.query.format==="text")return t.type("text/plain").send(TT(r));t.json(r)}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/usage/roundup",async(e,t)=>{try{t.json(await _T(await ae(),{window:e.query.window,from:e.query.from,to:e.query.to}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/usage/spend",async(e,t)=>{try{let n=await CT(await ae(),{window:e.query.window,from:e.query.from,to:e.query.to});n.cursorUsage=hp(),n.subscriptionMonthlyUsd=Number(process.env.BOSTRAT_SUBSCRIPTION_MONTHLY_USD)||null,n.caps=Ca(),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/usage/caps",(e,t)=>{t.json(Ca())});S.post("/api/usage/caps",async(e,t)=>{try{t.json(await Gc(e.body?.caps??{},{source:"local"}))}catch(n){t.status(400).json({error:n?.message||String(n)})}});S.get("/api/usage/limits",async(e,t)=>{try{let n=e.query.fresh==="1"||e.query.fresh==="true";t.json(await BT(await ae(),{fresh:n}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.post("/api/hook",async(e,t)=>{try{let{mode:n,target:r}=await cw(e.get(qi),{byToken:wm,legacy:()=>qa(e.body?.session_id,e.body?.cwd)});if(n==="refused")return Ws("refused",{reason:"unknown-token",hook:e.body?.hook_event_name}),t.json({ok:!1,error:"unknown hook token"});if(n==="legacy-denied")return Ws("legacy-denied",{reason:"tokenless-denied",hook:e.body?.hook_event_name}),t.status(401).json({ok:!1,error:"tokenless hook ingest is disabled (BOSTRAT_HOOK_LEGACY_DENY)"});n==="token"&&e.body?.session_id&&r.box?.sessionId&&e.body.session_id!==r.box.sessionId&&Ws("mismatch",{track:r.track.id,box:r.box.name}),Ws(n,{track:r?.track?.id,hook:e.body?.hook_event_name,...n==="legacy"?{reason:"tokenless-body-resolved",deny_with:"BOSTRAT_HOOK_LEGACY_DENY=1"}:{}});let o=await yT(e.body||{},()=>r);e.body?.hook_event_name==="Stop"&&r?.box?.cwd&&sc(r.box.cwd),t.json({ok:!0,events:o.length})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});S.post("/api/telemetry",async(e,t)=>{try{if(!DE(Fs.clientIp(e)))return t.json({ok:!0,dropped:!0});let n=await PE(e.body||{});t.json({ok:!0,events:n})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});S.get("/api/repos",async(e,t)=>{try{let n=await un(),r=new Set((await Promise.all(n.map(a=>me(a.path)))).filter(Boolean).map(a=>a.toLowerCase())),s=((await zs()).repos||[]).filter(a=>!r.has(String(a.slug).toLowerCase())).map(a=>({slug:a.slug,name:a.slug.split("/")[1],branch:a.defaultBranch||null,private:!!a.private,remote:!0}));t.json({repos:[...n,...s]})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/github/token",async(e,t)=>{try{t.json(await Xi(String(e.query.repo||"")))}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});S.get("/api/github/status",(e,t)=>{t.json({configured:Ji(),calls:ux(),latency:mx()})});S.post("/api/github/refresh",(e,t)=>{yw(),t.json({ok:!0})});S.get("/api/gmail/search",async(e,t)=>{try{let n=await LT(String(e.query.q||""),{max:Number(e.query.max)||10});t.json({messages:n})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});S.get("/api/gmail/messages/:id",async(e,t)=>{try{t.json({message:await FT(String(e.params.id))})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});function sw(e,t,n){let r=e.workspace;return r?.kind==="multi"?(r.repos??[]).some(o=>t&&o?.base===t||n&&o?.repo===n):!r?.base||!t||r.base===t||n&&r.repo===n}async function Ou({repo:e=null,number:t=null,branch:n=null}){let r=e?await me(e):null;if(r&&t!=null){let s=await qe(r,t),a=s&&await ne(s.trackId);if(a)return a}if(!n)return null;let o=await ae();return fl(o,n,s=>sw(s,e,r))}async function uA({repo:e=null,number:t=null,branch:n=null}){let r=await Ou({repo:e,number:t,branch:n}).catch(()=>null);if(r&&!r.archivedAt&&!r.transferredTo)return r;if(!n)return null;let o=e?await me(e).catch(()=>null):null,s=await ae();return fl(s,n,a=>!a.archivedAt&&!a.transferredTo&&sw(a,e,o))}async function Ut(e,{number:t,url:n=null,title:r=null,branch:o=null,repo:s=null,track:a=null,extra:i={}}){let c=a||await Ou({repo:s,number:t,branch:o}).catch(()=>null);if(!c)return;let l=i.repo??(s?await me(s).catch(()=>null):null);await _({id:c.id,cwd:c.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",payload:{ts:Date.now(),change:e,number:t,url:n,title:r,branch:o??c.workspace?.branch??null,...l?{repo:l}:{},...i}}).catch(()=>{})}async function kU(e){let t=(await ae()).filter(n=>!n.archivedAt&&!n.transferredTo);for(let n of e??[]){if(!n.prs?.length)continue;let r=await me(n.path);if(r)for(let o of n.prs){if(await qe(r,o.number))continue;let s=await fl(t,o.headRefName,a=>sw(a,n.path,r));s&&await mt({repo:r,number:o.number,trackId:s.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"})}}}S.get("/api/git/prs",async(e,t)=>{try{let n=await xx();await kU(n.repos).catch(()=>{}),await SE(n.repos).catch(()=>{}),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.post("/api/git/prs/merge",async(e,t)=>{let{repo:n,number:r,method:o,auto:s,update:a,archive:i,notify:c,headRefName:l,title:u,url:f}=e.body||{};try{if(s){let h=o||"merge";if(!La.has(h))throw new Error(`invalid merge method: ${h}`);let g=Number(r);if(!Number.isInteger(g)||g<=0)throw new Error("invalid PR number");let x=await me((await kn(n)).path);if(!x)throw new Error("repo has no GitHub remote");let k=await Ou({repo:n,number:g,branch:l}).catch(()=>null);if(!k)throw new Error("auto-merge needs a Track to watch this PR \u2014 none owns it");if(a&&await Fa(n,g),await mt({repo:x,number:g,trackId:k.id,url:f,headRef:l,title:u,source:"matched"}).catch(()=>{}),!await Na(x,g,{merge:{method:h}}))throw new Error("couldn't record the auto-merge arm");return await Jr(x,g,i===!0),await Pa(x,g,c===!0&&i!==!0),Yt(),await Ut("auto-armed",{number:g,url:f,title:u,branch:l,repo:n,track:k,...a?{extra:{updated:!0}}:{}}),t.json({ok:!0,number:g,auto:!0})}let d=await os(n,r,{method:o||"squash"});await Ut("merged",{number:d.number,url:f,title:u,branch:l,repo:n});let p=await me(n).catch(()=>null),m=!1;if(p&&(i===!0&&await Jr(p,d.number,!0).catch(()=>{}),c===!0&&i!==!0&&await Pa(p,d.number,!0).catch(()=>{}),await Sn(p,d.number).catch(()=>{}),m=await xn(p,d.number).catch(()=>!1),await ir(p,d.number,"merged").catch(()=>{})),i===!0&&!m){let h=await Ou({repo:n,number:d.number,branch:l}).catch(()=>null);h&&!h.archivedAt&&await io(h.id).catch(()=>{})}t.json(d)}catch(d){let p=d?.message||String(d),m=/invalid|unknown repo|required|needs a Track|no GitHub remote/i.test(p)?400:502;t.status(m).json({error:p})}});S.post("/api/git/prs/disarm-auto",async(e,t)=>{let{repo:n,number:r,headRefName:o,title:s,url:a}=e.body||{};try{let i=Number(r);if(!Number.isInteger(i)||i<=0)throw new Error("invalid PR number");let c=await me((await kn(n)).path).catch(()=>null),l=c?await Da(c,i).catch(()=>null):null;try{await Zf(n,i)}catch(u){if(!l)throw u}Yt(),await Ut("auto-canceled",{number:i,url:a,title:s,branch:o,repo:n}),t.json({ok:!0,number:i})}catch(i){let c=i?.message||String(i),l=/invalid|unknown repo|required/i.test(c)?400:502;t.status(l).json({error:c})}});S.post("/api/git/prs/merge-all",async(e,t)=>{let{repo:n,method:r}=e.body||{};try{let o=await me(n).catch(()=>null),s=await Ex(n,{method:r||"merge",onMerged:a=>{Ut("merged",{number:a.number,url:a.url,title:a.title,branch:a.headRefName,repo:n}),o&&Sn(o,a.number).catch(()=>{}).then(()=>xn(o,a.number)).catch(()=>{}).then(()=>ir(o,a.number,"merged")).catch(()=>{})}});t.json(s)}catch(o){let s=o?.message||String(o),a=/already running/i.test(s)?409:/invalid|unknown repo|no PRs ready/i.test(s)?400:502;t.status(a).json({error:s})}});S.get("/api/git/prs/merge-all",(e,t)=>{t.json({jobs:Tx()})});S.post("/api/git/prs/merge-track",async(e,t)=>{let{trackId:n,update:r,archive:o,notify:s,method:a}=e.body||{};try{let i=a||"merge";if(!La.has(i))throw new Error(`invalid merge method: ${i}`);if(!n)return t.status(400).json({error:"trackId required"});let c=await ne(n);if(!c)return t.status(404).json({error:`Track ${n} isn't on this node`});let l=(await Xr()).filter(d=>d.trackId===c.id&&d.state!=="merged"&&d.state!=="closed");if(!l.length)return t.status(409).json({error:"no open PRs on this Track"});for(let d of l)await Jr(d.repo,d.number,o===!0).catch(()=>{}),await Pa(d.repo,d.number,s===!0&&o!==!0).catch(()=>{});let u=[],f=[];for(let d of l){let p={repo:d.repo,number:d.number,ok:!0,action:"armed"};u.push(p);try{let m=await Zr(d.repo);if(!m)throw new Error(`no local checkout for ${d.repo}`);let h=await rs(m,d.number);f.push({r:p,l:d,repoPath:m,pr:h,plan:Sx(h,{update:r!==!1})})}catch(m){p.ok=!1,p.action="failed",p.reason=m?.message||String(m)}}for(let{r:d,l:p,repoPath:m,pr:h,plan:g}of vx(f))try{if(g.action==="skip")d.action="skipped",d.reason=g.reason;else if(g.action==="merge")await os(m,p.number,{method:i}),await Ut("merged",{number:p.number,url:h.url,title:h.title,branch:h.headRefName,repo:m,track:c}),await Sn(p.repo,p.number).catch(()=>{}),await xn(p.repo,p.number).catch(()=>{}),await ir(p.repo,p.number,"merged").catch(()=>{}),d.action="merged";else{if(g.action==="update-arm"&&(await Fa(m,p.number).catch(()=>{}),d.action="updated-armed"),!await Na(p.repo,p.number,{merge:{method:i}}))throw new Error("couldn't record the auto-merge arm");await Ut("auto-armed",{number:p.number,url:h.url,title:h.title,branch:h.headRefName,repo:m,track:c,...d.action==="updated-armed"?{extra:{updated:!0}}:{}})}}catch(x){d.ok=!1,d.action="failed",d.reason=x?.message||String(x)}if(Yt(),!u.some(d=>d.ok)){if(o===!0)for(let d of l)await Jr(d.repo,d.number,!1).catch(()=>{});if(s===!0&&o!==!0)for(let d of l)await Pa(d.repo,d.number,!1).catch(()=>{});return t.status(502).json({error:u.map(d=>`${d.repo}#${d.number}: ${d.reason}`).join("; "),results:u})}t.json({ok:!0,trackId:c.id,results:u})}catch(i){let c=i?.message||String(i),l=/invalid|required/i.test(c)?400:502;t.status(l).json({error:c})}});S.post("/api/git/prs/disarm-track",async(e,t)=>{let{trackId:n}=e.body||{};try{if(!n)return t.status(400).json({error:"trackId required"});let r=await ne(n);if(!r)return t.status(404).json({error:`Track ${n} isn't on this node`});let o=(await Xr()).filter(a=>a.trackId===r.id&&a.state!=="merged"&&a.state!=="closed"),s=[];for(let a of o){let i=await Da(a.repo,a.number).catch(()=>null),c=await Zr(a.repo).catch(()=>null);c&&await Zf(c,a.number).catch(()=>{}),i&&(await Ut("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}))}Yt(),t.json({ok:!0,trackId:r.id,canceled:s})}catch(r){let o=r?.message||String(r),s=/invalid|required/i.test(o)?400:502;t.status(s).json({error:o})}});S.post("/api/git/prs/open",async(e,t)=>{let{trackId:n,title:r,body:o,base:s,repos:a}=e.body||{};try{if(!n)return t.status(400).json({error:"trackId required"});let i=await ne(n);if(!i)return t.status(404).json({error:`Track ${n} isn't on this node`});if(i.workspace?.kind==="multi"){let u=gt(i.workspace),f,d=Array.isArray(a)?a.filter(Boolean):[];if(d.length)f=d.map(h=>{let g=u.find(x=>x.name===h||x.repo===h||x.base===h||x.dir===h);if(!g)throw new Error(`invalid repo "${h}" \u2014 not tagged on this Track`);return g});else if(f=await ls(i),!f.length)return t.status(409).json({error:"no tagged repo has work to ship"});let p=[];for(let h of f)try{let g=await ep(h.dir,{title:r,body:o,base:s}),x=h.repo||await me(h.dir).catch(()=>null);x&&g.number&&await mt({repo:x,number:g.number,trackId:i.id,url:g.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await Ut("opened",{number:g.number,url:g.url,title:r,track:i,branch:i.workspace?.branch,extra:{repo:x??h.name}}),p.push({repo:h.name,slug:x??null,ok:!0,url:g.url,number:g.number})}catch(g){p.push({repo:h.name,slug:h.repo??null,ok:!1,error:g?.message||String(g)})}let m=p.filter(h=>h.ok);return m.length?t.json({ok:!0,multi:!0,results:p,url:m[0].url,number:m[0].number}):t.status(502).json({error:p.map(h=>`${h.repo}: ${h.error}`).join("; "),results:p})}let c=await ep(i.cwd,{title:r,body:o,base:s}),l=await me(i.cwd).catch(()=>null);l&&c.number&&await mt({repo:l,number:c.number,trackId:i.id,url:c.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await Ut("opened",{number:c.number,url:c.url,title:r,track:i,branch:i.workspace?.branch,extra:{...l?{repo:l}:{}}}),t.json(c)}catch(i){let c=i?.message||String(i),l=/required|invalid/i.test(c)?400:502;t.status(l).json({error:c})}});S.get("/api/tracks/:id/repos",async(e,t)=>{try{let n=await ne(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await ls(n),o=new Map(r.map(a=>[a.base,a])),s=gt(n.workspace).map(a=>{let i=o.get(a.base);return{name:a.name,base:a.base,baseRef:a.baseRef??null,repo:a.repo??null,dirty:i?.dirty??!1,ahead:i?.ahead??0,changed:!!i}});t.json({repos:s,branch:n.workspace?.branch??null,kind:n.workspace?.kind??null})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.post("/api/tracks/:id/repos",async(e,t)=>{let{repo:n}=e.body||{};try{if(!n||typeof n!="string")return t.status(400).json({error:"repo (path or owner/name) required"});let r=await _m(e.params.id,n);t.json({ok:!0,added:{name:r.name,base:r.base,baseRef:r.baseRef??null,repo:r.repo??null}})}catch(r){let o=r?.message||String(r),s=/not found/i.test(o)?404:/already tagged|needs a multi|not a usable|archived|required/i.test(o)?400:502;t.status(s).json({error:o})}});S.delete("/api/tracks/:id/repos/:name",async(e,t)=>{try{let n=await Im(e.params.id,e.params.name);t.json({ok:!0,...n})}catch(n){let r=n?.message||String(n),o=/track .* not found/i.test(r)?404:/has work|still running|last repo/i.test(r)?409:/needs a multi|not tagged/i.test(r)?400:502;t.status(o).json({error:r})}});S.post("/api/git/prs/fix",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await rs(n,r),s=await me(n).catch(()=>null),a=await uA({repo:n,number:r,branch:o.headRefName});if(!a)return t.status(404).json({error:`no active Track owns PR #${o.number} (branch "${o.headRefName}")`});let i=gt(a.workspace).find(x=>x.base===n||s&&x.repo===s)??null,c=a.workspace?.kind==="multi",l=await Ax(n,o.number);if(!l.length)return t.status(409).json({error:"no failing checks on this PR"});let u=c&&i?ge.join("ci",i.name):"ci",f=ge.join(a.cwd,".bostrat",u),d=ge.join(".bostrat",u,`pr-${o.number}-fail.log`);await Ye.promises.mkdir(f,{recursive:!0}),await Ye.promises.writeFile(ge.join(a.cwd,d),l.map(x=>`\u2550\u2550\u2550\u2550 ${x.name}${x.link?` \xB7 ${x.link}`:""} \u2550\u2550\u2550\u2550
594
600
  ${x.log??"(no fetchable log \u2014 see link)"}
595
601
  `).join(`
596
- `));let p=l.map(x=>x.name).join(", "),m=c&&i?` in the ${i.name}/ checkout`:"",h=await It(a.id,`CI is red on PR #${o.number} "${o.title}" (${o.url}) \u2014 branch ${o.headRefName}${m}. Failing check${l.length===1?"":"s"}: ${p}. The failure log is at ${d} in this ${c?"workspace":"worktree"} \u2014 read it, fix the root cause${c&&i?` in ${i.name}/`:""}, run the relevant tests locally, then commit and push to update the PR.`,{kind:"ci-fix"}),g=s;g&&(await mt({repo:g,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await Fk(g,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await Ut("fix-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{checks:l.map(x=>x.name)}}),t.json({ok:!0,leadBox:h.leadBox,queued:!!h.queued,checks:l.map(x=>x.name),log:d})}catch(o){let s=o?.message||String(o),a=/unknown repo|invalid|required/i.test(s)?400:/not found|no active Track/i.test(s)?404:502;t.status(a).json({error:s})}});S.post("/api/git/prs/reconcile",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await es(n,r);if(o.mergeable!=="CONFLICTING")return t.status(409).json({error:"this PR does not conflict with its base branch"});let s=await me(n).catch(()=>null),a=await nA({repo:n,number:r,branch:o.headRefName});if(!a)return t.status(404).json({error:`no active Track owns PR #${o.number} (branch "${o.headRefName}")`});let i=gt(a.workspace).find(f=>f.base===n||s&&f.repo===s)??null,c=a.workspace?.kind==="multi"&&i?` In the ${i.name}/ checkout:`:"",l=await It(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 mt({repo:u,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await Uk(u,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await Ut("reconcile-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{base:o.baseRefName}}),t.json({ok:!0,leadBox:l.leadBox,queued:!!l.queued,base:o.baseRefName})}catch(o){let s=o?.message||String(o),a=/unknown repo|invalid|required/i.test(s)?400:/not found|no active Track/i.test(s)?404:502;t.status(a).json({error:s})}});S.post("/api/tracks/:id/pr-offer",async(e,t)=>{let{offerId:n,action:r}=e.body||{};try{let o=null;if(Array.isArray(e.body?.actions)){if(o=zo.filter(f=>e.body.actions.includes(f)),!o.length)return t.status(400).json({error:"actions must include commit, rebase, push and/or pr"})}else if(r==="pr")o=["commit","push","pr"];else if(r==="push")o=["commit","push"];else if(r!=="dismiss")return t.status(400).json({error:'offerId and actions ["commit"|"rebase"|"push"|"pr"] (or action "dismiss") required'});if(!n)return t.status(400).json({error:"offerId required"});let s=o!=null&&e.body?.notify===!0,a=await ne(e.params.id);if(!a)return t.status(404).json({error:"track not found"});let i=await L(a),c=i.find(f=>f.type==="pr.offered"&&f.payload?.offerId===n);if(!c)return t.status(404).json({error:"unknown offer"});if(i.some(f=>f.type==="pr.offer.answered"&&f.payload?.offerId===n))return t.status(409).json({error:"offer already answered"});if(o?.includes("pr")){let f=await Lh(a,c,{actions:o,notify:s});if(f)return t.json({ok:!0,offerId:n,action:"pr-exists",actions:o,notify:s,existingPr:f.pr})}let l=null;o&&(l=await It(a.id,Jo(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 _({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&&gm(a.id,{actions:o}),t.json({ok:!0,offerId:n,action:u,actions:o,notify:s,queued:!!l?.queued})}catch(o){let s=o?.message||String(o),a=/required|invalid/i.test(s)?400:/not found|not running|archived/i.test(s)?409:502;t.status(a).json({error:s})}});S.post("/api/tracks/:id/pr-exists",async(e,t)=>{let{offerId:n,choice:r}=e.body||{};try{let o=await ne(e.params.id);if(!o)return t.status(404).json({error:"track not found"});let{say:s}=await Fh(o,{offerId:n,choice:r});t.json({ok:!0,offerId:n,choice:r,queued:!!s?.queued})}catch(o){let s=o?.message||String(o),a=/required|invalid/i.test(s)?400:/unknown offer/i.test(s)?404:/already answered|not found|not running|archived/i.test(s)?409:502;t.status(a).json({error:s})}});var Di=e=>t=>({...t,url:qT(t,e.headers)});S.get("/api/views",async(e,t)=>{try{let n=await yl({trackId:e.query.track||void 0});t.json({views:n.map(Di(e)),maxLive:mr})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/views/:id",async(e,t)=>{let n=await mx(e.params.id);if(!n)return t.status(404).json({error:"view not found"});t.json({view:Di(e)(n),session:is(n.slug)})});S.post("/api/views",async(e,t)=>{let{trackId:n,name:r,cmd:o,cwd:s,port:a}=e.body||{};try{let i=n?await ne(n):null;if(!i&&s&&(i=(await ae()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+ge.sep)))||null),!i)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let c=await vp({trackId:i.id,name:r,cmd:o,cwd:i.cwd,serveCwd:s,port:a,box:i.leadBox,branch:i.workspace?.branch??null});t.json({ok:!0,view:Di(e)(c)})}catch(i){let c=i?.message||String(i),l=i?.status??(/cap reached/i.test(c)?409:/required|invalid|already owned|no free/i.test(c)?400:500);t.status(l).json({error:c})}});S.post("/api/views/:id/stop",async(e,t)=>{try{t.json({ok:!0,view:Di(e)(await hx(e.params.id))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});S.post("/api/views/:id/restart",async(e,t)=>{try{t.json({ok:!0,view:Di(e)(await wx(e.params.id))})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/cap reached|no known command/i.test(r)?409:500;t.status(o).json({error:r})}});S.delete("/api/views/:id",async(e,t)=>{try{t.json(await gx(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});var aU=[["linear",uo,rh],["jira",eu,th]],zh=new Map;S.get("/api/integrations/ticketing",async(e,t)=>{try{let n=await eh(),r={};for(let[o,s,a]of aU){let i=await s();if(!i){zh.delete(o),r[o]={configured:!1};continue}let c=zh.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},zh.set(o,c)}r[o]={...c.body,flow:n},o==="jira"&&i.tokenExpiresAt&&(r[o].tokenExpiresAt=i.tokenExpiresAt)}t.json(r)}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/tickets/flow",async(e,t)=>{try{t.json({flow:await eh()})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.post("/api/tickets/flow",async(e,t)=>{let{trackId:n,cwd:r,set:o,actor:s}=e.body||{};try{let a=await _v(o),i=n?await ne(n):null;!i&&r&&(i=(await ae()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+ge.sep)))||null),i&&await _({id:i.id,cwd:i.cwd},{type:"ticket.flow.changed",actor:s==="user"?"user":"agent",source:"orchestrator",payload:{ts:Date.now(),set:{...o},flow:a}}).catch(()=>{}),t.json({ok:!0,flow:a})}catch(a){let i=a?.message||String(a);t.status(/unknown|nothing to set/i.test(i)?400:500).json({error:i})}});var wo=async(e,t)=>{let n=e?await ne(e):null;return!n&&t&&(n=(await ae()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+ge.sep)))||null),n};S.get("/api/circuits",async(e,t)=>{try{t.json({circuits:await Ym()})}catch(n){t.status(502).json({error:n?.message||String(n)})}});S.post("/api/circuits/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=await wo(n,r);if(!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});if(!o)return t.status(400).json({error:"ref (circuit name or id) required"});let a=await vs(o);await Yl(s,a,{source:"chat"}),t.json({ok:!0,trackId:s.id,circuit:a})}catch(s){let a=s?.message||String(s);t.status(/required|no circuit|names \d|no plane/i.test(a)?400:502).json({error:a})}});S.post("/api/circuits/unlink",async(e,t)=>{let{trackId:n,cwd:r}=e.body||{};try{let o=await wo(n,r);if(!o)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});await Yl(o,null,{source:"chat"}),t.json({ok:!0,trackId:o.id})}catch(o){t.status(502).json({error:o?.message||String(o)})}});var rA=async(e,t,n)=>{if(e)return{ref:e,track:await wo(t,n)};let r=await wo(t,n),o=r?await Zm(r.id):null;if(!o)throw new Error(r?"this Track isn't in a circuit \u2014 pass --circuit <name-or-id> (or link one first: bostrat-circuit link \u2026)":"run from inside a Track workspace, or pass --circuit <name-or-id>");return{ref:o,track:r}};S.post("/api/blueprints/publish",async(e,t)=>{let{trackId:n,cwd:r,circuit:o,newCircuit:s,name:a,markdown:i}=e.body||{};try{if(!i||!String(i).trim())return t.status(400).json({error:"markdown required"});let{ref:c}=s?{ref:null}:await rA(o,n,r),l=await kv({circuitRef:c,newCircuitName:s,name:a,markdown:i});t.json({ok:!0,...l})}catch(c){let l=c?.message||String(c);t.status(/required|no circuit|names \d|no plane|isn't in a circuit|run from inside/i.test(l)?400:502).json({error:l})}});S.get("/api/blueprints/show",async(e,t)=>{try{let{ref:n}=await rA(e.query.circuit,e.query.track,e.query.cwd);t.json(await Xm(n))}catch(n){let r=n?.message||String(n);t.status(/no blueprint|no circuit|isn't in a circuit|run from inside|names \d/i.test(r)?404:502).json({error:r})}});S.post("/api/decisions/record",async(e,t)=>{let{trackId:n,cwd:r,title:o,context:s,decision:a,alternatives:i,supersedesId:c}=e.body||{};try{let l=await wo(n,r);if(!l)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let u=await Sv(l,{title:o,context:s,decision:a,alternatives:i,supersedesId:c});t.json({ok:!0,trackId:l.id,...u})}catch(l){let u=l?.message||String(l);t.status(/required/i.test(u)?400:502).json({error:u})}});S.get("/api/decisions",async(e,t)=>{try{let n=await wo(e.query.track,e.query.cwd);if(!n)return t.status(400).json({error:"run from inside a Track workspace"});t.json(await vv(n.id))}catch(n){let r=n?.message||String(n);t.status(/no plane|required|run from inside/i.test(r)?400:502).json({error:r})}});S.post("/api/blueprints/tag",async(e,t)=>{let{trackId:n,cwd:r,itemIds:o}=e.body||{};try{let s=Array.isArray(o)?o.map(String):[];if(!s.length)return t.status(400).json({error:"itemIds required (BP-\u2026 ids)"});let a=await wo(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=await Zm(a.id);if(!i)return t.status(400).json({error:"this Track isn't in a circuit \u2014 link one first (bostrat-circuit link \u2026)"});let c=await xv(a,i,s);t.json({ok:!0,trackId:a.id,...c})}catch(s){let a=s?.message||String(s);t.status(/unknown\/unbindable|required|no blueprint|isn't in a circuit/i.test(a)?400:502).json({error:a})}});S.post("/api/tickets/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=n?await ne(n):null;if(!s&&r&&(s=(await ae()).find(c=>c.cwd&&(r===c.cwd||r.startsWith(c.cwd+ge.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});if(!o)return t.status(400).json({error:"ref (issue URL or key) required"});let a=await As(s,o,{source:n?"api":"cli"});t.json({ok:!0,trackId:s.id,ticket:a})}catch(s){let a=s?.message||String(s);t.status(/not a Linear|not found|no ticketing|required/i.test(a)?400:502).json({error:a})}});S.get("/api/tickets/status",async(e,t)=>{let{cwd:n,track:r}=e.query;try{let o=r?await ne(r):null;if(!o&&n&&(o=(await ae()).find(a=>a.cwd&&(n===a.cwd||String(n).startsWith(a.cwd+ge.sep)))||null),!o)return t.status(400).json({error:"track (or a cwd inside a Track workspace) required"});t.json({trackId:o.id,configured:await Wv(),ticket:await an(o.id)})}catch(o){t.status(500).json({error:o?.message||String(o)})}});S.get("/api/tracks/:id/ticket",async(e,t)=>{t.json({ticket:await an(e.params.id)})});S.post("/api/tracks/:id/ticket",async(e,t)=>{try{let n=await ne(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await As(n,(e.body||{}).ref,{source:"api"});t.json({ok:!0,ticket:r})}catch(n){let r=n?.message||String(n);t.status(/not a Linear|not found|no ticketing|required/i.test(r)?400:502).json({error:r})}});S.delete("/api/tracks/:id/ticket",async(e,t)=>{t.json({ok:!0,removed:await hh(e.params.id)})});var Ru=e=>/no ticket linked|unknown offer|unknown state/i.test(e)?404:/already answered/i.test(e)?409:/required|no ticketing/i.test(e)?400:502;S.get("/api/tracks/:id/ticket/states",async(e,t)=>{try{t.json(await Vv(e.params.id))}catch(n){let r=n?.message||String(n);t.status(Ru(r)).json({error:r})}});S.post("/api/tracks/:id/ticket/state",async(e,t)=>{try{t.json({ok:!0,...await wh(e.params.id,(e.body||{}).stateId)})}catch(n){let r=n?.message||String(n);t.status(Ru(r)).json({error:r})}});S.post("/api/tracks/:id/ticket/comment",async(e,t)=>{try{t.json({ok:!0,...await zv(e.params.id,(e.body||{}).body)})}catch(n){let r=n?.message||String(n);t.status(Ru(r)).json({error:r})}});S.post("/api/tracks/:id/ticket-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{let o=await ne(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await Jv(o,n,r===!0)})}catch(o){let s=o?.message||String(o);t.status(Ru(s)).json({error:s})}});S.post("/api/tracks/:id/fullscreen-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{t.json(await Cm(e.params.id,n,r===!0))}catch(o){let s=o?.message||String(o),a=/not found|unknown offer/.test(s)?404:/already answered/.test(s)||/mid-turn/.test(s)?409:500;t.status(a).json({error:s})}});S.post("/api/tickets/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await ne(n):null;if(!s&&r&&(s=(await ae()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+ge.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,proposal:await Xv(s,o)})}catch(s){let a=s?.message||String(s);t.status(/no ticketing|are off|needs an epic|too many|required/i.test(a)?400:502).json({error:a})}});S.get("/api/tickets/teams",async(e,t)=>{try{t.json({teams:await Yv()})}catch(n){let r=n?.message||String(n);t.status(/no ticketing/i.test(r)?400:502).json({error:r})}});S.post("/api/tracks/:id/ticket-create-offer",async(e,t)=>{let{proposalId:n,accept:r,teamId:o}=e.body||{};try{let s=await ne(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await Zv(s,n,r===!0,{teamId:o||null})})}catch(s){let a=s?.message||String(s);t.status(/unknown proposal|unknown team/i.test(a)?404:/already answered/i.test(a)?409:/required|no ticketing|pick one/i.test(a)?400:502).json({error:a})}});S.get("/api/mocks",async(e,t)=>{try{t.json({mocks:await Va({trackId:e.query.track||void 0,group:e.query.group||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/mocks/:id",async(e,t)=>{let n=await En(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});t.json({mock:n})});var Bi={dotfiles:"allow"};S.get("/api/mocks/:id/png",async(e,t)=>{let n=await En(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=Bt(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=Ka(n,r,"png");if(!o)return t.status(404).json({error:"no image for this version (poster extraction failed)"});t.set("cache-control","private, max-age=31536000, immutable"),t.sendFile(o,Bi,s=>{s&&!t.headersSent&&t.status(404).json({error:"rendered artifact missing"})})});S.get("/api/mocks/:id/media",async(e,t)=>{let n=await En(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=Bt(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=Ka(n,r,"video");if(!o)return t.status(404).json({error:"this version has no video (image or html sourced)"});t.set("cache-control","private, max-age=31536000, immutable"),t.sendFile(o,Bi,s=>{s&&!t.headersSent&&t.status(404).json({error:"video artifact missing"})})});S.get("/api/mocks/:id/html",async(e,t)=>{let n=await En(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=Bt(n,e.query.v??null);if(!r?.htmlRel)return t.status(404).json({error:"this version has no HTML source (image-sourced)"});t.set("content-security-policy","sandbox"),t.sendFile(Et(n,r.v).html,Bi,o=>{o&&!t.headersSent&&t.status(404).json({error:"source artifact missing"})})});S.post("/api/mocks",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&Sl(n)?n:null,o=n&&!r?n:null,s=n?e.query:e.body||{},{trackId:a,name:i,cwd:c,width:l,group:u}=s;try{let f=a?await ne(a):null;if(!f&&c&&(f=(await ae()).find(h=>h.cwd&&(c===h.cwd||c.startsWith(h.cwd+ge.sep)))||null),!f)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let d=(f.boxes||[]).find(m=>m.name===f.leadBox),p=await Nx({trackId:f.id,name:i,html:n?null:s.html,image:r,video:o,cwd:f.cwd,width:l,group:u,box:f.leadBox,agent:d?.agent||null});t.json({ok:!0,mock:p})}catch(f){let d=f?.message||String(f);t.status(/required|invalid|must be/i.test(d)?400:500).json({error:d})}});S.post("/api/mocks/:id/update",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&Sl(n)?n:null;try{let o=await Px(e.params.id,{html:n?null:(e.body||{}).html,image:r,video:n&&!r?n:null,width:n?e.query.width:(e.body||{}).width});t.json({ok:!0,mock:o})}catch(o){let s=o?.message||String(o),a=/not found/i.test(s)?404:/required|invalid|must be/i.test(s)?400:500;t.status(a).json({error:s})}});S.post("/api/mocks/:id/pick",async(e,t)=>{try{let{mock:n,siblings:r}=await jx(e.params.id),o=r.length?` over ${r.map(s=>`"${s.name}"`).join(", ")}`:"";await It(n.trackId,`Design decision: go with "${n.name}" (mock:${n.id})${o} \u2014 proceed with this design.`,{kind:"mock-picked"}).catch(()=>{}),t.json({ok:!0,mock:n,siblings:r})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/nothing to pick/i.test(r)?409:500;t.status(o).json({error:r})}});S.delete("/api/mocks/:id",async(e,t)=>{try{let n=(await nS(e.params.id)).map(r=>({id:r.id,name:r.name}));t.json({...await Lx(e.params.id),...n.length?{danglingFlows:n}:{}})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});S.get("/api/flows",async(e,t)=>{try{t.json({flows:await Xx({trackId:e.query.track||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/flows/:id",async(e,t)=>{let n=await Zx(e.params.id);if(!n)return t.status(404).json({error:"flow not found"});t.json({flow:n})});S.post("/api/flows",async(e,t)=>{let{trackId:n,name:r,steps:o,cwd:s}=e.body||{};try{let a=n?await ne(n):null;if(!a&&s&&(a=(await ae()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+ge.sep)))||null),!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=(a.boxes||[]).find(l=>l.name===a.leadBox),c=await Qx({trackId:a.id,name:r,steps:o,cwd:a.cwd,box:a.leadBox,agent:i?.agent||null});t.json({ok:!0,flow:c})}catch(a){let i=a?.message||String(a),c=/already exists/i.test(i)?409:/required|invalid|no mock|ambiguous|over \d+ chars|must be|no captured/i.test(i)?400:500;t.status(c).json({error:i})}});S.post("/api/flows/:id/update",async(e,t)=>{try{let{steps:n,note:r}=e.body||{};t.json({ok:!0,flow:await eS(e.params.id,{steps:n,note:r})})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/required|invalid|no mock|ambiguous|over \d+ chars|must be|no captured/i.test(r)?400:500;t.status(o).json({error:r})}});S.delete("/api/flows/:id",async(e,t)=>{try{t.json(await tS(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});S.get("/api/runbooks",async(e,t)=>{try{let n=e.query.track||void 0;if(!n&&e.query.cwd){let s=await ae(),a=String(e.query.cwd);if(n=s.find(i=>i.cwd&&(a===i.cwd||a.startsWith(i.cwd+ge.sep)))?.id,!n)return t.json({runbooks:[]})}let{runbooks:r,fleetDegraded:o}=await uS({trackId:n,status:e.query.status||void 0});t.json({runbooks:r,...o?{fleetDegraded:!0}:{}})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/runbooks/:id",async(e,t)=>{let n=await Bp(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});t.json({runbook:n})});S.get("/api/runbooks/:id/md",async(e,t)=>{let n=await Bp(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});let r=cS(n,e.query.v??null);if(!r)return t.status(404).json({error:"no such version"});if(t.set("content-security-policy","sandbox"),t.set("cache-control","private, max-age=31536000, immutable"),t.type("text/markdown; charset=utf-8"),n.remote){let o=await dS(n,r.v);return typeof o!="string"?t.status(404).json({error:"runbook artifact missing"}):t.send(o)}t.sendFile(Rn(n,r.v),Bi,o=>{o&&!t.headersSent&&t.status(404).json({error:"runbook artifact missing"})})});S.get("/api/loops",async(e,t)=>{t.json(await dl())});S.post("/api/loops/report",async(e,t)=>{let{outcome:n,note:r,cwd:o}=e.body||{};if(!["ok","acted","attention"].includes(n))return t.status(400).json({error:"outcome must be one of ok | acted | attention"});if(!o)return t.status(400).json({error:"cwd required"});let a=(await ae()).find(u=>u.cwd&&(o===u.cwd||o.startsWith(u.cwd+ge.sep)))||null;if(!a)return t.status(400).json({error:"cwd is not inside a Track workspace"});let i=await dl();if(i.source!=="plane")return t.status(503).json({error:i.source==="unconfigured"?"this node isn't linked to a plane \u2014 loops live in the plane":`plane unreachable (${i.error||"no detail"})`});let c=i.loops.find(u=>u.trackId===a.id);if(!c)return t.status(404).json({error:`Track "${a.name}" is not a loop's run Track \u2014 nothing to report on`});let l=await np({loopId:c.id,outcome:n,note:r});if(!l.ok)return t.status(l.status||503).json({error:l.error||"report failed"});t.json({ok:!0,loop:{id:c.id,name:c.name},run:l.run})});S.post("/api/loops/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await ne(n):null;if(!s&&r&&(s=(await ae()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+ge.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,proposal:await YT(s,o)})}catch(s){t.status(400).json({error:s?.message||String(s)})}});S.post("/api/tracks/:id/loop-create-offer",async(e,t)=>{let{proposalId:n,accept:r,loopId:o,nextFireAt:s}=e.body||{};try{let a=await ne(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await XT(a,n,r===!0,{loopId:o||null,nextFireAt:s??null})})}catch(a){let i=a?.message||String(a);t.status(/unknown proposal/i.test(i)?404:/already answered/i.test(i)?409:400).json({error:i})}});S.post("/api/runbooks",async(e,t)=>{let{trackId:n,name:r,md:o,cwd:s}=e.body||{};try{let a=n?await ne(n):null;if(!a&&s&&(a=(await ae()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+ge.sep)))||null),!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=(a.boxes||[]).find(l=>l.name===a.leadBox),c=await fS({trackId:a.id,trackName:a.name,name:r,md:o,cwd:a.cwd,box:a.leadBox,agent:i?.agent||null});t.json({ok:!0,runbook:c})}catch(a){let i=a?.message||String(a);t.status(/required|invalid|over the|secret VALUE/i.test(i)?400:500).json({error:i})}});S.post("/api/runbooks/:id/update",async(e,t)=>{try{let{md:n,note:r}=e.body||{};t.json({ok:!0,runbook:await pS(e.params.id,{md:n,note:r})})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/orphaned/i.test(r)?410:/required|invalid|over the|secret VALUE/i.test(r)?400:500;t.status(o).json({error:r})}});S.post("/api/runbooks/:id/status",async(e,t)=>{try{t.json({ok:!0,runbook:await mS(e.params.id,(e.body||{}).status)})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/orphaned/i.test(r)?410:/must be/i.test(r)?400:500;t.status(o).json({error:r})}});S.delete("/api/runbooks/:id",async(e,t)=>{try{t.json(await hS(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});S.get("/api/changelog/draft",async(e,t)=>{try{let n=nE(e.query.since||null);t.json({since:n,repos:Mh(),...await rE(n)})}catch(n){let r=n?.message||String(n);t.status(/unparseable/i.test(r)?400:500).json({error:r})}});var oA=async({trackId:e,cwd:t})=>{let n=e?await ne(e):null;return!n&&t&&(n=(await ae()).find(o=>o.cwd&&(t===o.cwd||String(t).startsWith(o.cwd+ge.sep)))||null),n};S.post("/api/changelog/publish",async(e,t)=>{let{md:n,day:r,trackId:o,cwd:s}=e.body||{};try{let a=await oA({trackId:o,cwd:s});if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,entry:await oE(a,{md:n,day:r})})}catch(a){let i=a?.message||String(a);t.status(/required|invalid|no `- `|over the|secret VALUE|mentions "/i.test(i)?400:500).json({error:i})}});S.post("/api/changelog/retract",async(e,t)=>{let{day:n,trackId:r,cwd:o}=e.body||{};try{let s=await oA({trackId:r,cwd:o});if(!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,entry:await sE(s,{day:n})})}catch(s){let a=s?.message||String(s);t.status(/required|invalid/i.test(a)?400:500).json({error:a})}});var iU=120,Jh=400,Iu=null;S.post("/api/notify",async(e,t)=>{let{title:n,body:r,urgency:o,cwd:s,trackId:a}=e.body||{};try{let i=typeof r=="string"?r.trim():"";if(!i)return t.status(400).json({error:"body (the message) required"});if(i.length>Jh)return t.status(400).json({error:`message is ${i.length} chars \u2014 over the ${Jh} cap; a notification is a nudge, put the detail in chat`});let c=za(`${n||""}
597
- ${i}`);if(c.length)return t.status(400).json({error:`notification appears to contain a secret VALUE (${c.join(", ")}) \u2014 notifications ship off-box; never put a credential in one`});let l=a?await ne(a):null;if(!l&&s&&(l=(await ae()).find(m=>m.cwd&&(s===m.cwd||s.startsWith(m.cwd+ge.sep)))||null),!l)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let u=(l.boxes||[]).find(p=>p.name===l.leadBox),f=(p,m)=>String(p).replace(/\s+/g," ").trim().slice(0,m),d={title:n?f(n,iU):l.name,body:f(i,Jh),urgency:o==="high"?"high":"normal",trackName:l.name,ts:Date.now()};await _(l,{type:"notify.raised",actor:"agent",boxId:l.leadBox??null,provider:u?.agent||null,payload:d}),t.json({ok:!0,notification:d,delivered:Iu?Iu.status().connected:null})}catch(i){t.status(500).json({error:i?.message||String(i)})}});S.post("/api/dictation",async(e,t)=>{if(!Buffer.isBuffer(e.body)||e.body.length===0)return t.status(400).json({error:"expected a raw audio body"});try{t.json(await HE(e.body,e.headers["content-type"]))}catch(n){t.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});S.get("/api/dictation/glossary",async(e,t)=>{t.json({configured:!!await yi(),terms:await Gh(),problem:await UE()})});S.post("/api/dictation/learn",async(e,t)=>{let{transcript:n,finalText:r}=e.body||{};if(typeof n!="string"||typeof r!="string")return t.status(400).json({error:"transcript and finalText are required"});t.json({learned:await FE(n,r)})});S.get("/api/tracks/:id/voice-chat",async(e,t)=>{if(!await ne(e.params.id))return t.status(404).json({error:"track not found"});t.json(await WE())});S.post("/api/tracks/:id/voice-chat/session",async(e,t)=>{try{let n=await ne(e.params.id);if(!n)return t.status(404).json({error:"track not found"});if(n.archivedAt)return t.status(409).json({error:"track is archived"});t.json(await qE())}catch(n){t.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});S.post("/api/tracks/:id/voice-chat/usage",async(e,t)=>{try{let n=await ne(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let{model:r,usage:o,seconds:s}=e.body||{};t.json({ok:!0,...await KE(n,{model:r,usage:o,seconds:s})})}catch(n){t.status(n?.status||500).json({error:n?.message||String(n)})}});S.post("/api/tracks",async(e,t)=>{let{name:n,cwd:r,repo:o,repos:s,agent:a,skipPermissions:i,ticket:c,circuit:l}=e.body||{};try{let u=await Dl({name:n,cwd:r,repo:o,repos:s,agent:a,skipPermissions:i!==!1}),f=null;if(c)try{await As(u,c,{source:"create"})}catch(p){f=p?.message||String(p)}let d=null;if(l)try{await Yl(u,await vs(l),{source:"picker"})}catch(p){d=p?.message||String(p)}t.json({ok:!0,track:u,...f?{ticketWarning:f}:{},...d?{circuitWarning:d}:{}})}catch(u){let f=u?.message||String(u);t.status(/required|unknown agent|invalid|must be/i.test(f)?400:500).json({error:f})}});S.get("/api/tracks/:id",async(e,t)=>{let n=await ne(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({track:n,handoff:sA(xs(e.params.id)),subtasks:co(e.params.id).map(ji),pendingOffers:await fm(n)})});S.delete("/api/tracks/:id",async(e,t)=>{try{let n=await _m(e.params.id,{cascadeMocks:e.query.mocks!=="0",cascadeRunbooks:e.query.runbooks==="1"});await hh(e.params.id).catch(()=>{}),t.json(n)}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});S.post("/api/tracks/:id/archive",async(e,t)=>{try{t.json({ok:!0,track:await io(e.params.id)})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/already archived/i.test(r)?409:500).json({error:r})}});S.post("/api/tracks/:id/rename",async(e,t)=>{try{t.json({ok:!0,track:await $m(e.params.id,e.body?.name)})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/loop run Tracks/i.test(r)?409:/required|too long/i.test(r)?400:500;t.status(o).json({error:r})}});S.post("/api/tracks/:id/unarchive",async(e,t)=>{try{t.json({ok:!0,track:await Rm(e.params.id)})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/not archived/i.test(r)?409:500).json({error:r})}});S.get("/api/tracks/:id/messages",async(e,t)=>{let n=await Cl(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json(n)});S.get("/api/tracks/:id/events",async(e,t)=>{let n=await ne(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.set({"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive","x-accel-buffering":"no"}),t.flushHeaders();let r=i=>t.write(`id: ${i.seq}
602
+ `));let p=l.map(x=>x.name).join(", "),m=c&&i?` in the ${i.name}/ checkout`:"",h=await It(a.id,`CI is red on PR #${o.number} "${o.title}" (${o.url}) \u2014 branch ${o.headRefName}${m}. Failing check${l.length===1?"":"s"}: ${p}. The failure log is at ${d} in this ${c?"workspace":"worktree"} \u2014 read it, fix the root cause${c&&i?` in ${i.name}/`:""}, run the relevant tests locally, then commit and push to update the PR.`,{kind:"ci-fix"}),g=s;g&&(await mt({repo:g,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await Vk(g,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await Ut("fix-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{checks:l.map(x=>x.name)}}),t.json({ok:!0,leadBox:h.leadBox,queued:!!h.queued,checks:l.map(x=>x.name),log:d})}catch(o){let s=o?.message||String(o),a=/unknown repo|invalid|required/i.test(s)?400:/not found|no active Track/i.test(s)?404:502;t.status(a).json({error:s})}});S.post("/api/git/prs/reconcile",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await rs(n,r);if(o.mergeable!=="CONFLICTING")return t.status(409).json({error:"this PR does not conflict with its base branch"});let s=await me(n).catch(()=>null),a=await uA({repo:n,number:r,branch:o.headRefName});if(!a)return t.status(404).json({error:`no active Track owns PR #${o.number} (branch "${o.headRefName}")`});let i=gt(a.workspace).find(f=>f.base===n||s&&f.repo===s)??null,c=a.workspace?.kind==="multi"&&i?` In the ${i.name}/ checkout:`:"",l=await It(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 mt({repo:u,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await zk(u,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await Ut("reconcile-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{base:o.baseRefName}}),t.json({ok:!0,leadBox:l.leadBox,queued:!!l.queued,base:o.baseRefName})}catch(o){let s=o?.message||String(o),a=/unknown repo|invalid|required/i.test(s)?400:/not found|no active Track/i.test(s)?404:502;t.status(a).json({error:s})}});S.post("/api/tracks/:id/pr-offer",async(e,t)=>{let{offerId:n,action:r}=e.body||{};try{let o=null;if(Array.isArray(e.body?.actions)){if(o=Yo.filter(f=>e.body.actions.includes(f)),!o.length)return t.status(400).json({error:"actions must include commit, rebase, push and/or pr"})}else if(r==="pr")o=["commit","push","pr"];else if(r==="push")o=["commit","push"];else if(r!=="dismiss")return t.status(400).json({error:'offerId and actions ["commit"|"rebase"|"push"|"pr"] (or action "dismiss") required'});if(!n)return t.status(400).json({error:"offerId required"});let s=o!=null&&e.body?.notify===!0,a=await ne(e.params.id);if(!a)return t.status(404).json({error:"track not found"});let i=await L(a),c=i.find(f=>f.type==="pr.offered"&&f.payload?.offerId===n);if(!c)return t.status(404).json({error:"unknown offer"});if(i.some(f=>f.type==="pr.offer.answered"&&f.payload?.offerId===n))return t.status(409).json({error:"offer already answered"});if(o?.includes("pr")){let f=await Kh(a,c,{actions:o,notify:s});if(f)return t.json({ok:!0,offerId:n,action:"pr-exists",actions:o,notify:s,existingPr:f.pr})}let l=null;o&&(l=await It(a.id,Zo(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 _({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&&Sm(a.id,{actions:o}),t.json({ok:!0,offerId:n,action:u,actions:o,notify:s,queued:!!l?.queued})}catch(o){let s=o?.message||String(o),a=/required|invalid/i.test(s)?400:/not found|not running|archived/i.test(s)?409:502;t.status(a).json({error:s})}});S.post("/api/tracks/:id/pr-exists",async(e,t)=>{let{offerId:n,choice:r}=e.body||{};try{let o=await ne(e.params.id);if(!o)return t.status(404).json({error:"track not found"});let{say:s}=await Gh(o,{offerId:n,choice:r});t.json({ok:!0,offerId:n,choice:r,queued:!!s?.queued})}catch(o){let s=o?.message||String(o),a=/required|invalid/i.test(s)?400:/unknown offer/i.test(s)?404:/already answered|not found|not running|archived/i.test(s)?409:502;t.status(a).json({error:s})}});var Fi=e=>t=>({...t,url:ZT(t,e.headers)});S.get("/api/views",async(e,t)=>{try{let n=await Sl({trackId:e.query.track||void 0});t.json({views:n.map(Fi(e)),maxLive:mr})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/views/:id",async(e,t)=>{let n=await x0(e.params.id);if(!n)return t.status(404).json({error:"view not found"});t.json({view:Fi(e)(n),session:us(n.slug)})});S.post("/api/views",async(e,t)=>{let{trackId:n,name:r,cmd:o,cwd:s,port:a}=e.body||{};try{let i=n?await ne(n):null;if(!i&&s&&(i=(await ae()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+ge.sep)))||null),!i)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let c=await Rp({trackId:i.id,name:r,cmd:o,cwd:i.cwd,serveCwd:s,port:a,box:i.leadBox,branch:i.workspace?.branch??null});t.json({ok:!0,view:Fi(e)(c)})}catch(i){let c=i?.message||String(i),l=i?.status??(/cap reached/i.test(c)?409:/required|invalid|already owned|no free/i.test(c)?400:500);t.status(l).json({error:c})}});S.post("/api/views/:id/stop",async(e,t)=>{try{t.json({ok:!0,view:Fi(e)(await S0(e.params.id))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});S.post("/api/views/:id/restart",async(e,t)=>{try{t.json({ok:!0,view:Fi(e)(await v0(e.params.id))})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/cap reached|no known command/i.test(r)?409:500;t.status(o).json({error:r})}});S.delete("/api/views/:id",async(e,t)=>{try{t.json(await T0(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});var xU=[["linear",uo,lh],["jira",ou,ih]],ew=new Map;S.get("/api/integrations/ticketing",async(e,t)=>{try{let n=await ah(),r={};for(let[o,s,a]of xU){let i=await s();if(!i){ew.delete(o),r[o]={configured:!1};continue}let c=ew.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},ew.set(o,c)}r[o]={...c.body,flow:n},o==="jira"&&i.tokenExpiresAt&&(r[o].tokenExpiresAt=i.tokenExpiresAt)}t.json(r)}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/tickets/flow",async(e,t)=>{try{t.json({flow:await ah()})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.post("/api/tickets/flow",async(e,t)=>{let{trackId:n,cwd:r,set:o,actor:s}=e.body||{};try{let a=await Pv(o),i=n?await ne(n):null;!i&&r&&(i=(await ae()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+ge.sep)))||null),i&&await _({id:i.id,cwd:i.cwd},{type:"ticket.flow.changed",actor:s==="user"?"user":"agent",source:"orchestrator",payload:{ts:Date.now(),set:{...o},flow:a}}).catch(()=>{}),t.json({ok:!0,flow:a})}catch(a){let i=a?.message||String(a);t.status(/unknown|nothing to set/i.test(i)?400:500).json({error:i})}});var wo=async(e,t)=>{let n=e?await ne(e):null;return!n&&t&&(n=(await ae()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+ge.sep)))||null),n};S.get("/api/circuits",async(e,t)=>{try{t.json({circuits:await th()})}catch(n){t.status(502).json({error:n?.message||String(n)})}});S.post("/api/circuits/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=await wo(n,r);if(!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});if(!o)return t.status(400).json({error:"ref (circuit name or id) required"});let a=await _s(o);await eu(s,a,{source:"chat"}),t.json({ok:!0,trackId:s.id,circuit:a})}catch(s){let a=s?.message||String(s);t.status(/required|no circuit|names \d|no plane/i.test(a)?400:502).json({error:a})}});S.post("/api/circuits/unlink",async(e,t)=>{let{trackId:n,cwd:r}=e.body||{};try{let o=await wo(n,r);if(!o)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});await eu(o,null,{source:"chat"}),t.json({ok:!0,trackId:o.id})}catch(o){t.status(502).json({error:o?.message||String(o)})}});var dA=async(e,t,n)=>{if(e)return{ref:e,track:await wo(t,n)};let r=await wo(t,n),o=r?await rh(r.id):null;if(!o)throw new Error(r?"this Track isn't in a circuit \u2014 pass --circuit <name-or-id> (or link one first: bostrat-circuit link \u2026)":"run from inside a Track workspace, or pass --circuit <name-or-id>");return{ref:o,track:r}};S.post("/api/blueprints/publish",async(e,t)=>{let{trackId:n,cwd:r,circuit:o,newCircuit:s,name:a,markdown:i}=e.body||{};try{if(!i||!String(i).trim())return t.status(400).json({error:"markdown required"});let{ref:c}=s?{ref:null}:await dA(o,n,r),l=await _v({circuitRef:c,newCircuitName:s,name:a,markdown:i});t.json({ok:!0,...l})}catch(c){let l=c?.message||String(c);t.status(/required|no circuit|names \d|no plane|isn't in a circuit|run from inside/i.test(l)?400:502).json({error:l})}});S.get("/api/blueprints/show",async(e,t)=>{try{let{ref:n}=await dA(e.query.circuit,e.query.track,e.query.cwd);t.json(await nh(n))}catch(n){let r=n?.message||String(n);t.status(/no blueprint|no circuit|isn't in a circuit|run from inside|names \d/i.test(r)?404:502).json({error:r})}});S.post("/api/decisions/record",async(e,t)=>{let{trackId:n,cwd:r,title:o,context:s,decision:a,summary:i,alternatives:c,supersedesId:l}=e.body||{};try{let u=await wo(n,r);if(!u)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let f=await $v(u,{title:o,context:s,decision:a,summary:i,alternatives:c,supersedesId:l});t.json({ok:!0,trackId:u.id,...f})}catch(u){let f=u?.message||String(u);t.status(/required/i.test(f)?400:502).json({error:f})}});S.get("/api/decisions",async(e,t)=>{try{let n=await wo(e.query.track,e.query.cwd);if(!n)return t.status(400).json({error:"run from inside a Track workspace"});t.json(await Ov(n.id))}catch(n){let r=n?.message||String(n);t.status(/no plane|required|run from inside/i.test(r)?400:502).json({error:r})}});S.post("/api/blueprints/tag",async(e,t)=>{let{trackId:n,cwd:r,itemIds:o}=e.body||{};try{let s=Array.isArray(o)?o.map(String):[];if(!s.length)return t.status(400).json({error:"itemIds required (BP-\u2026 ids)"});let a=await wo(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=await rh(a.id);if(!i)return t.status(400).json({error:"this Track isn't in a circuit \u2014 link one first (bostrat-circuit link \u2026)"});let c=await Iv(a,i,s);t.json({ok:!0,trackId:a.id,...c})}catch(s){let a=s?.message||String(s);t.status(/unknown\/unbindable|required|no blueprint|isn't in a circuit/i.test(a)?400:502).json({error:a})}});S.post("/api/tickets/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=n?await ne(n):null;if(!s&&r&&(s=(await ae()).find(c=>c.cwd&&(r===c.cwd||r.startsWith(c.cwd+ge.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});if(!o)return t.status(400).json({error:"ref (issue URL or key) required"});let a=await $s(s,o,{source:n?"api":"cli"});t.json({ok:!0,trackId:s.id,ticket:a})}catch(s){let a=s?.message||String(s);t.status(/not a Linear|not found|no ticketing|required/i.test(a)?400:502).json({error:a})}});S.get("/api/tickets/status",async(e,t)=>{let{cwd:n,track:r}=e.query;try{let o=r?await ne(r):null;if(!o&&n&&(o=(await ae()).find(a=>a.cwd&&(n===a.cwd||String(n).startsWith(a.cwd+ge.sep)))||null),!o)return t.status(400).json({error:"track (or a cwd inside a Track workspace) required"});t.json({trackId:o.id,configured:await Yv(),ticket:await ln(o.id)})}catch(o){t.status(500).json({error:o?.message||String(o)})}});S.get("/api/tracks/:id/ticket",async(e,t)=>{t.json({ticket:await ln(e.params.id)})});S.post("/api/tracks/:id/ticket",async(e,t)=>{try{let n=await ne(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await $s(n,(e.body||{}).ref,{source:"api"});t.json({ok:!0,ticket:r})}catch(n){let r=n?.message||String(n);t.status(/not a Linear|not found|no ticketing|required/i.test(r)?400:502).json({error:r})}});S.delete("/api/tracks/:id/ticket",async(e,t)=>{t.json({ok:!0,removed:await xh(e.params.id)})});var Mu=e=>/no ticket linked|unknown offer|unknown state/i.test(e)?404:/already answered/i.test(e)?409:/required|no ticketing/i.test(e)?400:502;S.get("/api/tracks/:id/ticket/states",async(e,t)=>{try{t.json(await tT(e.params.id))}catch(n){let r=n?.message||String(n);t.status(Mu(r)).json({error:r})}});S.post("/api/tracks/:id/ticket/state",async(e,t)=>{try{t.json({ok:!0,...await Sh(e.params.id,(e.body||{}).stateId)})}catch(n){let r=n?.message||String(n);t.status(Mu(r)).json({error:r})}});S.post("/api/tracks/:id/ticket/comment",async(e,t)=>{try{t.json({ok:!0,...await nT(e.params.id,(e.body||{}).body)})}catch(n){let r=n?.message||String(n);t.status(Mu(r)).json({error:r})}});S.post("/api/tracks/:id/ticket-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{let o=await ne(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await rT(o,n,r===!0)})}catch(o){let s=o?.message||String(o);t.status(Mu(s)).json({error:s})}});S.post("/api/tracks/:id/fullscreen-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{t.json(await Bm(e.params.id,n,r===!0))}catch(o){let s=o?.message||String(o),a=/not found|unknown offer/.test(s)?404:/already answered/.test(s)||/mid-turn/.test(s)?409:500;t.status(a).json({error:s})}});S.post("/api/tickets/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await ne(n):null;if(!s&&r&&(s=(await ae()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+ge.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,proposal:await sT(s,o)})}catch(s){let a=s?.message||String(s);t.status(/no ticketing|are off|needs an epic|too many|required/i.test(a)?400:502).json({error:a})}});S.get("/api/tickets/teams",async(e,t)=>{try{t.json({teams:await oT()})}catch(n){let r=n?.message||String(n);t.status(/no ticketing/i.test(r)?400:502).json({error:r})}});S.post("/api/tracks/:id/ticket-create-offer",async(e,t)=>{let{proposalId:n,accept:r,teamId:o}=e.body||{};try{let s=await ne(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await aT(s,n,r===!0,{teamId:o||null})})}catch(s){let a=s?.message||String(s);t.status(/unknown proposal|unknown team/i.test(a)?404:/already answered/i.test(a)?409:/required|no ticketing|pick one/i.test(a)?400:502).json({error:a})}});S.get("/api/mocks",async(e,t)=>{try{t.json({mocks:await Za({trackId:e.query.track||void 0,group:e.query.group||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/mocks/:id",async(e,t)=>{let n=await An(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});t.json({mock:n})});var Ui={dotfiles:"allow"};S.get("/api/mocks/:id/png",async(e,t)=>{let n=await An(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=Bt(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=Xa(n,r,"png");if(!o)return t.status(404).json({error:"no image for this version (poster extraction failed)"});t.set("cache-control","private, max-age=31536000, immutable"),t.sendFile(o,Ui,s=>{s&&!t.headersSent&&t.status(404).json({error:"rendered artifact missing"})})});S.get("/api/mocks/:id/media",async(e,t)=>{let n=await An(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=Bt(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=Xa(n,r,"video");if(!o)return t.status(404).json({error:"this version has no video (image or html sourced)"});t.set("cache-control","private, max-age=31536000, immutable"),t.sendFile(o,Ui,s=>{s&&!t.headersSent&&t.status(404).json({error:"video artifact missing"})})});S.get("/api/mocks/:id/html",async(e,t)=>{let n=await An(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=Bt(n,e.query.v??null);if(!r?.htmlRel)return t.status(404).json({error:"this version has no HTML source (image-sourced)"});t.set("content-security-policy","sandbox"),t.sendFile(Et(n,r.v).html,Ui,o=>{o&&!t.headersSent&&t.status(404).json({error:"source artifact missing"})})});S.post("/api/mocks",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&Al(n)?n:null,o=n&&!r?n:null,s=n?e.query:e.body||{},{trackId:a,name:i,cwd:c,width:l,group:u}=s;try{let f=a?await ne(a):null;if(!f&&c&&(f=(await ae()).find(h=>h.cwd&&(c===h.cwd||c.startsWith(h.cwd+ge.sep)))||null),!f)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let d=(f.boxes||[]).find(m=>m.name===f.leadBox),p=await U0({trackId:f.id,name:i,html:n?null:s.html,image:r,video:o,cwd:f.cwd,width:l,group:u,box:f.leadBox,agent:d?.agent||null});t.json({ok:!0,mock:p})}catch(f){let d=f?.message||String(f);t.status(/required|invalid|must be/i.test(d)?400:500).json({error:d})}});S.post("/api/mocks/:id/update",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&Al(n)?n:null;try{let o=await H0(e.params.id,{html:n?null:(e.body||{}).html,image:r,video:n&&!r?n:null,width:n?e.query.width:(e.body||{}).width});t.json({ok:!0,mock:o})}catch(o){let s=o?.message||String(o),a=/not found/i.test(s)?404:/required|invalid|must be/i.test(s)?400:500;t.status(a).json({error:s})}});S.post("/api/mocks/:id/pick",async(e,t)=>{try{let{mock:n,siblings:r}=await K0(e.params.id),o=r.length?` over ${r.map(s=>`"${s.name}"`).join(", ")}`:"";await It(n.trackId,`Design decision: go with "${n.name}" (mock:${n.id})${o} \u2014 proceed with this design.`,{kind:"mock-picked"}).catch(()=>{}),t.json({ok:!0,mock:n,siblings:r})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/nothing to pick/i.test(r)?409:500;t.status(o).json({error:r})}});S.delete("/api/mocks/:id",async(e,t)=>{try{let n=(await lS(e.params.id)).map(r=>({id:r.id,name:r.name}));t.json({...await G0(e.params.id),...n.length?{danglingFlows:n}:{}})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});S.get("/api/flows",async(e,t)=>{try{t.json({flows:await oS({trackId:e.query.track||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/flows/:id",async(e,t)=>{let n=await sS(e.params.id);if(!n)return t.status(404).json({error:"flow not found"});t.json({flow:n})});S.post("/api/flows",async(e,t)=>{let{trackId:n,name:r,steps:o,cwd:s}=e.body||{};try{let a=n?await ne(n):null;if(!a&&s&&(a=(await ae()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+ge.sep)))||null),!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=(a.boxes||[]).find(l=>l.name===a.leadBox),c=await aS({trackId:a.id,name:r,steps:o,cwd:a.cwd,box:a.leadBox,agent:i?.agent||null});t.json({ok:!0,flow:c})}catch(a){let i=a?.message||String(a),c=/already exists/i.test(i)?409:/required|invalid|no mock|ambiguous|over \d+ chars|must be|no captured/i.test(i)?400:500;t.status(c).json({error:i})}});S.post("/api/flows/:id/update",async(e,t)=>{try{let{steps:n,note:r}=e.body||{};t.json({ok:!0,flow:await iS(e.params.id,{steps:n,note:r})})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/required|invalid|no mock|ambiguous|over \d+ chars|must be|no captured/i.test(r)?400:500;t.status(o).json({error:r})}});S.delete("/api/flows/:id",async(e,t)=>{try{t.json(await cS(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});S.get("/api/runbooks",async(e,t)=>{try{let n=e.query.track||void 0;if(!n&&e.query.cwd){let s=await ae(),a=String(e.query.cwd);if(n=s.find(i=>i.cwd&&(a===i.cwd||a.startsWith(i.cwd+ge.sep)))?.id,!n)return t.json({runbooks:[]})}let{runbooks:r,fleetDegraded:o}=await gS({trackId:n,status:e.query.status||void 0});t.json({runbooks:r,...o?{fleetDegraded:!0}:{}})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/runbooks/:id",async(e,t)=>{let n=await Wp(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});t.json({runbook:n})});S.get("/api/runbooks/:id/md",async(e,t)=>{let n=await Wp(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});let r=hS(n,e.query.v??null);if(!r)return t.status(404).json({error:"no such version"});if(t.set("content-security-policy","sandbox"),t.set("cache-control","private, max-age=31536000, immutable"),t.type("text/markdown; charset=utf-8"),n.remote){let o=await yS(n,r.v);return typeof o!="string"?t.status(404).json({error:"runbook artifact missing"}):t.send(o)}t.sendFile($n(n,r.v),Ui,o=>{o&&!t.headersSent&&t.status(404).json({error:"runbook artifact missing"})})});S.get("/api/loops",async(e,t)=>{t.json(await hl())});S.post("/api/loops/report",async(e,t)=>{let{outcome:n,note:r,cwd:o}=e.body||{};if(!["ok","acted","attention"].includes(n))return t.status(400).json({error:"outcome must be one of ok | acted | attention"});if(!o)return t.status(400).json({error:"cwd required"});let a=(await ae()).find(u=>u.cwd&&(o===u.cwd||o.startsWith(u.cwd+ge.sep)))||null;if(!a)return t.status(400).json({error:"cwd is not inside a Track workspace"});let i=await hl();if(i.source!=="plane")return t.status(503).json({error:i.source==="unconfigured"?"this node isn't linked to a plane \u2014 loops live in the plane":`plane unreachable (${i.error||"no detail"})`});let c=i.loops.find(u=>u.trackId===a.id);if(!c)return t.status(404).json({error:`Track "${a.name}" is not a loop's run Track \u2014 nothing to report on`});let l=await cp({loopId:c.id,outcome:n,note:r});if(!l.ok)return t.status(l.status||503).json({error:l.error||"report failed"});t.json({ok:!0,loop:{id:c.id,name:c.name},run:l.run})});S.post("/api/loops/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await ne(n):null;if(!s&&r&&(s=(await ae()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+ge.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,proposal:await oE(s,o)})}catch(s){t.status(400).json({error:s?.message||String(s)})}});S.post("/api/tracks/:id/loop-create-offer",async(e,t)=>{let{proposalId:n,accept:r,loopId:o,nextFireAt:s}=e.body||{};try{let a=await ne(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await sE(a,n,r===!0,{loopId:o||null,nextFireAt:s??null})})}catch(a){let i=a?.message||String(a);t.status(/unknown proposal/i.test(i)?404:/already answered/i.test(i)?409:400).json({error:i})}});S.post("/api/runbooks",async(e,t)=>{let{trackId:n,name:r,md:o,cwd:s}=e.body||{};try{let a=n?await ne(n):null;if(!a&&s&&(a=(await ae()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+ge.sep)))||null),!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=(a.boxes||[]).find(l=>l.name===a.leadBox),c=await bS({trackId:a.id,trackName:a.name,name:r,md:o,cwd:a.cwd,box:a.leadBox,agent:i?.agent||null});t.json({ok:!0,runbook:c})}catch(a){let i=a?.message||String(a);t.status(/required|invalid|over the|secret VALUE/i.test(i)?400:500).json({error:i})}});S.post("/api/runbooks/:id/update",async(e,t)=>{try{let{md:n,note:r}=e.body||{};t.json({ok:!0,runbook:await kS(e.params.id,{md:n,note:r})})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/orphaned/i.test(r)?410:/required|invalid|over the|secret VALUE/i.test(r)?400:500;t.status(o).json({error:r})}});S.post("/api/runbooks/:id/status",async(e,t)=>{try{t.json({ok:!0,runbook:await xS(e.params.id,(e.body||{}).status)})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/orphaned/i.test(r)?410:/must be/i.test(r)?400:500;t.status(o).json({error:r})}});S.delete("/api/runbooks/:id",async(e,t)=>{try{t.json(await SS(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});S.get("/api/changelog/draft",async(e,t)=>{try{let n=uE(e.query.since||null);t.json({since:n,repos:Lh(),...await dE(n)})}catch(n){let r=n?.message||String(n);t.status(/unparseable/i.test(r)?400:500).json({error:r})}});var fA=async({trackId:e,cwd:t})=>{let n=e?await ne(e):null;return!n&&t&&(n=(await ae()).find(o=>o.cwd&&(t===o.cwd||String(t).startsWith(o.cwd+ge.sep)))||null),n};S.post("/api/changelog/publish",async(e,t)=>{let{md:n,day:r,trackId:o,cwd:s}=e.body||{};try{let a=await fA({trackId:o,cwd:s});if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,entry:await fE(a,{md:n,day:r})})}catch(a){let i=a?.message||String(a);t.status(/required|invalid|no `- `|over the|secret VALUE|mentions "/i.test(i)?400:500).json({error:i})}});S.post("/api/changelog/retract",async(e,t)=>{let{day:n,trackId:r,cwd:o}=e.body||{};try{let s=await fA({trackId:r,cwd:o});if(!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,entry:await pE(s,{day:n})})}catch(s){let a=s?.message||String(s);t.status(/required|invalid/i.test(a)?400:500).json({error:a})}});var SU=120,tw=400,Cu=null;S.post("/api/notify",async(e,t)=>{let{title:n,body:r,urgency:o,cwd:s,trackId:a}=e.body||{};try{let i=typeof r=="string"?r.trim():"";if(!i)return t.status(400).json({error:"body (the message) required"});if(i.length>tw)return t.status(400).json({error:`message is ${i.length} chars \u2014 over the ${tw} cap; a notification is a nudge, put the detail in chat`});let c=Qa(`${n||""}
603
+ ${i}`);if(c.length)return t.status(400).json({error:`notification appears to contain a secret VALUE (${c.join(", ")}) \u2014 notifications ship off-box; never put a credential in one`});let l=a?await ne(a):null;if(!l&&s&&(l=(await ae()).find(m=>m.cwd&&(s===m.cwd||s.startsWith(m.cwd+ge.sep)))||null),!l)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let u=(l.boxes||[]).find(p=>p.name===l.leadBox),f=(p,m)=>String(p).replace(/\s+/g," ").trim().slice(0,m),d={title:n?f(n,SU):l.name,body:f(i,tw),urgency:o==="high"?"high":"normal",trackName:l.name,ts:Date.now()};await _(l,{type:"notify.raised",actor:"agent",boxId:l.leadBox??null,provider:u?.agent||null,payload:d}),t.json({ok:!0,notification:d,delivered:Cu?Cu.status().connected:null})}catch(i){t.status(500).json({error:i?.message||String(i)})}});S.post("/api/dictation",async(e,t)=>{if(!Buffer.isBuffer(e.body)||e.body.length===0)return t.status(400).json({error:"expected a raw audio body"});try{t.json(await XE(e.body,e.headers["content-type"]))}catch(n){t.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});S.get("/api/dictation/glossary",async(e,t)=>{t.json({configured:!!await Si(),terms:await Zh(),problem:await JE()})});S.post("/api/dictation/learn",async(e,t)=>{let{transcript:n,finalText:r}=e.body||{};if(typeof n!="string"||typeof r!="string")return t.status(400).json({error:"transcript and finalText are required"});t.json({learned:await zE(n,r)})});S.get("/api/tracks/:id/voice-chat",async(e,t)=>{if(!await ne(e.params.id))return t.status(404).json({error:"track not found"});t.json(await YE())});S.post("/api/tracks/:id/voice-chat/session",async(e,t)=>{try{let n=await ne(e.params.id);if(!n)return t.status(404).json({error:"track not found"});if(n.archivedAt)return t.status(409).json({error:"track is archived"});t.json(await ZE())}catch(n){t.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});S.post("/api/tracks/:id/voice-chat/usage",async(e,t)=>{try{let n=await ne(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let{model:r,usage:o,seconds:s}=e.body||{};t.json({ok:!0,...await QE(n,{model:r,usage:o,seconds:s})})}catch(n){t.status(n?.status||500).json({error:n?.message||String(n)})}});S.post("/api/tracks",async(e,t)=>{let{name:n,cwd:r,repo:o,repos:s,agent:a,skipPermissions:i,ticket:c,circuit:l}=e.body||{};try{let u=await Fl({name:n,cwd:r,repo:o,repos:s,agent:a,skipPermissions:i!==!1}),f=null;if(c)try{await $s(u,c,{source:"create"})}catch(p){f=p?.message||String(p)}let d=null;if(l)try{await eu(u,await _s(l),{source:"picker"})}catch(p){d=p?.message||String(p)}t.json({ok:!0,track:u,...f?{ticketWarning:f}:{},...d?{circuitWarning:d}:{}})}catch(u){let f=u?.message||String(u);t.status(/required|unknown agent|invalid|must be/i.test(f)?400:500).json({error:f})}});S.get("/api/tracks/:id",async(e,t)=>{let n=await ne(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({track:n,handoff:pA(Es(e.params.id)),subtasks:co(e.params.id).map(Hi),pendingOffers:await gm(n)})});S.delete("/api/tracks/:id",async(e,t)=>{try{let n=await Cm(e.params.id,{cascadeMocks:e.query.mocks!=="0",cascadeRunbooks:e.query.runbooks==="1"});await xh(e.params.id).catch(()=>{}),t.json(n)}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});S.post("/api/tracks/:id/archive",async(e,t)=>{try{t.json({ok:!0,track:await io(e.params.id)})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/already archived/i.test(r)?409:500).json({error:r})}});S.post("/api/tracks/:id/rename",async(e,t)=>{try{t.json({ok:!0,track:await Pm(e.params.id,e.body?.name)})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/loop run Tracks/i.test(r)?409:/required|too long/i.test(r)?400:500;t.status(o).json({error:r})}});S.post("/api/tracks/:id/unarchive",async(e,t)=>{try{t.json({ok:!0,track:await Nm(e.params.id)})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/not archived/i.test(r)?409:500).json({error:r})}});S.get("/api/tracks/:id/messages",async(e,t)=>{let n=await Dl(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json(n)});S.get("/api/tracks/:id/events",async(e,t)=>{let n=await ne(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.set({"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive","x-accel-buffering":"no"}),t.flushHeaders();let r=i=>t.write(`id: ${i.seq}
598
604
  data: ${JSON.stringify(i)}
599
605
 
600
- `),o=Number(e.query.since??e.headers["last-event-id"])||0;for(let i of await L(n))i.seq>o&&r(i);let s=kw(n.id,r),a=setInterval(()=>t.write(`: hb
606
+ `),o=Number(e.query.since??e.headers["last-event-id"])||0;for(let i of await L(n))i.seq>o&&r(i);let s=Aw(n.id,r),a=setInterval(()=>t.write(`: hb
601
607
 
602
- `),25e3);e.on("close",()=>{clearInterval(a),s()})});S.get("/api/tracks/:id/search",async(e,t)=>{let n=await ne(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=String(e.query.q||"").trim();if(!r)return t.status(400).json({error:"q (query) is required"});let o=Math.min(Math.max(Number(e.query.k)||8,1),50),s=ga(await L(n)),a=Ec(s,r,{k:o,role:e.query.role||null,tag:e.query.tag||null});t.json({q:r,indexed:s.N,hits:a.map(i=>({score:Number(i.score.toFixed(3)),seq:i.chunk.seq,ts:i.chunk.ts,role:i.chunk.role,box:i.chunk.boxId,provider:i.chunk.provider,tags:i.chunk.tags,text:i.chunk.text}))})});S.get("/api/memory",async(e,t)=>{t.json({stores:await Bw(),harvest:Mw()})});S.delete("/api/memory/:key/:file",async(e,t)=>{let n=String(e.params.key||"");if(!/^[a-z0-9][a-z0-9._-]*$/.test(n))return t.status(400).json({error:"bad store key"});try{t.json({ok:!0,...await jw(n,String(e.params.file||""))})}catch(r){let o=r?.message||String(r);t.status(/not found/i.test(o)?404:/bad fact/i.test(o)?400:500).json({error:o})}});var cU=["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(`
603
- `);S.post("/api/tracks/:id/memory/consolidate",async(e,t)=>{try{t.json({ok:!0,...await It(e.params.id,cU)})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/archived/i.test(r)?409:/not running/i.test(r)?400:500).json({error:r})}});S.post("/api/tracks/:id/lead/restart",async(e,t)=>{try{t.json({ok:!0,track:await jl(e.params.id)})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:n?.transferredTo||/mid-turn|terminal|archived/i.test(r)?409:500;t.status(o).json({error:r,...n?.transferredTo?{transferredTo:n.transferredTo}:{}})}});S.post("/api/tracks/:id/say",async(e,t)=>{let{text:n,attachments:r}=e.body||{};try{t.json(await It(e.params.id,n,{attachments:r}))}catch(o){let s=o?.message||String(o);if(o?.usageCap)return t.status(429).json({error:"usage_cap",message:s,cap:o.usageCap});if(o?.transferredTo)return t.status(409).json({error:s,transferredTo:o.transferredTo});t.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(e,t)=>{try{let n=await ne(e.params.id);if(!n)return t.status(404).json({error:`track "${e.params.id}" not found`});if(n.archivedAt)return t.status(409).json({error:"track is archived"});if(!n.cwd)return t.status(409).json({error:"track has no workspace yet"});let r=Buffer.isBuffer(e.body)?e.body:null,o=await xS(n.cwd,{filename:e.query.filename,buffer:r});t.json({ok:!0,attachment:o})}catch(n){let r=n?.message||String(n);t.status(/too large|unsupported|empty|required/i.test(r)?400:500).json({error:r})}});S.get("/api/tracks/:id/uploads/:file",async(e,t)=>{try{let n=await ne(e.params.id);if(!n)return t.status(404).json({error:`track "${e.params.id}" not found`});if(!n.cwd)return t.status(404).json({error:"track has no workspace"});let r=ge.basename(String(e.params.file||""));if(!r||!Fp(ge.extname(r).slice(1)))return t.status(400).json({error:"not an upload path"});t.set("cache-control","private, max-age=31536000, immutable"),t.set("content-security-policy","sandbox");let o=Lp(n.cwd),s,a;try{s=await Ye.promises.realpath(o),a=await Ye.promises.realpath(ge.join(o,r))}catch{return t.status(404).json({error:"upload not found"})}if(!a.startsWith(s+ge.sep))return t.status(404).json({error:"upload not found"});t.sendFile(r,{root:o},i=>{i&&!t.headersSent&&t.status(404).json({error:"upload not found"})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});var lU=/^[0-9a-fA-F-]{8,64}$/;S.get("/api/tracks/:id/chat-images/:box/:uuid/:idx",async(e,t)=>{try{let n=await ne(e.params.id);if(!n)return t.status(404).json({error:`track "${e.params.id}" not found`});let{box:r,uuid:o}=e.params,s=Number(e.params.idx);if(!lU.test(o)||!Number.isInteger(s)||s<0)return t.status(400).json({error:"bad image ref"});let a=(n.boxes||[]).find(d=>d.name===r);if(!a||a.agent!=="claude"||!a.cwd||!a.sessionId)return t.status(404).json({error:"image source not available"});let i=Mt(a.cwd,a.sessionId);if(!i)return t.status(404).json({error:"transcript not found"});let c=`"${o}"`,l=null,u=YF.createInterface({input:Ye.createReadStream(i,{encoding:"utf8"}),crlfDelay:1/0});for await(let d of u){if(!d.includes(c))continue;let p;try{p=JSON.parse(d)}catch{continue}if(p.uuid===o){l=p,u.close();break}}let f=l?yd(l)[s]:null;if(!f||!/^image\//.test(f.mediaType))return t.status(404).json({error:"image not found"});t.set("content-type",f.mediaType),t.set("cache-control","private, max-age=31536000, immutable"),t.set("content-security-policy","sandbox"),t.send(Buffer.from(f.data,"base64"))}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.post("/api/tracks/:id/interrupt",async(e,t)=>{try{t.json(await Pl(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/archived/i.test(r)?409:500).json({error:r})}});S.delete("/api/tracks/:id/queue",async(e,t)=>{try{let{removed:n,restored:r,draftRev:o}=await hm(e.params.id);t.json({ok:!0,removed:n.filter(s=>s.kind!=="ship-notify"),restored:r,draftRev:o})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.post("/api/tracks/:id/answer-prompt",async(e,t)=>{let{promptId:n,answers:r,text:o}=e.body||{};try{t.json(await Ml(e.params.id,{promptId:n,answers:r,text:o}))}catch(s){let a=s?.message||String(s),i=/not found/i.test(a)?404:/no pending prompt|changed since|not running|not supported|needs a code|look like a sign-in code|no answer selected/i.test(a)?409:500;t.status(i).json({error:a})}});S.post("/api/setup/:provider/start",async(e,t)=>{try{let n=await Em({provider:e.params.provider,fresh:e.body?.fresh===!0});t.json({ok:!0,track:n})}catch(n){let r=n?.message||String(n);t.status(/unknown setup provider|isn't available/i.test(r)?400:500).json({error:r})}});S.post("/api/tracks/:id/navigate-prompt",async(e,t)=>{let{promptId:n,questionIndex:r}=e.body||{};try{t.json(await mm(e.params.id,{promptId:n,questionIndex:r}))}catch(o){let s=o?.message||String(o),a=/not found/i.test(s)?404:/no pending prompt|changed since|not running|not supported|out of range|review screen/i.test(s)?409:500;t.status(a).json({error:s})}});S.put("/api/tracks/:id/draft",async(e,t)=>{let{text:n,rev:r}=e.body||{};try{t.json(await km(e.params.id,typeof n=="string"?n:"",{rev:typeof r=="number"?r:null}))}catch(o){let s=o?.message||String(o),a=/not found/i.test(s)?404:/required/i.test(s)?400:500;t.status(a).json({error:s})}});S.get("/api/tracks/:id/usage",async(e,t)=>{let n=await ne(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=n.boxes?.find(s=>s.name===n.leadBox)||null,o=e.query.fresh==="1"||e.query.fresh==="true";t.json(await pu(r,{fresh:o}))});S.post("/api/tracks/:id/model",async(e,t)=>{let{model:n}=e.body||{};try{t.json(await xm(e.params.id,n))}catch(r){let o=r?.message||String(r),s=/not found/i.test(o)?404:/required|unknown model|not running/i.test(o)?400:500;t.status(s).json({error:o})}});S.post("/api/tracks/:id/subtask",async(e,t)=>{let{agent:n,task:r,skipPermissions:o,reason:s}=e.body||{};try{let a=await Hm(e.params.id,{agent:n,task:r,skipPermissions:o!==!1,reason:s});t.json({ok:!0,subtask:ji(a)})}catch(a){let i=a?.message||String(a);if(a?.usageCap)return t.status(429).json({error:"usage_cap",message:i,cap:a.usageCap});let c=/not found/i.test(i)?404:/required|unknown agent|git repo|not running|can't resolve/i.test(i)?400:500;t.status(c).json({error:i})}});S.get("/api/tracks/:id/subtasks",(e,t)=>{t.json({subtasks:co(e.params.id).map(ji)})});S.get("/api/tracks/:id/subtask/:sid/messages",async(e,t)=>{let n=await pm(e.params.id,e.params.sid);if(!n)return t.status(404).json({error:"subtask not found"});t.json(n)});S.post("/api/tracks/:id/subtask/:sid/cancel",(e,t)=>{try{t.json({ok:!0,subtask:ji(Wl(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});S.post("/api/tracks/:id/subtask/:sid/merge-now",(e,t)=>{try{t.json({ok:!0,subtask:ji(Wm(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});function ji(e){return e?{id:e.id,agent:e.agent,task:e.task,skipPermissions:e.skipPermissions,step:e.step,running:!e.finishedAt,box:e.box,branch:e.branch,stat:e.stat,files:e.files||null,conflicts:e.conflicts||[],applied:e.applied,error:e.error,canceled:e.canceled,startedAt:e.startedAt,finishedAt:e.finishedAt}:null}S.post("/api/tracks/:id/handoff-lead",async(e,t)=>{let{toAgent:n,skipPermissions:r,reason:o}=e.body||{};try{let s=await Fl(e.params.id,n,r!==!1,o);t.json({ok:!0,step:s.step,toAgent:s.toAgent,fromBox:s.fromBox,skipPermissions:s.skipPermissions})}catch(s){let a=s?.message||String(s);if(s?.usageCap)return t.status(429).json({error:"usage_cap",message:a,cap:s.usageCap});t.status(/already running/i.test(a)?409:/not found/i.test(a)?404:400).json({error:a})}});S.post("/api/tracks/:id/spin-up-view",async(e,t)=>{try{t.json(await ym(e.params.id,e.body||{}))}catch(n){let r=n?.message||String(n);t.status(/already being spun up/i.test(r)?409:/not found/i.test(r)?404:400).json({error:r})}});S.get("/api/tracks/:id/handoff-lead",(e,t)=>{t.json(sA(xs(e.params.id))??{running:!1})});S.post("/api/tracks/:id/transfer-out",async(e,t)=>{try{let n=await Dm(e.params.id);t.json({ok:!0,step:n.step,startedAt:n.startedAt})}catch(n){let r=n?.message||String(n);t.status(/already running/i.test(r)?409:/not found/i.test(r)?404:400).json({error:r})}});S.get("/api/tracks/:id/transfer-out",(e,t)=>{let n=Pm(e.params.id);if(!n)return t.json({running:!1});t.json({running:!n.finishedAt,step:n.step,error:n.error,startedAt:n.startedAt,finishedAt:n.finishedAt,...n.result??{}})});S.post("/api/tracks/:id/transfer-out/commit",async(e,t)=>{try{t.json(await Ul(e.params.id,e.body||{}))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:400).json({error:r})}});S.post("/api/tracks/adopt",async(e,t)=>{let{trackId:n}=e.body||{};try{t.json(await Lm({...e.body||{},trackId:n}))}catch(r){let o=r?.message||String(r);t.status(/already running|already hosted/i.test(o)?409:/not found/i.test(o)?404:400).json({error:o})}});function sA(e){return e?{running:!e.finishedAt,step:e.step,error:e.error,fromBox:e.fromBox,toBox:e.toBox,toAgent:e.toAgent,skipPermissions:e.skipPermissions,startedAt:e.startedAt,finishedAt:e.finishedAt}:null}S.get("/api/debug/handoff",async(e,t)=>{let n=Math.min(Number(e.query.limit)||80,500);t.json({verbose:ic(),paths:Qw,trace:await Zw({limit:n})})});var Yh=ge.resolve(XE,"..","..","client","dist");Ye.existsSync(Yh)&&(S.use(Rt.static(Yh)),S.get(/^(?!\/api\/).*/,(e,t)=>t.sendFile(ge.join(Yh,"index.html"),Bi)));var aA=ZF.createServer(S),uU=new eU({noServer:!0}),iA=(e,t,n)=>{if(!(Ri(e)||Ds.allowed(Ds.clientIp(e))||Zh.allows(e))){t.write(`HTTP/1.1 403 Forbidden\r
608
+ `),25e3);e.on("close",()=>{clearInterval(a),s()})});S.get("/api/tracks/:id/search",async(e,t)=>{let n=await ne(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=String(e.query.q||"").trim();if(!r)return t.status(400).json({error:"q (query) is required"});let o=Math.min(Math.max(Number(e.query.k)||8,1),50),s=va(await L(n)),a=$c(s,r,{k:o,role:e.query.role||null,tag:e.query.tag||null});t.json({q:r,indexed:s.N,hits:a.map(i=>({score:Number(i.score.toFixed(3)),seq:i.chunk.seq,ts:i.chunk.ts,role:i.chunk.role,box:i.chunk.boxId,provider:i.chunk.provider,tags:i.chunk.tags,text:i.chunk.text}))})});S.get("/api/memory",async(e,t)=>{t.json({stores:await Ww(),harvest:Lw()})});S.delete("/api/memory/:key/:file",async(e,t)=>{let n=String(e.params.key||"");if(!/^[a-z0-9][a-z0-9._-]*$/.test(n))return t.status(400).json({error:"bad store key"});try{t.json({ok:!0,...await qw(n,String(e.params.file||""))})}catch(r){let o=r?.message||String(r);t.status(/not found/i.test(o)?404:/bad fact/i.test(o)?400:500).json({error:o})}});var vU=["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(`
609
+ `);S.post("/api/tracks/:id/memory/consolidate",async(e,t)=>{try{t.json({ok:!0,...await It(e.params.id,vU)})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/archived/i.test(r)?409:/not running/i.test(r)?400:500).json({error:r})}});S.post("/api/tracks/:id/lead/restart",async(e,t)=>{try{t.json({ok:!0,track:await Hl(e.params.id)})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:n?.transferredTo||/mid-turn|terminal|archived/i.test(r)?409:500;t.status(o).json({error:r,...n?.transferredTo?{transferredTo:n.transferredTo}:{}})}});S.post("/api/tracks/:id/say",async(e,t)=>{let{text:n,attachments:r}=e.body||{};try{t.json(await It(e.params.id,n,{attachments:r}))}catch(o){let s=o?.message||String(o);if(o?.usageCap)return t.status(429).json({error:"usage_cap",message:s,cap:o.usageCap});if(o?.transferredTo)return t.status(409).json({error:s,transferredTo:o.transferredTo});t.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(e,t)=>{try{let n=await ne(e.params.id);if(!n)return t.status(404).json({error:`track "${e.params.id}" not found`});if(n.archivedAt)return t.status(409).json({error:"track is archived"});if(!n.cwd)return t.status(409).json({error:"track has no workspace yet"});let r=Buffer.isBuffer(e.body)?e.body:null,o=await IS(n.cwd,{filename:e.query.filename,buffer:r});t.json({ok:!0,attachment:o})}catch(n){let r=n?.message||String(n);t.status(/too large|unsupported|empty|required/i.test(r)?400:500).json({error:r})}});S.get("/api/tracks/:id/uploads/:file",async(e,t)=>{try{let n=await ne(e.params.id);if(!n)return t.status(404).json({error:`track "${e.params.id}" not found`});if(!n.cwd)return t.status(404).json({error:"track has no workspace"});let r=ge.basename(String(e.params.file||""));if(!r||!Gp(ge.extname(r).slice(1)))return t.status(400).json({error:"not an upload path"});t.set("cache-control","private, max-age=31536000, immutable"),t.set("content-security-policy","sandbox");let o=Kp(n.cwd),s,a;try{s=await Ye.promises.realpath(o),a=await Ye.promises.realpath(ge.join(o,r))}catch{return t.status(404).json({error:"upload not found"})}if(!a.startsWith(s+ge.sep))return t.status(404).json({error:"upload not found"});t.sendFile(r,{root:o},i=>{i&&!t.headersSent&&t.status(404).json({error:"upload not found"})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});var TU=/^[0-9a-fA-F-]{8,64}$/;S.get("/api/tracks/:id/chat-images/:box/:uuid/:idx",async(e,t)=>{try{let n=await ne(e.params.id);if(!n)return t.status(404).json({error:`track "${e.params.id}" not found`});let{box:r,uuid:o}=e.params,s=Number(e.params.idx);if(!TU.test(o)||!Number.isInteger(s)||s<0)return t.status(400).json({error:"bad image ref"});let a=(n.boxes||[]).find(d=>d.name===r);if(!a||a.agent!=="claude"||!a.cwd||!a.sessionId)return t.status(404).json({error:"image source not available"});let i=Mt(a.cwd,a.sessionId);if(!i)return t.status(404).json({error:"transcript not found"});let c=`"${o}"`,l=null,u=dU.createInterface({input:Ye.createReadStream(i,{encoding:"utf8"}),crlfDelay:1/0});for await(let d of u){if(!d.includes(c))continue;let p;try{p=JSON.parse(d)}catch{continue}if(p.uuid===o){l=p,u.close();break}}let f=l?Sd(l)[s]:null;if(!f||!/^image\//.test(f.mediaType))return t.status(404).json({error:"image not found"});t.set("content-type",f.mediaType),t.set("cache-control","private, max-age=31536000, immutable"),t.set("content-security-policy","sandbox"),t.send(Buffer.from(f.data,"base64"))}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.post("/api/tracks/:id/interrupt",async(e,t)=>{try{t.json(await Ll(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/archived/i.test(r)?409:500).json({error:r})}});S.delete("/api/tracks/:id/queue",async(e,t)=>{try{let{removed:n,restored:r,draftRev:o}=await km(e.params.id);t.json({ok:!0,removed:n.filter(s=>s.kind!=="ship-notify"),restored:r,draftRev:o})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.post("/api/tracks/:id/answer-prompt",async(e,t)=>{let{promptId:n,answers:r,text:o}=e.body||{};try{t.json(await Bl(e.params.id,{promptId:n,answers:r,text:o}))}catch(s){let a=s?.message||String(s),i=/not found/i.test(a)?404:/no pending prompt|changed since|not running|not supported|needs a code|look like a sign-in code|no answer selected/i.test(a)?409:500;t.status(i).json({error:a})}});S.post("/api/setup/:provider/start",async(e,t)=>{try{let n=await $m({provider:e.params.provider,fresh:e.body?.fresh===!0});t.json({ok:!0,track:n})}catch(n){let r=n?.message||String(n);t.status(/unknown setup provider|isn't available/i.test(r)?400:500).json({error:r})}});S.post("/api/tracks/:id/navigate-prompt",async(e,t)=>{let{promptId:n,questionIndex:r}=e.body||{};try{t.json(await bm(e.params.id,{promptId:n,questionIndex:r}))}catch(o){let s=o?.message||String(o),a=/not found/i.test(s)?404:/no pending prompt|changed since|not running|not supported|out of range|review screen/i.test(s)?409:500;t.status(a).json({error:s})}});S.put("/api/tracks/:id/draft",async(e,t)=>{let{text:n,rev:r}=e.body||{};try{t.json(await Em(e.params.id,typeof n=="string"?n:"",{rev:typeof r=="number"?r:null}))}catch(o){let s=o?.message||String(o),a=/not found/i.test(s)?404:/required/i.test(s)?400:500;t.status(a).json({error:s})}});S.get("/api/tracks/:id/usage",async(e,t)=>{let n=await ne(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=n.boxes?.find(s=>s.name===n.leadBox)||null,o=e.query.fresh==="1"||e.query.fresh==="true";t.json(await gu(r,{fresh:o}))});S.post("/api/tracks/:id/model",async(e,t)=>{let{model:n}=e.body||{};try{t.json(await Am(e.params.id,n))}catch(r){let o=r?.message||String(r),s=/not found/i.test(o)?404:/required|unknown model|not running/i.test(o)?400:500;t.status(s).json({error:o})}});S.post("/api/tracks/:id/subtask",async(e,t)=>{let{agent:n,task:r,skipPermissions:o,reason:s}=e.body||{};try{let a=await Vm(e.params.id,{agent:n,task:r,skipPermissions:o!==!1,reason:s});t.json({ok:!0,subtask:Hi(a)})}catch(a){let i=a?.message||String(a);if(a?.usageCap)return t.status(429).json({error:"usage_cap",message:i,cap:a.usageCap});let c=/not found/i.test(i)?404:/required|unknown agent|git repo|not running|can't resolve/i.test(i)?400:500;t.status(c).json({error:i})}});S.get("/api/tracks/:id/subtasks",(e,t)=>{t.json({subtasks:co(e.params.id).map(Hi)})});S.get("/api/tracks/:id/subtask/:sid/messages",async(e,t)=>{let n=await ym(e.params.id,e.params.sid);if(!n)return t.status(404).json({error:"subtask not found"});t.json(n)});S.post("/api/tracks/:id/subtask/:sid/cancel",(e,t)=>{try{t.json({ok:!0,subtask:Hi(Vl(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});S.post("/api/tracks/:id/subtask/:sid/merge-now",(e,t)=>{try{t.json({ok:!0,subtask:Hi(zm(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});function Hi(e){return e?{id:e.id,agent:e.agent,task:e.task,skipPermissions:e.skipPermissions,step:e.step,running:!e.finishedAt,box:e.box,branch:e.branch,stat:e.stat,files:e.files||null,conflicts:e.conflicts||[],applied:e.applied,error:e.error,canceled:e.canceled,startedAt:e.startedAt,finishedAt:e.finishedAt}:null}S.post("/api/tracks/:id/handoff-lead",async(e,t)=>{let{toAgent:n,skipPermissions:r,reason:o}=e.body||{};try{let s=await ql(e.params.id,n,r!==!1,o);t.json({ok:!0,step:s.step,toAgent:s.toAgent,fromBox:s.fromBox,skipPermissions:s.skipPermissions})}catch(s){let a=s?.message||String(s);if(s?.usageCap)return t.status(429).json({error:"usage_cap",message:a,cap:s.usageCap});t.status(/already running/i.test(a)?409:/not found/i.test(a)?404:400).json({error:a})}});S.post("/api/tracks/:id/spin-up-view",async(e,t)=>{try{t.json(await vm(e.params.id,e.body||{}))}catch(n){let r=n?.message||String(n);t.status(/already being spun up/i.test(r)?409:/not found/i.test(r)?404:400).json({error:r})}});S.get("/api/tracks/:id/handoff-lead",(e,t)=>{t.json(pA(Es(e.params.id))??{running:!1})});S.post("/api/tracks/:id/transfer-out",async(e,t)=>{try{let n=await Um(e.params.id);t.json({ok:!0,step:n.step,startedAt:n.startedAt})}catch(n){let r=n?.message||String(n);t.status(/already running/i.test(r)?409:/not found/i.test(r)?404:400).json({error:r})}});S.get("/api/tracks/:id/transfer-out",(e,t)=>{let n=Fm(e.params.id);if(!n)return t.json({running:!1});t.json({running:!n.finishedAt,step:n.step,error:n.error,startedAt:n.startedAt,finishedAt:n.finishedAt,...n.result??{}})});S.post("/api/tracks/:id/transfer-out/commit",async(e,t)=>{try{t.json(await Kl(e.params.id,e.body||{}))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:400).json({error:r})}});S.post("/api/tracks/adopt",async(e,t)=>{let{trackId:n}=e.body||{};try{t.json(await qm({...e.body||{},trackId:n}))}catch(r){let o=r?.message||String(r);t.status(/already running|already hosted/i.test(o)?409:/not found/i.test(o)?404:400).json({error:o})}});function pA(e){return e?{running:!e.finishedAt,step:e.step,error:e.error,fromBox:e.fromBox,toBox:e.toBox,toAgent:e.toAgent,skipPermissions:e.skipPermissions,startedAt:e.startedAt,finishedAt:e.finishedAt}:null}S.get("/api/debug/handoff",async(e,t)=>{let n=Math.min(Number(e.query.limit)||80,500);t.json({verbose:dc(),paths:sg,trace:await og({limit:n})})});var nw=ge.resolve(sA,"..","..","client","dist");Ye.existsSync(nw)&&(S.use(Rt.static(nw)),S.get(/^(?!\/api\/).*/,(e,t)=>t.sendFile(ge.join(nw,"index.html"),Ui)));var mA=pU.createServer(S),EU=new hU({noServer:!0}),hA=(e,t,n)=>{if(!(Mi(e)||Fs.allowed(Fs.clientIp(e))||ow.allows(e))){t.write(`HTTP/1.1 403 Forbidden\r
604
610
  \r
605
- `),t.destroy();return}if(WT(e,t,n))return;if(!UT(e,QE,{enforce:eA})){t.write(`HTTP/1.1 401 Unauthorized\r
611
+ `),t.destroy();return}if(YT(e,t,n))return;if(!JT(e,iA,{enforce:cA})){t.write(`HTTP/1.1 401 Unauthorized\r
606
612
  \r
607
- `),t.destroy();return}let r=mg(e.url);if(!r.ok){t.write(`HTTP/1.1 ${r.status} ${r.status===400?"Bad Request":"Not Found"}\r
613
+ `),t.destroy();return}let r=kg(e.url);if(!r.ok){t.write(`HTTP/1.1 ${r.status} ${r.status===400?"Bad Request":"Not Found"}\r
608
614
  \r
609
615
  `),t.destroy();return}let o=r.sessionName;if(!_e(o)){t.write(`HTTP/1.1 400 Bad Request\r
610
616
  \r
611
- `),t.destroy();return}let{cols:s,rows:a}=r;uU.handleUpgrade(e,t,n,i=>dg(i,o,{cols:s,rows:a}))};aA.on("upgrade",iA);var cA=process.env.BOSTRAT_CERT_DIR||ge.join(process.env.HOME||Xh.tmpdir(),".bostrat","certs"),zE=Number(process.env.BOSTRAT_TLS_PORT)||3443,JE=ge.join(cA,"bostrat.globopi.key"),YE=ge.join(cA,"bostrat.globopi.crt");if(Ye.existsSync(JE)&&Ye.existsSync(YE)){let e=QF.createServer({key:Ye.readFileSync(JE),cert:Ye.readFileSync(YE)},S);e.on("upgrade",iA),e.on("error",t=>{console.error(`[bostrat-agent] https listener failed (${t?.code||t?.message}) \u2014 continuing HTTP-only`)}),e.listen(zE,Au,()=>{console.log(`[bostrat-agent] https listening on ${Au||"0.0.0.0"}:${zE}`)})}aA.listen(GE,Au,()=>{console.log(`[bostrat-agent] listening on ${Au||"0.0.0.0"}:${GE}`);let e=lv(process.env);e&&console.warn(`[bostrat-agent] \u26A0 SECURITY: plane-linked node bound to ${e.host?e.host:"ALL interfaces (BOSTRAT_HOST=all)"} \u2014 the API + Views are reachable off-loopback (LAN/VPN), where the IP allowlist is spoofable and Views need no token. The plane tunnel does not require this; set BOSTRAT_HOST=127.0.0.1 once any local reverse-proxy/WireGuard path is retired (F-2).`),console.log(`[bostrat-agent] tmux socket: ${ft}`),console.log(`[bostrat-agent] auto-trigger default: ${ZE}%`),console.log(`[bostrat-agent] ip allowlist: ${Ds.open?"OPEN":process.env.BOSTRAT_ALLOW_IPS||"CLOSED (BOSTRAT_ALLOW_IPS unset)"}`+(Zh.active?` \xB7 view front-door: ${process.env.BOSTRAT_VIEW_FRONT_CIDRS} (registered views only)`:"")),Nm().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted handoff(s)")).catch(t=>console.error("[bostrat-agent] handoff reconcile failed:",t?.message||t)),Fm().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted subtask(s)")).catch(t=>console.error("[bostrat-agent] subtask reconcile failed:",t?.message||t)),Om().then(t=>t&&console.log(`[bostrat-agent] reaped ${t} orphaned box(es) on archived track(s)`)).catch(t=>console.error("[bostrat-agent] archived-orphan sweep failed:",t?.message||t)),Tm().then(t=>console.log(`[bostrat-agent] standing instructions refreshed (${t.refreshed} updated, ${t.removed} legacy CLAUDE.md removed${t.codexGlobal?`, codex global ${t.codexGlobal}`:""})`)).catch(t=>console.error("[bostrat-agent] standing-instructions refresh failed:",t?.message||t)),gU(),pU(),wU(),ik({listTracks:ae,getTrack:ne}).then(t=>console.log(`[bostrat-agent] spend caps ${t.configured?"armed":"unconfigured (fail-open)"} \u2014 seeded ${Object.keys(t.spent).length} provider counter(s)`)).catch(t=>console.error("[bostrat-agent] spend-caps seed failed (staying fail-open):",t?.message||t)),AS()&&_S({listTracks:ae}),fE(),gE(),Qv({resolveTrack:ne}),lT({listTracks:ae,createTrack:Dl,archiveTrack:io,listRepos:cn,resolveTrack:ne,sayToLead:It,answerPrompt:Ml,startLeadHandoff:Fl,interruptLead:Pl,listSubtaskJobs:co,cancelSubtask:Wl,readEvents:L,appendEvent:_,divertShip:Lh,answerPrExists:Fh,knownAgents:ii}),dU(),ra().then(t=>{t||console.warn(`[boot] no host tmux server on ${ft} and auto-start failed \u2014 boxes cannot spawn until one runs`)}),OE(),process.env.BOSTRAT_PLANE_URL&&process.env.BOSTRAT_PLANE_TOKEN&&(Iu=mv({url:process.env.BOSTRAT_PLANE_URL,token:process.env.BOSTRAT_PLANE_TOKEN,nodeId:process.env.BOSTRAT_NODE_ID||Xh.hostname(),name:process.env.BOSTRAT_NODE_NAME||Xh.hostname(),listTracks:ae,detectAgents:Ol,sampleMetrics:fT,onTracksTransferred:jm,onUpdateAvailable:async t=>{try{Eu={latest:t.latest,current:t.current},await on({...t,policy:ut()}),ut()==="auto"&&!gi(await Ss())&&Bs.arm({to:t.latest,from:t.current,kind:Ft})}catch(n){console.error(`[plane-link] update notice failed: ${n?.message||n}`)}},onUpdatePolicy:t=>rU(t).catch(()=>{}),onHelloRefused:async({current:t,min:n,latest:r,installKind:o,fix:s})=>{try{let a=r||n;if(await on({current:t,latest:a,min:n,installKind:o,required:!0,policy:ut(),status:"available",reason:"refused"}),ut()!=="off"&&a){let i=await Jl({to:a,kind:Ft,reason:"hard-floor"});i.ok?(Bs.cancel(),await on({current:t,latest:a,min:n,installKind:o,required:!0,policy:ut(),status:"updating",reason:"hard-floor"})):console.error(`[self-update] hard-floor update not started: ${i.reason} \u2014 ${s}`)}}catch(a){console.error(`[plane-link] hard-floor handling failed: ${a?.message||a}`)}},updatePolicy:ut}),console.log(`[bostrat-agent] plane link \u2192 ${process.env.BOSTRAT_PLANE_URL}`),Eo().catch(()=>{}),yS().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} runbooks to the plane`),()=>{}),eT().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} ticket links to the plane`),()=>{}),Hx().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} mocks to the plane`),()=>{}),sS().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} flows to the plane`),()=>{}),zk().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} PR links to the plane`),()=>{}))});process.on("SIGTERM",()=>{try{Iu?.stop()}catch{}setTimeout(()=>process.exit(0),150)});function dU(){fU(),gl().catch(()=>{}),setInterval(()=>gl().catch(()=>{}),1e4)}function fU(){for(let e 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 t=ge.resolve(XE,"..","bin",e),n=ge.join(process.env.HOME||"",".local","bin");if(!process.env.HOME||!Ye.existsSync(t))continue;Ye.mkdirSync(n,{recursive:!0});let r=ge.join(n,e);(Ye.existsSync(r)?Ye.readlinkSync(r):null)!==t&&(Ye.rmSync(r,{force:!0}),Ye.symlinkSync(t,r)),console.log(`[bostrat-agent] ${e} CLI linked at ${r}`)}catch(t){console.error(`[bostrat-agent] ${e} CLI link failed:`,t?.message||t)}}function pU(){let e=!1,t=async()=>{if(!e){e=!0;try{let n=await ae(),r=await AT({tracks:n});r.committed&&console.log(`[state-sync] committed (${r.staged} file(s) staged${r.pushed?", pushed":""})`)}catch{}finally{e=!1}}};setInterval(t,6e4),t()}var mU=Number(process.env.BOSTRAT_MEMORY_RECONCILE_MS)||5*6e4,hU=Number(process.env.BOSTRAT_MEMORY_RECONCILE_FIRST_MS)||5*6e4;function wU(){let e=async()=>{try{let n=await Dw();n.ran&&console.log(`[memory] one-time full backfill sweep: ${n.harvested} fact(s) harvested`);let o=(await ae()).filter(a=>!a.archivedAt&&!a.transferredTo&&a.kind!=="setup").flatMap(a=>[a.cwd,...(a.boxes||[]).map(i=>i.cwd)]).filter(Boolean),s=await Pw([...new Set(o)]);s.harvested&&console.log(`[memory] reconciler harvested ${s.harvested} fact(s) from ${o.length} live workspace(s)`)}catch{}};setTimeout(()=>{e(),setInterval(e,mU).unref()},hU).unref()}function gU(){let e=!1;setInterval(async()=>{if(!e){e=!0;try{let t=await ae();for(let n of t)n.archivedAt||n.transferredTo||!n.boxes?.some(r=>r.state==="live")||(await Cl(n.id).catch(()=>{}),await kx(n).catch(()=>{}))}catch{}finally{e=!1}}},4e3)}
617
+ `),t.destroy();return}let{cols:s,rows:a}=r;EU.handleUpgrade(e,t,n,i=>gg(i,o,{cols:s,rows:a}))};mA.on("upgrade",hA);var wA=process.env.BOSTRAT_CERT_DIR||ge.join(process.env.HOME||rw.tmpdir(),".bostrat","certs"),nA=Number(process.env.BOSTRAT_TLS_PORT)||3443,rA=ge.join(wA,"bostrat.globopi.key"),oA=ge.join(wA,"bostrat.globopi.crt");if(Ye.existsSync(rA)&&Ye.existsSync(oA)){let e=mU.createServer({key:Ye.readFileSync(rA),cert:Ye.readFileSync(oA)},S);e.on("upgrade",hA),e.on("error",t=>{console.error(`[bostrat-agent] https listener failed (${t?.code||t?.message}) \u2014 continuing HTTP-only`)}),e.listen(nA,$u,()=>{console.log(`[bostrat-agent] https listening on ${$u||"0.0.0.0"}:${nA}`)})}mA.listen(eA,$u,()=>{console.log(`[bostrat-agent] listening on ${$u||"0.0.0.0"}:${eA}`);let e=wv(process.env);e&&console.warn(`[bostrat-agent] \u26A0 SECURITY: plane-linked node bound to ${e.host?e.host:"ALL interfaces (BOSTRAT_HOST=all)"} \u2014 the API + Views are reachable off-loopback (LAN/VPN), where the IP allowlist is spoofable and Views need no token. The plane tunnel does not require this; set BOSTRAT_HOST=127.0.0.1 once any local reverse-proxy/WireGuard path is retired (F-2).`),console.log(`[bostrat-agent] tmux socket: ${ft}`),console.log(`[bostrat-agent] auto-trigger default: ${aA}%`),console.log(`[bostrat-agent] ip allowlist: ${Fs.open?"OPEN":process.env.BOSTRAT_ALLOW_IPS||"CLOSED (BOSTRAT_ALLOW_IPS unset)"}`+(ow.active?` \xB7 view front-door: ${process.env.BOSTRAT_VIEW_FRONT_CIDRS} (registered views only)`:"")),Lm().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted handoff(s)")).catch(t=>console.error("[bostrat-agent] handoff reconcile failed:",t?.message||t)),Km().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted subtask(s)")).catch(t=>console.error("[bostrat-agent] subtask reconcile failed:",t?.message||t)),Dm().then(t=>t&&console.log(`[bostrat-agent] reaped ${t} orphaned box(es) on archived track(s)`)).catch(t=>console.error("[bostrat-agent] archived-orphan sweep failed:",t?.message||t)),Rm().then(t=>console.log(`[bostrat-agent] standing instructions refreshed (${t.refreshed} updated, ${t.removed} legacy CLAUDE.md removed${t.codexGlobal?`, codex global ${t.codexGlobal}`:""})`)).catch(t=>console.error("[bostrat-agent] standing-instructions refresh failed:",t?.message||t)),CU(),IU(),OU(),mk({listTracks:ae,getTrack:ne}).then(t=>console.log(`[bostrat-agent] spend caps ${t.configured?"armed":"unconfigured (fail-open)"} \u2014 seeded ${Object.keys(t.spent).length} provider counter(s)`)).catch(t=>console.error("[bostrat-agent] spend-caps seed failed (staying fail-open):",t?.message||t)),MS()&&NS({listTracks:ae}),kE(),EE(),iT({resolveTrack:ne}),gT({listTracks:ae,createTrack:Fl,archiveTrack:io,listRepos:un,resolveTrack:ne,sayToLead:It,answerPrompt:Bl,startLeadHandoff:ql,interruptLead:Ll,listSubtaskJobs:co,cancelSubtask:Vl,readEvents:L,appendEvent:_,divertShip:Kh,answerPrExists:Gh,knownAgents:fi}),AU(),ia().then(t=>{t||console.warn(`[boot] no host tmux server on ${ft} and auto-start failed \u2014 boxes cannot spawn until one runs`)}),LE(),process.env.BOSTRAT_PLANE_URL&&process.env.BOSTRAT_PLANE_TOKEN&&(Cu=xv({url:process.env.BOSTRAT_PLANE_URL,token:process.env.BOSTRAT_PLANE_TOKEN,nodeId:process.env.BOSTRAT_NODE_ID||rw.hostname(),name:process.env.BOSTRAT_NODE_NAME||rw.hostname(),listTracks:ae,detectAgents:Pl,sampleMetrics:kT,onTracksTransferred:Wm,onUpdateAvailable:async t=>{try{Ru={latest:t.latest,current:t.current},await an({...t,policy:ut()}),ut()==="auto"&&!xi(await As())&&Us.arm({to:t.latest,from:t.current,kind:Ft})}catch(n){console.error(`[plane-link] update notice failed: ${n?.message||n}`)}},onUpdatePolicy:t=>yU(t).catch(()=>{}),onHelloRefused:async({current:t,min:n,latest:r,installKind:o,fix:s})=>{try{let a=r||n;if(await an({current:t,latest:a,min:n,installKind:o,required:!0,policy:ut(),status:"available",reason:"refused"}),ut()!=="off"&&a){let i=await Ql({to:a,kind:Ft,reason:"hard-floor"});i.ok?(Us.cancel(),await an({current:t,latest:a,min:n,installKind:o,required:!0,policy:ut(),status:"updating",reason:"hard-floor"})):console.error(`[self-update] hard-floor update not started: ${i.reason} \u2014 ${s}`)}}catch(a){console.error(`[plane-link] hard-floor handling failed: ${a?.message||a}`)}},updatePolicy:ut}),console.log(`[bostrat-agent] plane link \u2192 ${process.env.BOSTRAT_PLANE_URL}`),Eo().catch(()=>{}),ES().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} runbooks to the plane`),()=>{}),cT().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} ticket links to the plane`),()=>{}),J0().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} mocks to the plane`),()=>{}),fS().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} flows to the plane`),()=>{}),tx().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} PR links to the plane`),()=>{}))});process.on("SIGTERM",()=>{try{Cu?.stop()}catch{}setTimeout(()=>process.exit(0),150)});function AU(){_U(),xl().catch(()=>{}),setInterval(()=>xl().catch(()=>{}),1e4)}function _U(){for(let e 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 t=ge.resolve(sA,"..","bin",e),n=ge.join(process.env.HOME||"",".local","bin");if(!process.env.HOME||!Ye.existsSync(t))continue;Ye.mkdirSync(n,{recursive:!0});let r=ge.join(n,e);(Ye.existsSync(r)?Ye.readlinkSync(r):null)!==t&&(Ye.rmSync(r,{force:!0}),Ye.symlinkSync(t,r)),console.log(`[bostrat-agent] ${e} CLI linked at ${r}`)}catch(t){console.error(`[bostrat-agent] ${e} CLI link failed:`,t?.message||t)}}function IU(){let e=!1,t=async()=>{if(!e){e=!0;try{let n=await ae(),r=await NT({tracks:n});r.committed&&console.log(`[state-sync] committed (${r.staged} file(s) staged${r.pushed?", pushed":""})`)}catch{}finally{e=!1}}};setInterval(t,6e4),t()}var RU=Number(process.env.BOSTRAT_MEMORY_RECONCILE_MS)||5*6e4,$U=Number(process.env.BOSTRAT_MEMORY_RECONCILE_FIRST_MS)||5*6e4;function OU(){let e=async()=>{try{let n=await Hw();n.ran&&console.log(`[memory] one-time full backfill sweep: ${n.harvested} fact(s) harvested`);let o=(await ae()).filter(a=>!a.archivedAt&&!a.transferredTo&&a.kind!=="setup").flatMap(a=>[a.cwd,...(a.boxes||[]).map(i=>i.cwd)]).filter(Boolean),s=await Uw([...new Set(o)]);s.harvested&&console.log(`[memory] reconciler harvested ${s.harvested} fact(s) from ${o.length} live workspace(s)`)}catch{}};setTimeout(()=>{e(),setInterval(e,RU).unref()},$U).unref()}function CU(){let e=!1;setInterval(async()=>{if(!e){e=!0;try{let t=await ae();for(let n of t)n.archivedAt||n.transferredTo||!n.boxes?.some(r=>r.state==="live")||(await Dl(n.id).catch(()=>{}),await _0(n).catch(()=>{}))}catch{}finally{e=!1}}},4e3)}