bostrat-node 1.9.6 → 1.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +200 -196
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,52 +1,52 @@
1
- var GO=Object.defineProperty;var G=(e,t,n)=>()=>{if(n)throw n[0];try{return e&&(t=e(e=0)),t}catch(r){throw n=[r],r}};var Dp=(e,t)=>{for(var n in t)GO(e,n,{get:t[n],enumerable:!0})};import{createHash as zO,randomBytes as VO,timingSafeEqual as JO}from"node:crypto";function ub(){return VO(32).toString("hex")}function Ha(e){let t=typeof e=="string"?e.trim():"";return t?zO("sha256").update(t).digest("hex"):null}function db(e,t){return typeof e!="string"||typeof t!="string"||e.length!==t.length||!e?!1:JO(Buffer.from(e),Buffer.from(t))}function qa(e,t={},{now:n=Date.now(),log:r=console.warn}={}){if(Bp.set(e,(Bp.get(e)||0)+1),jp.has(e)&&n-jp.get(e)<YO)return!1;jp.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=${Bp.get(e)}${o?` ${o}`:""}`),!0}async function pb(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 zn,Vn,Bp,jp,YO,fs=G(()=>{zn="BOSTRAT_HOOK_TOKEN",Vn="x-bostrat-hook";Bp=new Map,jp=new Map,YO=6e4});import $t from"node:fs/promises";import fb from"node:os";import At from"node:path";import{execFile as XO}from"node:child_process";import{promisify as ZO}from"node:util";function fl(){return/^(1|true|yes|on)$/i.test(process.env.BOSTRAT_CLAUDE_USE_API_KEY||"")&&process.env.ANTHROPIC_API_KEY?.trim()||null}function QO(){return process.env.CLAUDE_CONFIG_DIR?At.join(process.env.CLAUDE_CONFIG_DIR,".claude.json"):At.join(fb.homedir(),".claude.json")}function eM(){return process.env.CLAUDE_CONFIG_DIR?At.join(process.env.CLAUDE_CONFIG_DIR,"settings.json"):At.join(fb.homedir(),".claude","settings.json")}async function vr(e){if(!e||typeof e!="string")return;let t=At.resolve(e),n=QO(),r=eM(),o={};try{o=JSON.parse(await $t.readFile(n,"utf8"))}catch{}o.hasCompletedOnboarding=!0,o.theme||(o.theme="dark"),o.projects=o.projects||{},o.projects[t]=o.projects[t]||{};let s=o.projects[t];Array.isArray(s.allowedTools)||(s.allowedTools=[]),s.hasTrustDialogAccepted=!0,s.hasCompletedProjectOnboarding=!0;let a=process.env.ANTHROPIC_API_KEY;if(a){let c=a.slice(-20);o.customApiKeyResponses=o.customApiKeyResponses||{},o.customApiKeyResponses.approved=o.customApiKeyResponses.approved||[],o.customApiKeyResponses.rejected=o.customApiKeyResponses.rejected||[],o.customApiKeyResponses.approved.includes(c)||o.customApiKeyResponses.approved.push(c)}await $t.mkdir(At.dirname(n),{recursive:!0}),await $t.writeFile(n,JSON.stringify(o,null,2));let i={};try{i=JSON.parse(await $t.readFile(r,"utf8"))}catch{}if(i.skipDangerousModePermissionPrompt=!0,i.remoteControlAtStartup=!1,i.tui===void 0&&(i.tui="default"),process.env.BOSTRAT_HOOKS!=="off"){let l=`curl -sS -m 3 -X POST ${process.env.BOSTRAT_HOOK_URL||`http://127.0.0.1:${process.env.PORT||3362}/api/hook`} -H 'content-type: application/json' -H "${Vn}: $${zn}" --data-binary @- >/dev/null 2>&1 || true`,u=[{hooks:[{type:"command",command:l}]}];i.hooks=i.hooks||{};for(let d of["SessionStart","UserPromptSubmit","Stop"])i.hooks[d]=u;i.hooks.PostToolUse=[{matcher:"*",hooks:[{type:"command",command:l}]}]}await $t.mkdir(At.dirname(r),{recursive:!0}),await $t.writeFile(r,JSON.stringify(i,null,2)),await tM(t)}async function tM(e){try{let t=At.resolve(e),n=At.join(t,".bostrat","memory","claude"),r=At.join(t,".claude","settings.local.json"),o={};try{o=JSON.parse(await $t.readFile(r,"utf8"))}catch{}let s=o.autoMemoryDirectory,a=typeof s=="string"&&s.includes(At.join(".bostrat","memory"));if(s&&!a||s===n)return;o.autoMemoryDirectory=n,await $t.mkdir(n,{recursive:!0}),await $t.mkdir(At.dirname(r),{recursive:!0}),await $t.writeFile(r,JSON.stringify(o,null,2)),await nM(t,["/.claude/settings.local.json"])}catch{}}async function nM(e,t){try{let{stdout:n}=await ZO(XO)("git",["-C",e,"rev-parse","--git-path","info/exclude"]),r=At.resolve(e,n.trim()),o=await $t.readFile(r,"utf8").catch(()=>""),s=t.filter(a=>!o.split(`
2
- `).includes(a));if(!s.length)return;await $t.mkdir(At.dirname(r),{recursive:!0}),await $t.appendFile(r,(o&&!o.endsWith(`
1
+ var cM=Object.defineProperty;var G=(e,t,n)=>()=>{if(n)throw n[0];try{return e&&(t=e(e=0)),t}catch(r){throw n=[r],r}};var Zp=(e,t)=>{for(var n in t)cM(e,n,{get:t[n],enumerable:!0})};import{createHash as lM,randomBytes as uM,timingSafeEqual as dM}from"node:crypto";function Eb(){return uM(32).toString("hex")}function To(e){let t=typeof e=="string"?e.trim():"";return t?lM("sha256").update(t).digest("hex"):null}function _b(e,t){return typeof e!="string"||typeof t!="string"||e.length!==t.length||!e?!1:dM(Buffer.from(e),Buffer.from(t))}function Xa(e,t={},{now:n=Date.now(),log:r=console.warn}={}){if(Qp.set(e,(Qp.get(e)||0)+1),ef.has(e)&&n-ef.get(e)<pM)return!1;ef.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=${Qp.get(e)}${o?` ${o}`:""}`),!0}async function Ib(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 Yn,Xn,Qp,ef,pM,Ts=G(()=>{Yn="BOSTRAT_HOOK_TOKEN",Xn="x-bostrat-hook";Qp=new Map,ef=new Map,pM=6e4});import Pt from"node:fs/promises";import $b from"node:os";import _t from"node:path";import{execFile as fM}from"node:child_process";import{promisify as mM}from"node:util";function gl(){return/^(1|true|yes|on)$/i.test(process.env.BOSTRAT_CLAUDE_USE_API_KEY||"")&&process.env.ANTHROPIC_API_KEY?.trim()||null}function hM(){return process.env.CLAUDE_CONFIG_DIR?_t.join(process.env.CLAUDE_CONFIG_DIR,".claude.json"):_t.join($b.homedir(),".claude.json")}function wM(){return process.env.CLAUDE_CONFIG_DIR?_t.join(process.env.CLAUDE_CONFIG_DIR,"settings.json"):_t.join($b.homedir(),".claude","settings.json")}async function _r(e){if(!e||typeof e!="string")return;let t=_t.resolve(e),n=hM(),r=wM(),o={};try{o=JSON.parse(await Pt.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 Pt.mkdir(_t.dirname(n),{recursive:!0}),await Pt.writeFile(n,JSON.stringify(o,null,2));let i={};try{i=JSON.parse(await Pt.readFile(r,"utf8"))}catch{}if(i.skipDangerousModePermissionPrompt=!0,i.remoteControlAtStartup=!1,i.tui===void 0&&(i.tui="default"),process.env.BOSTRAT_HOOKS!=="off"){let l=`curl -sS -m 3 -X POST ${process.env.BOSTRAT_HOOK_URL||`http://127.0.0.1:${process.env.PORT||3362}/api/hook`} -H 'content-type: application/json' -H "${Xn}: $${Yn}" --data-binary @- >/dev/null 2>&1 || true`,u=[{hooks:[{type:"command",command:l}]}];i.hooks=i.hooks||{};for(let d of["SessionStart","UserPromptSubmit","Stop"])i.hooks[d]=u;i.hooks.PostToolUse=[{matcher:"*",hooks:[{type:"command",command:l}]}]}await Pt.mkdir(_t.dirname(r),{recursive:!0}),await Pt.writeFile(r,JSON.stringify(i,null,2)),await gM(t)}async function gM(e){try{let t=_t.resolve(e),n=_t.join(t,".bostrat","memory","claude"),r=_t.join(t,".claude","settings.local.json"),o={};try{o=JSON.parse(await Pt.readFile(r,"utf8"))}catch{}let s=o.autoMemoryDirectory,a=typeof s=="string"&&s.includes(_t.join(".bostrat","memory"));if(s&&!a||s===n)return;o.autoMemoryDirectory=n,await Pt.mkdir(n,{recursive:!0}),await Pt.mkdir(_t.dirname(r),{recursive:!0}),await Pt.writeFile(r,JSON.stringify(o,null,2)),await yM(t,["/.claude/settings.local.json"])}catch{}}async function yM(e,t){try{let{stdout:n}=await mM(fM)("git",["-C",e,"rev-parse","--git-path","info/exclude"]),r=_t.resolve(e,n.trim()),o=await Pt.readFile(r,"utf8").catch(()=>""),s=t.filter(a=>!o.split(`
2
+ `).includes(a));if(!s.length)return;await Pt.mkdir(_t.dirname(r),{recursive:!0}),await Pt.appendFile(r,(o&&!o.endsWith(`
3
3
  `)?`
4
4
  `:"")+s.join(`
5
5
  `)+`
6
- `)}catch{}}var Wa=G(()=>{fs()});import Lp from"node:fs/promises";import rM from"node:os";import ml from"node:path";function oM(){let e=process.env.CODEX_HOME||ml.join(rM.homedir(),".codex");return ml.join(e,"config.toml")}function mb(e){return`[projects."${e}"]`}function sM(e,t){let n=mb(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 ms(e){if(!e||typeof e!="string")return;let t=ml.resolve(e),n=oM(),r="";try{r=await Lp.readFile(n,"utf8")}catch{}if(sM(r,t))return;let o=mb(t);if(r.includes(o)){let a=r.indexOf(o)+o.length,c=r.slice(a).search(/^\s*\[/m),l=c===-1?r.length:a+c,u=r.slice(a,l),d=/trust_level\s*=/.test(u)?u.replace(/trust_level\s*=\s*"[^"]*"/,'trust_level = "trusted"'):`${u.replace(/\s*$/,"")}
6
+ `)}catch{}}var Za=G(()=>{Ts()});import tf from"node:fs/promises";import bM from"node:os";import yl from"node:path";function kM(){let e=process.env.CODEX_HOME||yl.join(bM.homedir(),".codex");return yl.join(e,"config.toml")}function Rb(e){return`[projects."${e}"]`}function xM(e,t){let n=Rb(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 Es(e){if(!e||typeof e!="string")return;let t=yl.resolve(e),n=kM(),r="";try{r=await tf.readFile(n,"utf8")}catch{}if(xM(r,t))return;let o=Rb(t);if(r.includes(o)){let a=r.indexOf(o)+o.length,c=r.slice(a).search(/^\s*\[/m),l=c===-1?r.length:a+c,u=r.slice(a,l),d=/trust_level\s*=/.test(u)?u.replace(/trust_level\s*=\s*"[^"]*"/,'trust_level = "trusted"'):`${u.replace(/\s*$/,"")}
7
7
  trust_level = "trusted"
8
8
  `;r=r.slice(0,a)+d+r.slice(l)}else{let s=`
9
9
  ${o}
10
10
  trust_level = "trusted"
11
11
  `;r=r.trimEnd()+s+(r.length&&!r.endsWith(`
12
12
  `)?`
13
- `:"")}try{await Lp.mkdir(ml.dirname(n),{recursive:!0}),await Lp.writeFile(n,r)}catch(s){console.warn(`[codex-config] could not seed folder trust for ${t}: ${s?.message||s}`)}}var hl=G(()=>{});import hb from"node:fs/promises";import aM from"node:os";import Ka from"node:path";function iM(e){let n=Ka.resolve(e).slice(1).replace(/\//g,"-").replace(/\./g,""),r=process.env.CURSOR_CONFIG_DIR||Ka.join(aM.homedir(),".cursor");return Ka.join(r,"projects",n)}async function hs(e){if(!e||typeof e!="string")return;let t=Ka.resolve(e),n=iM(t),r=Ka.join(n,".workspace-trusted");await hb.mkdir(n,{recursive:!0}),await hb.writeFile(r,`${JSON.stringify({trustedAt:new Date().toISOString(),workspacePath:t},null,2)}
14
- `,"utf8")}var wl=G(()=>{});import Up from"node:fs/promises";import Sr from"node:path";import{execFile as cM}from"node:child_process";import{promisify as lM}from"node:util";async function hM(e){try{return(await Up.stat(Sr.join(e,".git"))).isDirectory()?"repo":"worktree"}catch{return null}}async function wM(e){let t=i=>Up.readFile(Sr.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 Jn(){let e=new Map;async function t(o,s){if(e.has(o))return;let a=await hM(o);if(a==="worktree")return;if(a==="repo"){e.set(o,{path:o,name:Sr.basename(o),branch:await wM(o)});return}if(s>=fM)return;let i;try{i=await Up.readdir(o,{withFileTypes:!0})}catch{return}for(let c of i)!c.isDirectory()||c.name.startsWith(".")||mM.has(c.name)||await t(Sr.join(o,c.name),s+1)}for(let o of pM)await t(Sr.resolve(o),0);let n=new Set,r=[];for(let o of e.values()){let s=await _e(o.path),a=s?.toLowerCase();if(a){if(n.has(a))continue;n.add(a),o.slug=s}r.push(o)}return r.sort((o,s)=>o.name.localeCompare(s.name))}function gM(e){let t=String(e||"").trim().match(/github\.com[:/]+([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i);return t?`${t[1]}/${t[2]}`:null}async function _e(e){if(!e)return null;if(Fp.has(e))return Fp.get(e);let t=null;try{let{stdout:n}=await uM("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});t=gM(n)}catch{t=null}return Fp.set(e,t),t}async function ws(e){let t=String(e||"").toLowerCase();if(!t)return null;for(let n of await Jn())if((await _e(n.path))?.toLowerCase()===t)return n.path;return null}var uM,wb,dM,pM,fM,mM,Fp,Tr=G(()=>{uM=lM(cM),wb=process.env.HOME||"/home/globo",dM=Sr.join(process.env.BOSTRAT_STATE_DIR||Sr.join(wb,".bostrat"),"repos"),pM=[...(process.env.BOSTRAT_REPOS_ROOT||Sr.join(wb,"Documents")).split(","),dM].map(e=>e.trim()).filter(Boolean),fM=Number(process.env.BOSTRAT_REPOS_DEPTH)||3,mM=new Set(["node_modules",".git",".cache","dist","build",".next","vendor","__pycache__","venv",".venv","target"]);Fp=new Map});import yM from"node:fs";import gb from"node:fs/promises";import Ga from"node:path";import bM from"node:os";import{fileURLToPath as kM}from"node:url";import{execFile as xM}from"node:child_process";import{promisify as vM}from"node:util";function Re(e=process.env){let t=e.BOSTRAT_PLANE_URL||"";if(!t)return null;try{let n=new URL(t);return n.protocol=n.protocol==="ws:"?"http:":"https:",n.origin}catch{return null}}function gl(e=process.env){return!!(Re(e)&&e.BOSTRAT_PLANE_TOKEN)}async function yl(e,{env:t=process.env}={}){let n=String(e||"").toLowerCase();if(!bb.test(n))throw gs("repo must be owner/name",400);let r=Hp.get(n);if(r&&r.expiresAt-Date.now()>AM)return r;if(!gl(t))throw gs("node is not plane-linked \u2014 GitHub auth unavailable",503);let o;try{o=await kb(`${Re(t)}/v1/github/token?repo=${encodeURIComponent(e)}`,{headers:xb(t)})}catch(i){if(r&&r.expiresAt>Date.now())return r;throw gs(`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 gs(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 Hp.set(n,a),a}async function za({env:e=process.env,force:t=!1}={}){if(!gl(e))return{configured:!1,repos:[],username:null};if(!t&&ko&&Date.now()-ko.at<EM)return ko.data;try{let n=await kb(`${Re(e)}/v1/github/repos`,{headers:xb(e)});if(!n.ok)throw new Error(`plane replied ${n.status}`);let r=await n.json();return ko={at:Date.now(),data:r},r}catch(n){return ko?ko.data:{configured:!0,repos:[],username:null,error:n?.message||String(n)}}}function vb(){Hp.clear(),ko=null}async function vn({cwd:e=null,slug:t=null,env:n=process.env}={}){try{let r=t||(e?await _e(e):null);if(!r)return{};let{token:o}=await yl(r,{env:n});return o?{GH_TOKEN:o}:{}}catch{return{}}}async function qp({env:e=process.env}={}){return(await za({env:e})).username??null}function RM(e){let[t,n]=String(e).split("/");return Ga.join(TM,t,n)}async function Wp(e,{env:t=process.env}={}){let n=(...r)=>yb("git",["-C",e,...r],{timeout:1e4});await n("config","--replace-all","credential.helper",""),await n("config","--add","credential.helper",`!"${IM()}" ${$M(t)}`),await n("config","credential.useHttpPath","true")}async function bl(e,{env:t=process.env,baseUrl:n="https://github.com"}={}){if(!bb.test(String(e||"")))throw gs(`bad repo slug "${e}"`,400);let r=RM(e);if(yM.existsSync(Ga.join(r,".git")))return r;let{token:o}=await yl(e,{env:t});await gb.mkdir(Ga.dirname(r),{recursive:!0});let s="!f() { echo username=x-access-token; echo password=$BOSTRAT_GIT_TOKEN; }; f";try{await yb("git",["-c","credential.helper=","-c",`credential.helper=${s}`,"clone","--no-tags","-q",`${n}/${e}.git`,r],{timeout:_M,env:{...t,BOSTRAT_GIT_TOKEN:o,GIT_TERMINAL_PROMPT:"0"}})}catch(a){throw await gb.rm(r,{recursive:!0,force:!0}).catch(()=>{}),gs(`clone of ${e} failed: ${a?.stderr?.trim?.()||a?.message||a}`,502)}return await Wp(r,{env:t}),r}var yb,SM,TM,bb,AM,EM,_M,kb,Hp,ko,xb,gs,IM,$M,pt=G(()=>{Tr();yb=vM(xM),SM=process.env.BOSTRAT_STATE_DIR||Ga.join(process.env.HOME||bM.tmpdir(),".bostrat"),TM=Ga.join(SM,"repos"),bb=/^[^/\s]+\/[^/\s]+$/,AM=5*6e4,EM=6e4,_M=10*6e4,kb=fetch,Hp=new Map,ko=null;xb=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),gs=(e,t)=>Object.assign(new Error(e),{status:t});IM=()=>kM(new URL("../bin/bostrat-git-credential",import.meta.url)),$M=(e=process.env)=>`http://127.0.0.1:${Number(e.PORT)||3362}`});function Tb(e=process.env){return!!(Re(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Eb(e,t,n,r=Sb){let o=Re(n),s=new AbortController,a=setTimeout(()=>s.abort(),r);try{return await MM(`${o}${e}`,{...t,signal:s.signal})}finally{clearTimeout(a)}}async function _b(e,{env:t=process.env,force:n=!1,timeoutMs:r=Sb}={}){if(!Tb(t))return{facts:[],source:"unconfigured"};let o=Kp.get(e);if(!n&&o&&Date.now()-o.at<OM)return{facts:o.facts,source:"cache"};try{let s=await Eb(`/v1/memory/${encodeURIComponent(e)}`,{headers:Ab(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 Kp.set(e,{at:Date.now(),facts:i}),{facts:i,source:"plane"}}catch(s){return o?{facts:o.facts,source:"stale",error:s?.message}:{facts:[],source:"unreachable",error:s?.message}}}async function kl(e,t,{env:n=process.env}={}){if(!Tb(n))return{pushed:0,source:"unconfigured"};if(!t?.length)return{pushed:0,source:"empty"};try{let r=await Eb(`/v1/memory/${encodeURIComponent(e)}`,{method:"POST",headers:{...Ab(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 Kp.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 OM,Sb,Kp,MM,Ab,Ib=G(()=>{pt();OM=6e4,Sb=5e3,Kp=new Map,MM=(...e)=>fetch(...e);Ab=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});import Gp from"node:fs/promises";import ys from"node:path";import CM from"node:os";import{EventEmitter as NM}from"node:events";import{randomUUID as PM}from"node:crypto";function bs(e){return e?.cwd?ys.join(e.cwd,".bostrat","events"):ys.join(zp,"events")}async function LM(e,t){if(!xl.has(t)){let o=(await K(e,t)).reduce((s,a)=>a.seq>s?a.seq:s,0);xl.set(t,o)}let n=xl.get(t)+1;return xl.set(t,n),n}function Vp(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 M(e,t){let n=typeof e=="string"?e:e?.id;if(!n)throw new Error("appendEvent: a track (or trackId) is required");if(!t||!DM.has(t.type))throw new Error(`appendEvent: unknown event type "${t?.type}"`);if(t.actor&&!BM.has(t.actor))throw new Error(`appendEvent: bad actor "${t.actor}"`);if(t.source&&!jM.has(t.source))throw new Error(`appendEvent: bad source "${t.source}"`);let r=typeof e=="string"?ys.join(zp,"events"):bs(e),o=t.epoch;if(o==null&&typeof e=="object"&&t.boxId&&Array.isArray(e?.boxes)){let u=e.boxes.find(d=>d.name===t.boxId);o=Vp(u,Number(t.payload?.ts??t.ts)||Date.now())}let s=await LM(r,n),a=t.userId??process.env.BOSTRAT_OWNER??null,i={id:t.id||PM(),trackId:n,boxId:t.boxId??null,...o!=null?{epoch:o}:{},...a?{userId:a}:{},seq:s,ts:t.ts??Date.now(),type:t.type,actor:t.actor??"system",provider:t.provider??null,source:t.source??"orchestrator",payload:t.payload??{},...t.causationId?{causationId:t.causationId}:{},...t.correlationId?{correlationId:t.correlationId}:{}},c=JSON.stringify(i),l=i;return Rb(c)&&(c=Ob(c),l=JSON.parse(c)),await Gp.mkdir(r,{recursive:!0}),await Gp.appendFile($b(r,n),c+`
15
- `),Je.emit("event",l),Je.emit(`track:${n}`,l),l}async function K(e,t){let n,r;typeof e=="string"&&t?(n=e,r=t):(r=typeof e=="string"?e:e?.id,n=typeof e=="string"?ys.join(zp,"events"):bs(e));let o;try{o=await Gp.readFile($b(n,r),"utf8")}catch{return[]}let s=[];for(let a of o.split(`
16
- `))if(a.trim())try{s.push(JSON.parse(Rb(a)?Ob(a):a))}catch{}return s}function Mb(e,t){let n=`track:${e}`;return Je.on(n,t),()=>Je.off(n,t)}var DM,BM,jM,Je,zp,$b,xl,FM,Rb,Ob,de=G(()=>{DM=new Set(["session.ready","turn.user","turn.agent","turn.retracted","peer.message","provider.error","delivery.queued","delivery.settled","turn.interrupted","tool.called","tool.result","prompt.raised","prompt.answered","prompt.dismissed","prompt.autoRejected","box.fullscreen.detected","box.fullscreen.answered","context.usage","cost.recorded","memory.seed","memory.harvested","handoff.artifact","code.pushed","code.committed","code.rework","rework.cause.offered","rework.cause.answered","rework.cause.retracted","handoff.started","handoff.step","handoff.done","handoff.failed","subtask.delegated","subtask.merged","job.started","job.stalled","pr.state.changed","pr.offered","pr.offer.answered","pr.exists.offered","pr.exists.answered","box.state.changed","view.state.changed","view.spinup.failed","mock.state.changed","flow.state.changed","runbook.state.changed","ticket.linked","ticket.sync.failed","ticket.move.offered","ticket.move.answered","ticket.state.changed","ticket.commented","ticket.flow.changed","ticket.create.offered","ticket.create.answered","ticket.created","loop.create.offered","loop.create.answered","loop.created","loop.update.offered","loop.update.answered","loop.updated","loop.delete.offered","loop.delete.answered","loop.deleted","loop.paused","followup.armed","followup.armed.cancelled","followup.offered","followup.answered","followup.create.offered","followup.create.answered","followup.created","planning.change.offered","planning.change.answered","planning.changed","notify.raised","usage.cap.hit","usage.cap.warning","provider.connected","track.summary.recorded","track.transferred","track.recovered","track.phase.changed","track.operation.changed","track.obligations.changed","track.circuit.tagged","blueprint.item.bound","decision.recorded","changelog.published","stall.detected","error"]),BM=new Set(["user","agent","orchestrator","system","peer"]),jM=new Set(["hook","otel","statusline","transcript","pane","orchestrator","vendor","cli"]),Je=new NM;Je.setMaxListeners(0);zp=process.env.BOSTRAT_STATE_DIR||ys.join(process.env.HOME||CM.tmpdir(),".bostrat");$b=(e,t)=>ys.join(e,`${t}.ndjson`),xl=new Map;FM=/(?<!\\)((?:\\\\)*)\\u0000/g,Rb=e=>e.includes("\\u0000"),Ob=e=>e.replace(FM,"$1\\ufffd")});import re from"node:fs/promises";import UM from"node:os";import be from"node:path";import{execFile as HM}from"node:child_process";import{promisify as qM}from"node:util";function Sl(){return be.join(Tl,"memory","repos")}function xo(e){return e===Yn?be.join(Tl,"memory",Yn):be.join(Sl(),e)}async function Ja(e){try{return JSON.parse(await re.readFile(be.join(e,Lb),"utf8"))}catch{return{}}}async function Yp(e,t){let n=await Ja(e);for(let[r,o]of t)n[r]=Math.max(Number(n[r])||0,o);await re.mkdir(e,{recursive:!0}),await re.writeFile(be.join(e,Lb),JSON.stringify(n))}function Nb(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 Pb(e){try{let{stdout:t}=await WM("git",["-C",e,"config","--get","remote.origin.url"]);return t.trim()||null}catch{return null}}async function Xp(e){if(!e)return[];let t=Nb(await Pb(e));if(t)return[t];let n=[],r=[];try{r=await re.readdir(e,{withFileTypes:!0})}catch{return[]}for(let o of r){if(!o.isDirectory()||o.name.startsWith("."))continue;let s=Nb(await Pb(be.join(e,o.name)));s&&!n.includes(s)&&n.push(s)}return n}function Al(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 Ar(e,t){let n=new RegExp(`^\\s*${t}:\\s*(.+?)\\s*$`,"m").exec(e||"");return n?n[1].replace(/^"|"$/g,""):null}async function Sn(e,t=null){let n=t??await re.readFile(e,"utf8").catch(()=>""),{fm:r}=Al(n),o=Ar(r,"modified"),s=o?Date.parse(o):NaN;if(Number.isFinite(s))return s;try{return(await re.stat(e)).mtimeMs}catch{return 0}}function Fb(e,t){let n=Ar(e,"scope"),r=/^repo:([a-z0-9][a-z0-9._-]*)$/i.exec(n||"");if(r)return r[1].toLowerCase();if((n||"").toLowerCase()===Yn){let o=Ar(e,"trust");if(!o||/^operator/i.test(o))return Yn}return t}function Zp(e,t,n,r=new Map){let o=(e||"").split(`
13
+ `:"")}try{await tf.mkdir(yl.dirname(n),{recursive:!0}),await tf.writeFile(n,r)}catch(s){console.warn(`[codex-config] could not seed folder trust for ${t}: ${s?.message||s}`)}}var bl=G(()=>{});import Ob from"node:fs/promises";import vM from"node:os";import Qa from"node:path";function SM(e){let n=Qa.resolve(e).slice(1).replace(/\//g,"-").replace(/\./g,""),r=process.env.CURSOR_CONFIG_DIR||Qa.join(vM.homedir(),".cursor");return Qa.join(r,"projects",n)}async function _s(e){if(!e||typeof e!="string")return;let t=Qa.resolve(e),n=SM(t),r=Qa.join(n,".workspace-trusted");await Ob.mkdir(n,{recursive:!0}),await Ob.writeFile(r,`${JSON.stringify({trustedAt:new Date().toISOString(),workspacePath:t},null,2)}
14
+ `,"utf8")}var kl=G(()=>{});import rf from"node:fs/promises";import Ir from"node:path";import{execFile as AM}from"node:child_process";import{promisify as TM}from"node:util";async function OM(e){try{return(await rf.stat(Ir.join(e,".git"))).isDirectory()?"repo":"worktree"}catch{return null}}async function MM(e){let t=i=>rf.readFile(Ir.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 Zn(){let e=new Map;async function t(o,s){if(e.has(o))return;let a=await OM(o);if(a==="worktree")return;if(a==="repo"){e.set(o,{path:o,name:Ir.basename(o),branch:await MM(o)});return}if(s>=$M)return;let i;try{i=await rf.readdir(o,{withFileTypes:!0})}catch{return}for(let c of i)!c.isDirectory()||c.name.startsWith(".")||RM.has(c.name)||await t(Ir.join(o,c.name),s+1)}for(let o of IM)await t(Ir.resolve(o),0);let n=new Set,r=[];for(let o of e.values()){let s=await _e(o.path),a=s?.toLowerCase();if(a){if(n.has(a))continue;n.add(a),o.slug=s}r.push(o)}return r.sort((o,s)=>o.name.localeCompare(s.name))}function CM(e){let t=String(e||"").trim().match(/github\.com[:/]+([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i);return t?`${t[1]}/${t[2]}`:null}async function _e(e){if(!e)return null;if(nf.has(e))return nf.get(e);let t=null;try{let{stdout:n}=await EM("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});t=CM(n)}catch{t=null}return nf.set(e,t),t}async function Is(e){let t=String(e||"").toLowerCase();if(!t)return null;for(let n of await Zn())if((await _e(n.path))?.toLowerCase()===t)return n.path;return null}var EM,Mb,_M,IM,$M,RM,nf,$r=G(()=>{EM=TM(AM),Mb=process.env.HOME||"/home/globo",_M=Ir.join(process.env.BOSTRAT_STATE_DIR||Ir.join(Mb,".bostrat"),"repos"),IM=[...(process.env.BOSTRAT_REPOS_ROOT||Ir.join(Mb,"Documents")).split(","),_M].map(e=>e.trim()).filter(Boolean),$M=Number(process.env.BOSTRAT_REPOS_DEPTH)||3,RM=new Set(["node_modules",".git",".cache","dist","build",".next","vendor","__pycache__","venv",".venv","target"]);nf=new Map});import NM from"node:fs";import Cb from"node:fs/promises";import ei from"node:path";import PM from"node:os";import{fileURLToPath as DM}from"node:url";import{execFile as BM}from"node:child_process";import{promisify as jM}from"node:util";function Oe(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 xl(e=process.env){return!!(Oe(e)&&e.BOSTRAT_PLANE_TOKEN)}async function vl(e,{env:t=process.env}={}){let n=String(e||"").toLowerCase();if(!Pb.test(n))throw $s("repo must be owner/name",400);let r=of.get(n);if(r&&r.expiresAt-Date.now()>UM)return r;if(!xl(t))throw $s("node is not plane-linked \u2014 GitHub auth unavailable",503);let o;try{o=await Db(`${Oe(t)}/v1/github/token?repo=${encodeURIComponent(e)}`,{headers:Bb(t)})}catch(i){if(r&&r.expiresAt>Date.now())return r;throw $s(`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 $s(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 of.set(n,a),a}async function ti({env:e=process.env,force:t=!1}={}){if(!xl(e))return{configured:!1,repos:[],username:null};if(!t&&Eo&&Date.now()-Eo.at<HM)return Eo.data;try{let n=await Db(`${Oe(e)}/v1/github/repos`,{headers:Bb(e)});if(!n.ok)throw new Error(`plane replied ${n.status}`);let r=await n.json();return Eo={at:Date.now(),data:r},r}catch(n){return Eo?Eo.data:{configured:!0,repos:[],username:null,error:n?.message||String(n)}}}function jb(){of.clear(),Eo=null}async function An({cwd:e=null,slug:t=null,env:n=process.env}={}){try{let r=t||(e?await _e(e):null);if(!r)return{};let{token:o}=await vl(r,{env:n});return o?{GH_TOKEN:o}:{}}catch{return{}}}async function sf({env:e=process.env}={}){return(await ti({env:e})).username??null}function GM(e){let[t,n]=String(e).split("/");return ei.join(FM,t,n)}async function af(e,{env:t=process.env}={}){let n=(...r)=>Nb("git",["-C",e,...r],{timeout:1e4});await n("config","--replace-all","credential.helper",""),await n("config","--add","credential.helper",`!"${qM()}" ${KM(t)}`),await n("config","credential.useHttpPath","true")}async function Sl(e,{env:t=process.env,baseUrl:n="https://github.com"}={}){if(!Pb.test(String(e||"")))throw $s(`bad repo slug "${e}"`,400);let r=GM(e);if(NM.existsSync(ei.join(r,".git")))return r;let{token:o}=await vl(e,{env:t});await Cb.mkdir(ei.dirname(r),{recursive:!0});let s="!f() { echo username=x-access-token; echo password=$BOSTRAT_GIT_TOKEN; }; f";try{await Nb("git",["-c","credential.helper=","-c",`credential.helper=${s}`,"clone","--no-tags","-q",`${n}/${e}.git`,r],{timeout:WM,env:{...t,BOSTRAT_GIT_TOKEN:o,GIT_TERMINAL_PROMPT:"0"}})}catch(a){throw await Cb.rm(r,{recursive:!0,force:!0}).catch(()=>{}),$s(`clone of ${e} failed: ${a?.stderr?.trim?.()||a?.message||a}`,502)}return await af(r,{env:t}),r}var Nb,LM,FM,Pb,UM,HM,WM,Db,of,Eo,Bb,$s,qM,KM,ft=G(()=>{$r();Nb=jM(BM),LM=process.env.BOSTRAT_STATE_DIR||ei.join(process.env.HOME||PM.tmpdir(),".bostrat"),FM=ei.join(LM,"repos"),Pb=/^[^/\s]+\/[^/\s]+$/,UM=5*6e4,HM=6e4,WM=10*6e4,Db=fetch,of=new Map,Eo=null;Bb=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),$s=(e,t)=>Object.assign(new Error(e),{status:t});qM=()=>DM(new URL("../bin/bostrat-git-credential",import.meta.url)),KM=(e=process.env)=>`http://127.0.0.1:${Number(e.PORT)||3362}`});function Fb(e=process.env){return!!(Oe(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Hb(e,t,n,r=Lb){let o=Oe(n),s=new AbortController,a=setTimeout(()=>s.abort(),r);try{return await VM(`${o}${e}`,{...t,signal:s.signal})}finally{clearTimeout(a)}}async function Wb(e,{env:t=process.env,force:n=!1,timeoutMs:r=Lb}={}){if(!Fb(t))return{facts:[],source:"unconfigured"};let o=cf.get(e);if(!n&&o&&Date.now()-o.at<zM)return{facts:o.facts,source:"cache"};try{let s=await Hb(`/v1/memory/${encodeURIComponent(e)}`,{headers:Ub(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 cf.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 Al(e,t,{env:n=process.env}={}){if(!Fb(n))return{pushed:0,source:"unconfigured"};if(!t?.length)return{pushed:0,source:"empty"};try{let r=await Hb(`/v1/memory/${encodeURIComponent(e)}`,{method:"POST",headers:{...Ub(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 cf.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 zM,Lb,cf,VM,Ub,qb=G(()=>{ft();zM=6e4,Lb=5e3,cf=new Map,VM=(...e)=>fetch(...e);Ub=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});import lf from"node:fs/promises";import Rs from"node:path";import JM from"node:os";import{EventEmitter as YM}from"node:events";import{randomUUID as XM}from"node:crypto";function Os(e){return e?.cwd?Rs.join(e.cwd,".bostrat","events"):Rs.join(uf,"events")}async function tC(e,t){if(!Tl.has(t)){let o=(await K(e,t)).reduce((s,a)=>a.seq>s?a.seq:s,0);Tl.set(t,o)}let n=Tl.get(t)+1;return Tl.set(t,n),n}function df(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 M(e,t){let n=typeof e=="string"?e:e?.id;if(!n)throw new Error("appendEvent: a track (or trackId) is required");if(!t||!ZM.has(t.type))throw new Error(`appendEvent: unknown event type "${t?.type}"`);if(t.actor&&!QM.has(t.actor))throw new Error(`appendEvent: bad actor "${t.actor}"`);if(t.source&&!eC.has(t.source))throw new Error(`appendEvent: bad source "${t.source}"`);let r=typeof e=="string"?Rs.join(uf,"events"):Os(e),o=t.epoch;if(o==null&&typeof e=="object"&&t.boxId&&Array.isArray(e?.boxes)){let u=e.boxes.find(d=>d.name===t.boxId);o=df(u,Number(t.payload?.ts??t.ts)||Date.now())}let s=await tC(r,n),a=t.userId??process.env.BOSTRAT_OWNER??null,i={id:t.id||XM(),trackId:n,boxId:t.boxId??null,...o!=null?{epoch:o}:{},...a?{userId:a}:{},seq:s,ts:t.ts??Date.now(),type:t.type,actor:t.actor??"system",provider:t.provider??null,source:t.source??"orchestrator",payload:t.payload??{},...t.causationId?{causationId:t.causationId}:{},...t.correlationId?{correlationId:t.correlationId}:{}},c=JSON.stringify(i),l=i;return Gb(c)&&(c=zb(c),l=JSON.parse(c)),await lf.mkdir(r,{recursive:!0}),await lf.appendFile(Kb(r,n),c+`
15
+ `),Je.emit("event",l),Je.emit(`track:${n}`,l),l}async function K(e,t){let n,r;typeof e=="string"&&t?(n=e,r=t):(r=typeof e=="string"?e:e?.id,n=typeof e=="string"?Rs.join(uf,"events"):Os(e));let o;try{o=await lf.readFile(Kb(n,r),"utf8")}catch{return[]}let s=[];for(let a of o.split(`
16
+ `))if(a.trim())try{s.push(JSON.parse(Gb(a)?zb(a):a))}catch{}return s}function Vb(e,t){let n=`track:${e}`;return Je.on(n,t),()=>Je.off(n,t)}var ZM,QM,eC,Je,uf,Kb,Tl,nC,Gb,zb,fe=G(()=>{ZM=new Set(["session.ready","turn.user","turn.agent","turn.retracted","peer.message","provider.error","delivery.queued","delivery.settled","turn.interrupted","tool.called","tool.result","prompt.raised","prompt.answered","prompt.dismissed","prompt.autoRejected","box.fullscreen.detected","box.fullscreen.answered","context.usage","cost.recorded","memory.seed","memory.harvested","handoff.artifact","code.pushed","code.committed","code.rework","rework.cause.offered","rework.cause.answered","rework.cause.retracted","handoff.started","handoff.step","handoff.done","handoff.failed","subtask.delegated","subtask.merged","job.started","job.stalled","pr.state.changed","pr.offered","pr.offer.answered","pr.exists.offered","pr.exists.answered","box.state.changed","view.state.changed","view.spinup.failed","mock.state.changed","flow.state.changed","runbook.state.changed","ticket.linked","ticket.sync.failed","ticket.move.offered","ticket.move.answered","ticket.state.changed","ticket.commented","ticket.flow.changed","ticket.create.offered","ticket.create.answered","ticket.created","loop.create.offered","loop.create.answered","loop.created","loop.update.offered","loop.update.answered","loop.updated","loop.delete.offered","loop.delete.answered","loop.deleted","loop.paused","followup.armed","followup.armed.cancelled","followup.offered","followup.answered","followup.create.offered","followup.create.answered","followup.created","planning.change.offered","planning.change.answered","planning.changed","notify.raised","usage.cap.hit","usage.cap.warning","provider.connected","track.summary.recorded","track.transferred","track.recovered","track.phase.changed","track.operation.changed","track.obligations.changed","track.circuit.tagged","blueprint.item.bound","decision.recorded","changelog.published","stall.detected","error"]),QM=new Set(["user","agent","orchestrator","system","peer"]),eC=new Set(["hook","otel","statusline","transcript","pane","orchestrator","vendor","cli"]),Je=new YM;Je.setMaxListeners(0);uf=process.env.BOSTRAT_STATE_DIR||Rs.join(process.env.HOME||JM.tmpdir(),".bostrat");Kb=(e,t)=>Rs.join(e,`${t}.ndjson`),Tl=new Map;nC=/(?<!\\)((?:\\\\)*)\\u0000/g,Gb=e=>e.includes("\\u0000"),zb=e=>e.replace(nC,"$1\\ufffd")});import se from"node:fs/promises";import rC from"node:os";import ke from"node:path";import{execFile as oC}from"node:child_process";import{promisify as sC}from"node:util";function _l(){return ke.join(Il,"memory","repos")}function _o(e){return e===Qn?ke.join(Il,"memory",Qn):ke.join(_l(),e)}async function ri(e){try{return JSON.parse(await se.readFile(ke.join(e,tk),"utf8"))}catch{return{}}}async function ff(e,t){let n=await ri(e);for(let[r,o]of t)n[r]=Math.max(Number(n[r])||0,o);await se.mkdir(e,{recursive:!0}),await se.writeFile(ke.join(e,tk),JSON.stringify(n))}function Yb(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 Xb(e){try{let{stdout:t}=await aC("git",["-C",e,"config","--get","remote.origin.url"]);return t.trim()||null}catch{return null}}async function mf(e){if(!e)return[];let t=Yb(await Xb(e));if(t)return[t];let n=[],r=[];try{r=await se.readdir(e,{withFileTypes:!0})}catch{return[]}for(let o of r){if(!o.isDirectory()||o.name.startsWith("."))continue;let s=Yb(await Xb(ke.join(e,o.name)));s&&!n.includes(s)&&n.push(s)}return n}function $l(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 Rr(e,t){let n=new RegExp(`^\\s*${t}:\\s*(.+?)\\s*$`,"m").exec(e||"");return n?n[1].replace(/^"|"$/g,""):null}async function Tn(e,t=null){let n=t??await se.readFile(e,"utf8").catch(()=>""),{fm:r}=$l(n),o=Rr(r,"modified"),s=o?Date.parse(o):NaN;if(Number.isFinite(s))return s;try{return(await se.stat(e)).mtimeMs}catch{return 0}}function nk(e,t){let n=Rr(e,"scope"),r=/^repo:([a-z0-9][a-z0-9._-]*)$/i.exec(n||"");if(r)return r[1].toLowerCase();if((n||"").toLowerCase()===Qn){let o=Rr(e,"trust");if(!o||/^operator/i.test(o))return Qn}return t}function hf(e,t,n,r=new Map){let o=(e||"").split(`
17
17
  `),s=new Map;for(let c of(t||"").split(`
18
- `)){let l=xs(c);l&&c.trim().startsWith("-")&&s.set(l,c)}let a=new Set,i=o.map(c=>{let l=xs(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(`
18
+ `)){let l=Cs(c);l&&c.trim().startsWith("-")&&s.set(l,c)}let a=new Set,i=o.map(c=>{let l=Cs(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 Ub(e,t){let n=Ar(t,"name")||e.replace(/\.md$/,""),r=Ar(t,"description")||"";return`- [${n}](${e})${r?` \u2014 ${r}`:""}`}async function Ya(e){let t=[];try{t=await re.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 Hb(e,t){let n=be.join(e,".bostrat","memory"),r=await Ya(n);if(!r.length)return{harvested:0,changedByKey:new Map};let o=Db.get(e)??0,s=Date.now(),a=new Map,i=new Map,c=0,l=new Map;for(let d of r){let p=be.join(n,d);if(o)try{if((await re.stat(p)).mtimeMs<o-GM)continue}catch{continue}let f;try{f=await re.readFile(p,"utf8")}catch{continue}let{fm:w}=Al(f),m=Fb(w,t);if(!m)continue;let g=xo(m),y=be.join(g,d),x=await Sn(p,f);if(l.has(g)||l.set(g,await Ja(g)),(l.get(g)[d]||0)>=x)continue;let b=await Sn(y).catch(()=>0);if(await re.access(y).then(()=>!0).catch(()=>!1)&&b>=x)continue;await re.mkdir(g,{recursive:!0}),await re.writeFile(y,f),c++;let $=a.get(g);$||a.set(g,$={won:new Set,generated:new Map}),$.won.add(d),$.generated.set(d,Ub(d,w)),i.has(m)||i.set(m,new Set),i.get(m).add(d)}let u=await re.readFile(be.join(n,"MEMORY.md"),"utf8").catch(()=>"");for(let[d,p]of a){let f=be.join(d,"MEMORY.md"),w=await re.readFile(f,"utf8").catch(()=>"");await re.writeFile(f,Zp(w,u,p.won,p.generated))}return Db.set(e,s),{harvested:c,changedByKey:i}}async function qb(e){let t=0,n=new Map;for(let r of e||[]){if(!r||!await re.access(be.join(r,".bostrat","memory")).then(()=>!0).catch(()=>!1))continue;let[s]=await Xp(r),a=await Hb(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 zM(){let e=be.join(Tl,"workspaces"),t=[];try{t=await re.readdir(e,{withFileTypes:!0})}catch{return{harvested:0,changedByKey:new Map}}return qb(t.filter(n=>n.isDirectory()).map(n=>be.join(e,n.name)))}async function YM(e,t){let n=xo(e),r=await Ja(n),o=new Set,s=new Map,a=[],i=0;for(let c of t||[]){let l=String(c?.file||"");if(!VM.test(l)||l==="MEMORY.md")continue;let u=be.join(n,l),d=await re.access(u).then(()=>!0).catch(()=>!1),p=d?await Sn(u):0,f=Number(c.modified)||0;if(c.deleted){f>p&&(d&&await re.rm(u,{force:!0}),await Yp(n,[[l,f]]),d&&(a.push(l),i++));continue}d&&p>=f||(r[l]||0)>=f||(await re.mkdir(n,{recursive:!0}),await re.writeFile(u,String(c.content??"")),o.add(l),typeof c.indexLine=="string"&&c.indexLine.trim()&&s.set(l,c.indexLine),i++)}if(o.size||a.length){let c=be.join(n,"MEMORY.md"),l=await re.readFile(c,"utf8").catch(()=>""),u=Zp(l,[...s.values()].join(`
21
+ `)}function rk(e,t){let n=Rr(t,"name")||e.replace(/\.md$/,""),r=Rr(t,"description")||"";return`- [${n}](${e})${r?` \u2014 ${r}`:""}`}async function oi(e){let t=[];try{t=await se.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 ok(e,t){let n=ke.join(e,".bostrat","memory"),r=await oi(n);if(!r.length)return{harvested:0,changedByKey:new Map};let o=Zb.get(e)??0,s=Date.now(),a=new Map,i=new Map,c=0,l=new Map;for(let d of r){let p=ke.join(n,d);if(o)try{if((await se.stat(p)).mtimeMs<o-cC)continue}catch{continue}let f;try{f=await se.readFile(p,"utf8")}catch{continue}let{fm:w}=$l(f),m=nk(w,t);if(!m)continue;let g=_o(m),y=ke.join(g,d),x=await Tn(p,f);if(l.has(g)||l.set(g,await ri(g)),(l.get(g)[d]||0)>=x)continue;let b=await Tn(y).catch(()=>0);if(await se.access(y).then(()=>!0).catch(()=>!1)&&b>=x)continue;await se.mkdir(g,{recursive:!0}),await se.writeFile(y,f),c++;let _=a.get(g);_||a.set(g,_={won:new Set,generated:new Map}),_.won.add(d),_.generated.set(d,rk(d,w)),i.has(m)||i.set(m,new Set),i.get(m).add(d)}let u=await se.readFile(ke.join(n,"MEMORY.md"),"utf8").catch(()=>"");for(let[d,p]of a){let f=ke.join(d,"MEMORY.md"),w=await se.readFile(f,"utf8").catch(()=>"");await se.writeFile(f,hf(w,u,p.won,p.generated))}return Zb.set(e,s),{harvested:c,changedByKey:i}}async function sk(e){let t=0,n=new Map;for(let r of e||[]){if(!r||!await se.access(ke.join(r,".bostrat","memory")).then(()=>!0).catch(()=>!1))continue;let[s]=await mf(r),a=await ok(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 lC(){let e=ke.join(Il,"workspaces"),t=[];try{t=await se.readdir(e,{withFileTypes:!0})}catch{return{harvested:0,changedByKey:new Map}}return sk(t.filter(n=>n.isDirectory()).map(n=>ke.join(e,n.name)))}async function pC(e,t){let n=_o(e),r=await ri(n),o=new Set,s=new Map,a=[],i=0;for(let c of t||[]){let l=String(c?.file||"");if(!uC.test(l)||l==="MEMORY.md")continue;let u=ke.join(n,l),d=await se.access(u).then(()=>!0).catch(()=>!1),p=d?await Tn(u):0,f=Number(c.modified)||0;if(c.deleted){f>p&&(d&&await se.rm(u,{force:!0}),await ff(n,[[l,f]]),d&&(a.push(l),i++));continue}d&&p>=f||(r[l]||0)>=f||(await se.mkdir(n,{recursive:!0}),await se.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=ke.join(n,"MEMORY.md"),l=await se.readFile(c,"utf8").catch(()=>""),u=hf(l,[...s.values()].join(`
22
22
  `),o);if(a.length){let d=new Set(a);u=u.split(`
23
- `).filter(p=>!d.has(xs(p))).join(`
24
- `)}await re.mkdir(n,{recursive:!0}),await re.writeFile(c,u)}return{changed:i,tombstoned:a.length}}async function El(e,t=null){let n=xo(e),r=t?.length?t:await Ya(n);if(!r.length)return{pushed:0,source:"empty"};let o=JM(await re.readFile(be.join(n,"MEMORY.md"),"utf8").catch(()=>"")),s=[];for(let a of r){let i=be.join(n,a),c;try{c=await re.readFile(i,"utf8")}catch{continue}s.push({file:a,content:c,modified:await Sn(i,c),indexLine:o.get(a)??null})}return kl(e,s)}async function XM(e,{timeoutMs:t}={}){let{facts:n,source:r}=await _b(e,t?{timeoutMs:t}:{});n.length?await YM(e,n):r==="plane"&&await El(e)}function ZM(e){let t=e.split(`
25
- `);t.length>Cb&&(t=t.slice(0,Cb));let n=t.join(`
26
- `);for(;Buffer.byteLength(n,"utf8")>KM&&t.length;)t.pop(),n=t.join(`
27
- `);return n}async function eC(e,t){if(!e||!t?.length)return{materialized:!1,reason:"no-repo-key"};let n=be.join(e,".bostrat","memory"),r=0,o=0,s=[];for(let u of t){let d=xo(u),p=await Ja(d);for(let[g,y]of Object.entries(p)){let x=be.join(n,g);await re.access(x).then(()=>!0).catch(()=>!1)&&await Sn(x)<=y&&(await re.rm(x,{force:!0}),o++)}let f=await Ya(d);if(!f.length)continue;await re.mkdir(n,{recursive:!0});for(let g of f){let y=be.join(d,g),x=be.join(n,g),b=await Sn(y),O=await Sn(x).catch(()=>0);await re.access(x).then(()=>!0).catch(()=>!1)&&O>=b||(await re.copyFile(y,x),r++)}let w=await re.readFile(be.join(d,"MEMORY.md"),"utf8").catch(()=>""),m=u===Yn?"## operator memory":`## repo: ${u}`;w.trim()&&s.push(t.length>1?`${m}
23
+ `).filter(p=>!d.has(Cs(p))).join(`
24
+ `)}await se.mkdir(n,{recursive:!0}),await se.writeFile(c,u)}return{changed:i,tombstoned:a.length}}async function Rl(e,t=null){let n=_o(e),r=t?.length?t:await oi(n);if(!r.length)return{pushed:0,source:"empty"};let o=dC(await se.readFile(ke.join(n,"MEMORY.md"),"utf8").catch(()=>"")),s=[];for(let a of r){let i=ke.join(n,a),c;try{c=await se.readFile(i,"utf8")}catch{continue}s.push({file:a,content:c,modified:await Tn(i,c),indexLine:o.get(a)??null})}return Al(e,s)}async function fC(e,{timeoutMs:t}={}){let{facts:n,source:r}=await Wb(e,t?{timeoutMs:t}:{});n.length?await pC(e,n):r==="plane"&&await Rl(e)}function mC(e){let t=e.split(`
25
+ `);t.length>Jb&&(t=t.slice(0,Jb));let n=t.join(`
26
+ `);for(;Buffer.byteLength(n,"utf8")>iC&&t.length;)t.pop(),n=t.join(`
27
+ `);return n}async function wC(e,t){if(!e||!t?.length)return{materialized:!1,reason:"no-repo-key"};let n=ke.join(e,".bostrat","memory"),r=0,o=0,s=[];for(let u of t){let d=_o(u),p=await ri(d);for(let[g,y]of Object.entries(p)){let x=ke.join(n,g);await se.access(x).then(()=>!0).catch(()=>!1)&&await Tn(x)<=y&&(await se.rm(x,{force:!0}),o++)}let f=await oi(d);if(!f.length)continue;await se.mkdir(n,{recursive:!0});for(let g of f){let y=ke.join(d,g),x=ke.join(n,g),b=await Tn(y),R=await Tn(x).catch(()=>0);await se.access(x).then(()=>!0).catch(()=>!1)&&R>=b||(await se.copyFile(y,x),r++)}let w=await se.readFile(ke.join(d,"MEMORY.md"),"utf8").catch(()=>""),m=u===Qn?"## operator memory":`## repo: ${u}`;w.trim()&&s.push(t.length>1?`${m}
28
28
 
29
29
  ${w.trim()}`:w.trim())}if(!s.length)return o?{materialized:!1,reason:"empty-store",cleaned:o}:{materialized:!1,reason:"empty-store"};let i="_Shared Track memory (point-in-time facts). Verify file/line citations against the current code before acting on them; correct a wrong fact in place (bump `modified`, use `supersedes`) rather than working around it._\n\n"+s.join(`
30
30
 
31
31
  `)+`
32
- `,c=ZM(i);await re.mkdir(n,{recursive:!0}),await re.writeFile(be.join(n,"MEMORY.md"),c);let l=be.join(n,"claude");return await re.mkdir(l,{recursive:!0}),await re.writeFile(be.join(l,"MEMORY.md"),QM,{flag:"wx"}).catch(()=>{}),{materialized:!0,facts:r,capped:c!==i}}async function Wb(e){try{let t=await Xp(e);if(!t.length)return{materialized:!1,reason:"no-repo-key"};let n=[...t,Yn];return await Promise.all(n.map(r=>XM(r,{timeoutMs:tC}))),await eC(e,n)}catch(t){return{materialized:!1,reason:"error",error:t?.message||String(t)}}}function Kb(){return{...rt,pending:ks.size,queued:Jp.size}}function Gb(e){if(vl.has(e))return vl.get(e);Jp.add(e);let t=Bb.then(async()=>{Jp.delete(e),vl.delete(e);let n=await ef(e);return rt.runs++,rt.lastRunAt=Date.now(),n.error?(rt.errors++,rt.lastError=n.error):rt.harvested+=n.harvested||0,n}).catch(n=>({harvested:0,error:n?.message||String(n)}));return vl.set(e,t),Bb=t.then(()=>{}),t}function _l(e,{delayMs:t=nC}={}){if(!e||typeof e!="string")return;rt.scheduled++;let n=ks.get(e);n&&clearTimeout(n);let r=setTimeout(()=>{ks.delete(e),Gb(e)},t);r.unref?.(),ks.set(e,r)}async function Qp(e,{timeoutMs:t=3e3}={}){if(!e)return{harvested:0,skipped:"no-cwd"};if(!await re.access(be.join(e,".bostrat","memory")).then(()=>!0,()=>!1))return{harvested:0,skipped:"no-memory-dir"};let r=ks.get(e);r&&(clearTimeout(r),ks.delete(e));let o,s=new Promise(a=>{o=setTimeout(()=>a({harvested:0,timedOut:!0}),t),o.unref?.()});try{return await Promise.race([Gb(e),s])}finally{clearTimeout(o)}}async function zb(e){return Va||(Va=(async()=>{try{jb||(jb=!0,await oC());let{harvested:t,changedByKey:n}=await qb(e);for(let[r,o]of n)await El(r,[...o]);return rt.reconciles++,rt.lastReconcileAt=Date.now(),rt.harvested+=t,{harvested:t,keys:[...n.keys()]}}catch(t){return rt.errors++,rt.lastError=t?.message||String(t),{harvested:0,error:rt.lastError}}finally{Va=null}})(),Va)}function rC(){return be.join(Tl,"memory",".full-sweep-done")}async function Vb(){let e=rC();try{let t=JSON.parse(await re.readFile(e,"utf8"));return rt.backfill={at:Number(t?.at)||0,harvested:Number(t?.harvested)||0,prior:!0},{ran:!1,...rt.backfill}}catch{}try{let{harvested:t,changedByKey:n}=await zM();for(let[o,s]of n)await El(o,[...s]);let r={at:Date.now(),harvested:t};return await re.mkdir(be.dirname(e),{recursive:!0}),await re.writeFile(e,JSON.stringify(r)),rt.backfill=r,{ran:!0,...r}}catch(t){return rt.errors++,rt.lastError=t?.message||String(t),{ran:!1,error:rt.lastError}}}async function oC(){let e=0,t=[];try{t=await re.readdir(Sl(),{withFileTypes:!0})}catch{return{moved:e}}for(let n of t){if(!n.isDirectory())continue;let r=be.join(Sl(),n.name),o=xo(Yn),s=new Set,a=new Map;for(let f of await Ya(r)){let w=be.join(r,f),m;try{m=await re.readFile(w,"utf8")}catch{continue}let{fm:g}=Al(m);if(Fb(g,n.name)!==Yn)continue;let y=be.join(o,f),x=await Sn(y).catch(()=>0),b=await Sn(w,m);await re.mkdir(o,{recursive:!0}),b>x&&await re.writeFile(y,m),await re.rm(w,{force:!0}),s.add(f),a.set(f,Ub(f,g)),e++}if(!s.size)continue;let i=Date.now();await Yp(r,[...s].map(f=>[f,i])),await kl(n.name,[...s].map(f=>({file:f,deleted:!0,modified:i})));let c=be.join(r,"MEMORY.md"),l=await re.readFile(c,"utf8").catch(()=>""),u=l.split(`
33
- `).filter(f=>!s.has(xs(f))).join(`
34
- `);await re.writeFile(c,u).catch(()=>{});let d=be.join(o,"MEMORY.md"),p=await re.readFile(d,"utf8").catch(()=>"");await re.writeFile(d,Zp(p,l,s,a))}return{moved:e}}async function Jb(){let e=[],t=[Yn];try{for(let n of await re.readdir(Sl(),{withFileTypes:!0}))n.isDirectory()&&t.push(n.name)}catch{}for(let n of t){let r=xo(n),o=await Ya(r),s=await Ja(r);if(!o.length&&!Object.keys(s).length)continue;let a=[];for(let i of o){let c=await re.readFile(be.join(r,i),"utf8").catch(()=>""),{fm:l}=Al(c);a.push({file:i,name:Ar(l,"name")||i.replace(/\.md$/,""),description:Ar(l,"description")||"",scope:Ar(l,"scope")||null,modified:await Sn(be.join(r,i),c)})}e.push({key:n,facts:a,tombstones:Object.keys(s).length})}return e}async function Yb(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=xo(e),r=be.join(n,t);if(!await re.access(r).then(()=>!0).catch(()=>!1))throw new Error(`fact ${t} not found in ${e}`);let s=Date.now();await re.rm(r,{force:!0}),await Yp(n,[[t,s]]);let a=be.join(n,"MEMORY.md"),i=await re.readFile(a,"utf8").catch(()=>"");await re.writeFile(a,i.split(`
35
- `).filter(l=>xs(l)!==t).join(`
36
- `)).catch(()=>{});let c=await kl(e,[{file:t,deleted:!0,modified:s}]);return{deleted:t,key:e,plane:c.source}}async function ef(e){try{let t=await Xp(e),{harvested:n,changedByKey:r}=await Hb(e,t[0]||null);for(let[o,s]of r)await El(o,[...s]);return n>0&&await aC(e,r).catch(()=>{}),{harvested:n}}catch(t){return{harvested:0,error:t?.message||String(t)}}}async function aC(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,sC)}}await M({id:n,cwd:e},{type:"memory.harvested",actor:"orchestrator",payload:{harvested:o,keys:r,ts:Date.now()}})}var WM,Tl,Cb,KM,Yn,Lb,xs,Db,GM,VM,JM,QM,tC,nC,ks,Jp,Bb,rt,vl,jb,Va,sC,Xa=G(()=>{Ib();de();WM=qM(HM),Tl=process.env.BOSTRAT_STATE_DIR||be.join(process.env.HOME||UM.tmpdir(),".bostrat"),Cb=200,KM=25*1024;Yn="operator";Lb=".tombstones.json";xs=e=>/\]\(([^)]+\.md)\)/.exec(e)?.[1]||null;Db=new Map,GM=2e3;VM=/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/,JM=e=>{let t=new Map;for(let n of(e||"").split(`
37
- `)){let r=xs(n);r&&n.trim().startsWith("-")&&t.set(r,n)}return t};QM=`# Track memory
32
+ `,c=mC(i);await se.mkdir(n,{recursive:!0}),await se.writeFile(ke.join(n,"MEMORY.md"),c);let l=ke.join(n,"claude");return await se.mkdir(l,{recursive:!0}),await se.writeFile(ke.join(l,"MEMORY.md"),hC,{flag:"wx"}).catch(()=>{}),{materialized:!0,facts:r,capped:c!==i}}async function ak(e){try{let t=await mf(e);if(!t.length)return{materialized:!1,reason:"no-repo-key"};let n=[...t,Qn];return await Promise.all(n.map(r=>fC(r,{timeoutMs:gC}))),await wC(e,n)}catch(t){return{materialized:!1,reason:"error",error:t?.message||String(t)}}}function ik(){return{...rt,pending:Ms.size,queued:pf.size}}function ck(e){if(El.has(e))return El.get(e);pf.add(e);let t=Qb.then(async()=>{pf.delete(e),El.delete(e);let n=await wf(e);return rt.runs++,rt.lastRunAt=Date.now(),n.error?(rt.errors++,rt.lastError=n.error):rt.harvested+=n.harvested||0,n}).catch(n=>({harvested:0,error:n?.message||String(n)}));return El.set(e,t),Qb=t.then(()=>{}),t}function Ol(e,{delayMs:t=yC}={}){if(!e||typeof e!="string")return;rt.scheduled++;let n=Ms.get(e);n&&clearTimeout(n);let r=setTimeout(()=>{Ms.delete(e),ck(e)},t);r.unref?.(),Ms.set(e,r)}async function Ml(e,{timeoutMs:t=3e3}={}){if(!e)return{harvested:0,skipped:"no-cwd"};if(!await se.access(ke.join(e,".bostrat","memory")).then(()=>!0,()=>!1))return{harvested:0,skipped:"no-memory-dir"};let r=Ms.get(e);r&&(clearTimeout(r),Ms.delete(e));let o,s=new Promise(a=>{o=setTimeout(()=>a({harvested:0,timedOut:!0}),t),o.unref?.()});try{return await Promise.race([ck(e),s])}finally{clearTimeout(o)}}async function lk(e){return ni||(ni=(async()=>{try{ek||(ek=!0,await kC());let{harvested:t,changedByKey:n}=await sk(e);for(let[r,o]of n)await Rl(r,[...o]);return rt.reconciles++,rt.lastReconcileAt=Date.now(),rt.harvested+=t,{harvested:t,keys:[...n.keys()]}}catch(t){return rt.errors++,rt.lastError=t?.message||String(t),{harvested:0,error:rt.lastError}}finally{ni=null}})(),ni)}function bC(){return ke.join(Il,"memory",".full-sweep-done")}async function uk(){let e=bC();try{let t=JSON.parse(await se.readFile(e,"utf8"));return rt.backfill={at:Number(t?.at)||0,harvested:Number(t?.harvested)||0,prior:!0},{ran:!1,...rt.backfill}}catch{}try{let{harvested:t,changedByKey:n}=await lC();for(let[o,s]of n)await Rl(o,[...s]);let r={at:Date.now(),harvested:t};return await se.mkdir(ke.dirname(e),{recursive:!0}),await se.writeFile(e,JSON.stringify(r)),rt.backfill=r,{ran:!0,...r}}catch(t){return rt.errors++,rt.lastError=t?.message||String(t),{ran:!1,error:rt.lastError}}}async function kC(){let e=0,t=[];try{t=await se.readdir(_l(),{withFileTypes:!0})}catch{return{moved:e}}for(let n of t){if(!n.isDirectory())continue;let r=ke.join(_l(),n.name),o=_o(Qn),s=new Set,a=new Map;for(let f of await oi(r)){let w=ke.join(r,f),m;try{m=await se.readFile(w,"utf8")}catch{continue}let{fm:g}=$l(m);if(nk(g,n.name)!==Qn)continue;let y=ke.join(o,f),x=await Tn(y).catch(()=>0),b=await Tn(w,m);await se.mkdir(o,{recursive:!0}),b>x&&await se.writeFile(y,m),await se.rm(w,{force:!0}),s.add(f),a.set(f,rk(f,g)),e++}if(!s.size)continue;let i=Date.now();await ff(r,[...s].map(f=>[f,i])),await Al(n.name,[...s].map(f=>({file:f,deleted:!0,modified:i})));let c=ke.join(r,"MEMORY.md"),l=await se.readFile(c,"utf8").catch(()=>""),u=l.split(`
33
+ `).filter(f=>!s.has(Cs(f))).join(`
34
+ `);await se.writeFile(c,u).catch(()=>{});let d=ke.join(o,"MEMORY.md"),p=await se.readFile(d,"utf8").catch(()=>"");await se.writeFile(d,hf(p,l,s,a))}return{moved:e}}async function dk(){let e=[],t=[Qn];try{for(let n of await se.readdir(_l(),{withFileTypes:!0}))n.isDirectory()&&t.push(n.name)}catch{}for(let n of t){let r=_o(n),o=await oi(r),s=await ri(r);if(!o.length&&!Object.keys(s).length)continue;let a=[];for(let i of o){let c=await se.readFile(ke.join(r,i),"utf8").catch(()=>""),{fm:l}=$l(c);a.push({file:i,name:Rr(l,"name")||i.replace(/\.md$/,""),description:Rr(l,"description")||"",scope:Rr(l,"scope")||null,modified:await Tn(ke.join(r,i),c)})}e.push({key:n,facts:a,tombstones:Object.keys(s).length})}return e}async function pk(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=_o(e),r=ke.join(n,t);if(!await se.access(r).then(()=>!0).catch(()=>!1))throw new Error(`fact ${t} not found in ${e}`);let s=Date.now();await se.rm(r,{force:!0}),await ff(n,[[t,s]]);let a=ke.join(n,"MEMORY.md"),i=await se.readFile(a,"utf8").catch(()=>"");await se.writeFile(a,i.split(`
35
+ `).filter(l=>Cs(l)!==t).join(`
36
+ `)).catch(()=>{});let c=await Al(e,[{file:t,deleted:!0,modified:s}]);return{deleted:t,key:e,plane:c.source}}async function wf(e){try{let t=await mf(e),{harvested:n,changedByKey:r}=await ok(e,t[0]||null);for(let[o,s]of r)await Rl(o,[...s]);return n>0&&await vC(e,r).catch(()=>{}),{harvested:n}}catch(t){return{harvested:0,error:t?.message||String(t)}}}async function vC(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,xC)}}await M({id:n,cwd:e},{type:"memory.harvested",actor:"orchestrator",payload:{harvested:o,keys:r,ts:Date.now()}})}var aC,Il,Jb,iC,Qn,tk,Cs,Zb,cC,uC,dC,hC,gC,yC,Ms,pf,Qb,rt,El,ek,ni,xC,si=G(()=>{qb();fe();aC=sC(oC),Il=process.env.BOSTRAT_STATE_DIR||ke.join(process.env.HOME||rC.tmpdir(),".bostrat"),Jb=200,iC=25*1024;Qn="operator";tk=".tombstones.json";Cs=e=>/\]\(([^)]+\.md)\)/.exec(e)?.[1]||null;Zb=new Map,cC=2e3;uC=/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/,dC=e=>{let t=new Map;for(let n of(e||"").split(`
37
+ `)){let r=Cs(n);r&&n.trim().startsWith("-")&&t.set(r,n)}return t};hC=`# 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
- `;tC=Number(process.env.BOSTRAT_MEMORY_SPAWN_PULL_MS)||1500;nC=Number(process.env.BOSTRAT_MEMORY_HARVEST_DEBOUNCE_MS)||2e3,ks=new Map,Jp=new Set,Bb=Promise.resolve(),rt={scheduled:0,runs:0,harvested:0,errors:0,lastRunAt:null,lastError:null,reconciles:0,lastReconcileAt:null,backfill:null};vl=new Map;jb=!1,Va=null;sC=20});import Il from"node:fs/promises";import iC from"node:path";async function Et(e,t,{mode:n}={}){await Il.mkdir(iC.dirname(e),{recursive:!0});let r=`${e}.${process.pid}.${++cC}.tmp`;try{await Il.writeFile(r,JSON.stringify(t,null,2)+`
43
- `,n!=null?{mode:n}:void 0),await Il.rename(r,e)}catch(o){throw await Il.unlink(r).catch(()=>{}),o}}var cC,Er=G(()=>{cC=0});import tk from"node:fs/promises";import nk from"node:os";import rk from"node:path";function He(e=process.env){return!!(Re(e)&&e.BOSTRAT_PLANE_TOKEN)}async function ei(e,t={},n=process.env){let r=new AbortController,o=setTimeout(()=>r.abort(),lC);try{return await hC(`${Re(n)}${e}`,{...t,signal:r.signal})}finally{clearTimeout(o)}}async function sk(){return Rl||(tf||=tk.readFile(ok(),"utf8").then(e=>JSON.parse(e)).catch(()=>({ops:[]})).then(e=>Rl={ops:Array.isArray(e?.ops)?e.ops:[],parked:Array.isArray(e?.parked)?e.parked:[]}).finally(()=>tf=null),tf)}async function Ol(){await Et(ok(),Rl).catch(()=>{})}function Qb(e){return e.op==="blob"?`blob ${e.family} ${e.id} ${e.v} ${e.kind}`:`${e.op} ${e.family} ${e.id}`}async function rf(e){let t=await sk(),n=Qb(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=>Qb(o)===n);r>=0?t.ops[r]=e:t.ops.push(e)}t.ops.length>Xb&&(t.ops=t.ops.slice(-Xb)),await Ol()}function ek(){$l||($l=setTimeout(()=>{$l=null,vs().catch(()=>{})},wC),$l.unref?.())}function nf(e){let t=new Error(`plane ${e}`);return t.refused=!0,t}async function yC(e,t=process.env){if(e.op==="record"){let n=await ei(`/v1/content/${encodeURIComponent(e.family)}`,{method:"POST",headers:{...Qa(t),"content-type":"application/json"},body:JSON.stringify({records:[{id:e.id,trackId:e.trackId??null,data:e.data,updatedAt:e.updatedAt,originNode:mC()}]})},t);if(!n.ok)throw nf(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 tk.readFile(e.path).catch(()=>null);if(!n)return{delivered:!0,dropped:"source file gone"};let r=await ei(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}/blob?v=${e.v}&kind=${encodeURIComponent(e.kind)}`,{method:"POST",headers:{...Qa(t),"content-type":"application/octet-stream"},body:n},t);if(!r.ok&&r.status!==400)throw nf(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 ei(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}?deletedAt=${e.deletedAt}`,{method:"DELETE",headers:Qa(t)},t);if(!n.ok)throw nf(n.status);return{delivered:!0}}return{delivered:!0,dropped:"unknown op"}}async function vs({env:e=process.env,log:t=console,now:n=Date.now()}={}){return He(e)?Za||(Za=(async()=>{let r=await sk();bC(r,n);let o=0,s=0;for(;r.ops.length;){let a=r.ops[0],i;try{i=await yC(a,e)}catch(c){if(!c?.refused)return ek(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};if(a.refusals=(a.refusals||0)+1,a.refusals<dC)return ek(),await Ol(),{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>Zb&&(r.parked=r.parked.slice(-Zb)),s++,await Ol();continue}i.rejected&&t.error?.(`[content-plane] ALARM plane rejected ${a.op} ${a.family}/${a.id}: ${i.rejected}`),r.ops.shift(),o++,await Ol()}return{flushed:o,parked:s,pending:0}})().finally(()=>{Za=null}),Za):{flushed:0,source:"unconfigured"}}function bC(e,t){if(!e.parked.length||e.ops.length)return;let n=e.parked.filter(r=>t-(r.parkedAt||0)>=gC);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 bt(e,t,{trackId:n=null,env:r=process.env}={}){return He(r)?(await rf({op:"record",family:e,id:t.id,trackId:n??t.trackId??null,data:t,updatedAt:Number(t.updatedAt)||Date.now()}),vs({env:r})):{queued:!1,source:"unconfigured"}}async function _r(e,t,n,r,o,{env:s=process.env}={}){return He(s)?(await rf({op:"blob",family:e,id:t,v:Number(n),kind:r,path:o}),vs({env:s})):{queued:!1,source:"unconfigured"}}async function tn(e,t,{deletedAt:n=Date.now(),env:r=process.env}={}){return He(r)?(await rf({op:"delete",family:e,id:t,deletedAt:n}),vs({env:r})):{queued:!1,source:"unconfigured"}}async function st(e,{env:t=process.env}={}){if(!He(t))return{records:[],source:"unconfigured"};try{let n=await ei(`/v1/content/${encodeURIComponent(e)}?tombstones=1`,{headers:Qa(t)},t);if(!n.ok)throw new Error(`plane ${n.status}`);let r=await n.json();return{records:Array.isArray(r?.records)?r.records:[],source:"plane"}}catch(n){return{records:[],source:"unreachable",error:n?.message}}}async function ti(e,t,n,r,{env:o=process.env}={}){if(!He(o))return null;try{let s=await ei(`/v1/content/${encodeURIComponent(e)}/${encodeURIComponent(t)}/blob?v=${Number(n)}&kind=${encodeURIComponent(r)}`,{headers:Qa(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 lC,uC,Xb,dC,Zb,pC,fC,ok,mC,hC,wC,gC,Qa,Rl,tf,$l,Za,Ir=G(()=>{pt();Er();lC=1e4,uC=3e4,Xb=2e3,dC=5,Zb=100,pC=60*6e4,fC=()=>process.env.BOSTRAT_STATE_DIR||rk.join(process.env.HOME||nk.tmpdir(),".bostrat"),ok=()=>rk.join(fC(),"content-outbox.json"),mC=()=>process.env.BOSTRAT_NODE_ID||nk.hostname(),hC=(...e)=>fetch(...e),wC=uC,gC=pC;Qa=(e=process.env)=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`});Rl=null,tf=null,$l=null,Za=null});import of from"node:fs/promises";import ak from"node:path";async function ik(e,t,{box:n=null,agent:r=null}={}){if(!e||!He())return{pushed:!1};try{let o=Date.now();return await bt("checkpoints",{id:e,trackId:e,v:o,box:n,agent:r,updatedAt:o},{trackId:e}),await _r("checkpoints",e,o,"md",t),ni=null,{pushed:!0,v:o}}catch{return{pushed:!1}}}async function TC(){if(ni&&Date.now()-ni.at<SC)return{records:ni.records,source:"plane"};let e=await st("checkpoints");return e.source==="plane"&&(ni={at:Date.now(),records:e.records}),e}async function Ml(e){try{let t=vC(e);if(!t||!He())return{restored:!1};let n=ak.join(e,kC,xC);if(await of.stat(n).then(()=>!0,()=>!1))return{restored:!1};let{records:r,source:o}=await TC();if(o!=="plane")return{restored:!1};let s=r.find(i=>!i.deletedAt&&i.data?.id===t);if(!s?.data?.v)return{restored:!1};let a=await ti("checkpoints",t,s.data.v,"md");return typeof a!="string"||!a?{restored:!1}:(await of.mkdir(ak.dirname(n),{recursive:!0}),await of.writeFile(n,a),{restored:!0,v:s.data.v})}catch{return{restored:!1}}}var kC,xC,vC,SC,ni,Cl=G(()=>{Ir();kC=".bostrat/handoff",xC="latest.md",vC=e=>/workspaces[/\\]([0-9a-f]{8})$/.exec(e||"")?.[1]??null;SC=6e4,ni=null});import ri from"node:fs/promises";import AC from"node:os";import lk from"node:path";function vo(e){let t=String(e??"");for(let n of EC)t=t.replace(n,"\u2039redacted\u203A");return t}function Nl(){let e=process.env.BOSTRAT_HANDOFF_DEBUG;return e==="1"||e==="true"}async function _C(e){try{await ri.mkdir(sf,{recursive:!0}),await ri.appendFile(Ss,`${JSON.stringify(e)}
44
- `,"utf8");let n=(await ri.readFile(Ss,"utf8")).split(`
45
- `).filter(Boolean);n.length>ck&&await ri.writeFile(Ss,`${n.slice(-ck).join(`
42
+ `;gC=Number(process.env.BOSTRAT_MEMORY_SPAWN_PULL_MS)||1500;yC=Number(process.env.BOSTRAT_MEMORY_HARVEST_DEBOUNCE_MS)||2e3,Ms=new Map,pf=new Set,Qb=Promise.resolve(),rt={scheduled:0,runs:0,harvested:0,errors:0,lastRunAt:null,lastError:null,reconciles:0,lastReconcileAt:null,backfill:null};El=new Map;ek=!1,ni=null;xC=20});import Cl from"node:fs/promises";import SC from"node:path";async function It(e,t,{mode:n}={}){await Cl.mkdir(SC.dirname(e),{recursive:!0});let r=`${e}.${process.pid}.${++AC}.tmp`;try{await Cl.writeFile(r,JSON.stringify(t,null,2)+`
43
+ `,n!=null?{mode:n}:void 0),await Cl.rename(r,e)}catch(o){throw await Cl.unlink(r).catch(()=>{}),o}}var AC,Or=G(()=>{AC=0});import gk from"node:fs/promises";import yk from"node:os";import bk from"node:path";function He(e=process.env){return!!(Oe(e)&&e.BOSTRAT_PLANE_TOKEN)}async function ci(e,t={},n=process.env){let r=new AbortController,o=setTimeout(()=>r.abort(),TC);try{return await OC(`${Oe(n)}${e}`,{...t,signal:r.signal})}finally{clearTimeout(o)}}async function xk(){return Pl||(gf||=gk.readFile(kk(),"utf8").then(e=>JSON.parse(e)).catch(()=>({ops:[]})).then(e=>Pl={ops:Array.isArray(e?.ops)?e.ops:[],parked:Array.isArray(e?.parked)?e.parked:[]}).finally(()=>gf=null),gf)}async function Dl(){await It(kk(),Pl).catch(()=>{})}function hk(e){return e.op==="blob"?`blob ${e.family} ${e.id} ${e.v} ${e.kind}`:`${e.op} ${e.family} ${e.id}`}async function bf(e){let t=await xk(),n=hk(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=>hk(o)===n);r>=0?t.ops[r]=e:t.ops.push(e)}t.ops.length>fk&&(t.ops=t.ops.slice(-fk)),await Dl()}function wk(){Nl||(Nl=setTimeout(()=>{Nl=null,Ns().catch(()=>{})},MC),Nl.unref?.())}function yf(e){let t=new Error(`plane ${e}`);return t.refused=!0,t}async function NC(e,t=process.env){if(e.op==="record"){let n=await ci(`/v1/content/${encodeURIComponent(e.family)}`,{method:"POST",headers:{...ii(t),"content-type":"application/json"},body:JSON.stringify({records:[{id:e.id,trackId:e.trackId??null,data:e.data,updatedAt:e.updatedAt,originNode:RC()}]})},t);if(!n.ok)throw yf(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 gk.readFile(e.path).catch(()=>null);if(!n)return{delivered:!0,dropped:"source file gone"};let r=await ci(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}/blob?v=${e.v}&kind=${encodeURIComponent(e.kind)}`,{method:"POST",headers:{...ii(t),"content-type":"application/octet-stream"},body:n},t);if(!r.ok&&r.status!==400)throw yf(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 ci(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}?deletedAt=${e.deletedAt}`,{method:"DELETE",headers:ii(t)},t);if(!n.ok)throw yf(n.status);return{delivered:!0}}return{delivered:!0,dropped:"unknown op"}}async function Ns({env:e=process.env,log:t=console,now:n=Date.now()}={}){return He(e)?ai||(ai=(async()=>{let r=await xk();PC(r,n);let o=0,s=0;for(;r.ops.length;){let a=r.ops[0],i;try{i=await NC(a,e)}catch(c){if(!c?.refused)return wk(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};if(a.refusals=(a.refusals||0)+1,a.refusals<_C)return wk(),await Dl(),{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>mk&&(r.parked=r.parked.slice(-mk)),s++,await Dl();continue}i.rejected&&t.error?.(`[content-plane] ALARM plane rejected ${a.op} ${a.family}/${a.id}: ${i.rejected}`),r.ops.shift(),o++,await Dl()}return{flushed:o,parked:s,pending:0}})().finally(()=>{ai=null}),ai):{flushed:0,source:"unconfigured"}}function PC(e,t){if(!e.parked.length||e.ops.length)return;let n=e.parked.filter(r=>t-(r.parkedAt||0)>=CC);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 kt(e,t,{trackId:n=null,env:r=process.env}={}){return He(r)?(await bf({op:"record",family:e,id:t.id,trackId:n??t.trackId??null,data:t,updatedAt:Number(t.updatedAt)||Date.now()}),Ns({env:r})):{queued:!1,source:"unconfigured"}}async function Mr(e,t,n,r,o,{env:s=process.env}={}){return He(s)?(await bf({op:"blob",family:e,id:t,v:Number(n),kind:r,path:o}),Ns({env:s})):{queued:!1,source:"unconfigured"}}async function rn(e,t,{deletedAt:n=Date.now(),env:r=process.env}={}){return He(r)?(await bf({op:"delete",family:e,id:t,deletedAt:n}),Ns({env:r})):{queued:!1,source:"unconfigured"}}async function st(e,{env:t=process.env}={}){if(!He(t))return{records:[],source:"unconfigured"};try{let n=await ci(`/v1/content/${encodeURIComponent(e)}?tombstones=1`,{headers:ii(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 li(e,t,n,r,{env:o=process.env}={}){if(!He(o))return null;try{let s=await ci(`/v1/content/${encodeURIComponent(e)}/${encodeURIComponent(t)}/blob?v=${Number(n)}&kind=${encodeURIComponent(r)}`,{headers:ii(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 TC,EC,fk,_C,mk,IC,$C,kk,RC,OC,MC,CC,ii,Pl,gf,Nl,ai,Cr=G(()=>{ft();Or();TC=1e4,EC=3e4,fk=2e3,_C=5,mk=100,IC=60*6e4,$C=()=>process.env.BOSTRAT_STATE_DIR||bk.join(process.env.HOME||yk.tmpdir(),".bostrat"),kk=()=>bk.join($C(),"content-outbox.json"),RC=()=>process.env.BOSTRAT_NODE_ID||yk.hostname(),OC=(...e)=>fetch(...e),MC=EC,CC=IC;ii=(e=process.env)=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`});Pl=null,gf=null,Nl=null,ai=null});import kf from"node:fs/promises";import vk from"node:path";async function Sk(e,t,{box:n=null,agent:r=null}={}){if(!e||!He())return{pushed:!1};try{let o=Date.now();return await kt("checkpoints",{id:e,trackId:e,v:o,box:n,agent:r,updatedAt:o},{trackId:e}),await Mr("checkpoints",e,o,"md",t),ui=null,{pushed:!0,v:o}}catch{return{pushed:!1}}}async function FC(){if(ui&&Date.now()-ui.at<LC)return{records:ui.records,source:"plane"};let e=await st("checkpoints");return e.source==="plane"&&(ui={at:Date.now(),records:e.records}),e}async function Bl(e){try{let t=jC(e);if(!t||!He())return{restored:!1};let n=vk.join(e,DC,BC);if(await kf.stat(n).then(()=>!0,()=>!1))return{restored:!1};let{records:r,source:o}=await FC();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 li("checkpoints",t,s.data.v,"md");return typeof a!="string"||!a?{restored:!1}:(await kf.mkdir(vk.dirname(n),{recursive:!0}),await kf.writeFile(n,a),{restored:!0,v:s.data.v})}catch{return{restored:!1}}}var DC,BC,jC,LC,ui,jl=G(()=>{Cr();DC=".bostrat/handoff",BC="latest.md",jC=e=>/workspaces[/\\]([0-9a-f]{8})$/.exec(e||"")?.[1]??null;LC=6e4,ui=null});import di from"node:fs/promises";import UC from"node:os";import Tk from"node:path";function Io(e){let t=String(e??"");for(let n of HC)t=t.replace(n,"\u2039redacted\u203A");return t}function Ll(){let e=process.env.BOSTRAT_HANDOFF_DEBUG;return e==="1"||e==="true"}async function WC(e){try{await di.mkdir(xf,{recursive:!0}),await di.appendFile(Ps,`${JSON.stringify(e)}
44
+ `,"utf8");let n=(await di.readFile(Ps,"utf8")).split(`
45
+ `).filter(Boolean);n.length>Ak&&await di.writeFile(Ps,`${n.slice(-Ak).join(`
46
46
  `)}
47
- `,"utf8")}catch(t){console.warn(`[handoff-debug] failed to write ${Ss}: ${t?.message||t}`)}}async function ie(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&&Nl())try{t.paneTail=vo((await Be(t.sessionName,{lines:35})).slice(-4e3))}catch{t.paneTail=null}(Nl()||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 _C(t)}async function uk({limit:e=80}={}){try{return(await ri.readFile(Ss,"utf8")).split(`
48
- `).filter(Boolean).slice(-e).map(r=>{try{let o=JSON.parse(r);return typeof o?.paneTail=="string"&&(o.paneTail=vo(o.paneTail)),o}catch{return{raw:vo(r)}}})}catch{return[]}}var EC,sf,Ss,ck,dk,Tn=G(()=>{ct();EC=[/[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];sf=process.env.BOSTRAT_DEBUG_DIR||lk.join(AC.homedir(),".bostrat","debug"),Ss=lk.join(sf,"handoff.jsonl"),ck=Number(process.env.BOSTRAT_HANDOFF_DEBUG_MAX)||500;dk={DEBUG_DIR:sf,LOG_FILE:Ss}});import Pl from"node:fs/promises";import af from"node:path";import IC from"node:os";async function fk(e=pk){await Pl.mkdir(e,{recursive:!0});for(let t of RC){let n=t==="prepare-commit-msg"?OC:t==="post-commit"?MC:`${cf}exit 0
49
- `,r=af.join(e,t),o=null;try{o=await Pl.readFile(r,"utf8")}catch{}o!==n&&await Pl.writeFile(r,n,{mode:493}),await Pl.chmod(r,493).catch(()=>{})}return e}function mk({nodeUrl:e,dir:t=pk,env:n=process.env}={}){return String(n.BOSTRAT_GIT_HOOKS||"").toLowerCase()==="off"?[]:["-e","GIT_CONFIG_COUNT=1","-e","GIT_CONFIG_KEY_0=core.hooksPath","-e",`GIT_CONFIG_VALUE_0=${t}`,"-e",`${oi}=${e}`]}function hk(e=process.env){return e.BOSTRAT_NODE_URL||`http://127.0.0.1:${e.PORT||3362}`}var oi,$C,pk,RC,cf,OC,MC,lf=G(()=>{fs();oi="BOSTRAT_NODE_URL",$C=process.env.BOSTRAT_STATE_DIR||af.join(process.env.HOME||IC.tmpdir(),".bostrat"),pk=af.join($C,"git-hooks"),RC=["applypatch-msg","pre-applypatch","post-applypatch","pre-commit","pre-merge-commit","prepare-commit-msg","commit-msg","post-commit","pre-rebase","post-checkout","post-merge","pre-push","post-rewrite","pre-auto-gc"],cf=`#!/bin/sh
47
+ `,"utf8")}catch(t){console.warn(`[handoff-debug] failed to write ${Ps}: ${t?.message||t}`)}}async function ue(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&&Ll())try{t.paneTail=Io((await Pe(t.sessionName,{lines:35})).slice(-4e3))}catch{t.paneTail=null}(Ll()||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 WC(t)}async function Ek({limit:e=80}={}){try{return(await di.readFile(Ps,"utf8")).split(`
48
+ `).filter(Boolean).slice(-e).map(r=>{try{let o=JSON.parse(r);return typeof o?.paneTail=="string"&&(o.paneTail=Io(o.paneTail)),o}catch{return{raw:Io(r)}}})}catch{return[]}}var HC,xf,Ps,Ak,_k,En=G(()=>{ct();HC=[/[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];xf=process.env.BOSTRAT_DEBUG_DIR||Tk.join(UC.homedir(),".bostrat","debug"),Ps=Tk.join(xf,"handoff.jsonl"),Ak=Number(process.env.BOSTRAT_HANDOFF_DEBUG_MAX)||500;_k={DEBUG_DIR:xf,LOG_FILE:Ps}});import Fl from"node:fs/promises";import vf from"node:path";import qC from"node:os";async function $k(e=Ik){await Fl.mkdir(e,{recursive:!0});for(let t of GC){let n=t==="prepare-commit-msg"?zC:t==="post-commit"?VC:`${Sf}exit 0
49
+ `,r=vf.join(e,t),o=null;try{o=await Fl.readFile(r,"utf8")}catch{}o!==n&&await Fl.writeFile(r,n,{mode:493}),await Fl.chmod(r,493).catch(()=>{})}return e}function Rk({nodeUrl:e,dir:t=Ik,env:n=process.env}={}){return String(n.BOSTRAT_GIT_HOOKS||"").toLowerCase()==="off"?[]:["-e","GIT_CONFIG_COUNT=1","-e","GIT_CONFIG_KEY_0=core.hooksPath","-e",`GIT_CONFIG_VALUE_0=${t}`,"-e",`${pi}=${e}`]}function Ok(e=process.env){return e.BOSTRAT_NODE_URL||`http://127.0.0.1:${e.PORT||3362}`}var pi,KC,Ik,GC,Sf,zC,VC,Af=G(()=>{Ts();pi="BOSTRAT_NODE_URL",KC=process.env.BOSTRAT_STATE_DIR||vf.join(process.env.HOME||qC.tmpdir(),".bostrat"),Ik=vf.join(KC,"git-hooks"),GC=["applypatch-msg","pre-applypatch","post-applypatch","pre-commit","pre-merge-commit","prepare-commit-msg","commit-msg","post-commit","pre-rebase","post-checkout","post-merge","pre-push","post-rewrite","pre-auto-gc"],Sf=`#!/bin/sh
50
50
  # bostrat git hook shim (agent/src/git-hooks.js) \u2014 chains to the repo's own hook,
51
51
  # then stamps/reports for rework attribution when running inside a bostrat box.
52
52
  hook=$(basename "$0")
@@ -61,75 +61,75 @@ esac
61
61
  if [ -x "$orig/$hook" ] && [ "$orig/$hook" != "$0" ]; then
62
62
  "$orig/$hook" "$@" || exit $?
63
63
  fi
64
- `,OC=`${cf}
64
+ `,zC=`${Sf}
65
65
  # \u2500\u2500 bostrat: append provenance trailers (Layer 0). Skipped for merge commits
66
66
  # (nobody "wrote" a merge) and outside a box (no token / no node url).
67
- [ -z "$${zn}" ] && exit 0
68
- [ -z "$${oi}" ] && exit 0
67
+ [ -z "$${Yn}" ] && exit 0
68
+ [ -z "$${pi}" ] && exit 0
69
69
  [ "$2" = "merge" ] && exit 0
70
- trailers=$(curl -sS -m 3 -H "${Vn}: $${zn}" "$${oi}/api/git/trailers" 2>/dev/null) || exit 0
70
+ trailers=$(curl -sS -m 3 -H "${Xn}: $${Yn}" "$${pi}/api/git/trailers" 2>/dev/null) || exit 0
71
71
  [ -z "$trailers" ] && exit 0
72
72
  printf '%s\\n' "$trailers" | while IFS= read -r line; do
73
73
  [ -n "$line" ] && git interpret-trailers --in-place --if-exists addIfDifferent --trailer "$line" "$1" >/dev/null 2>&1 || true
74
74
  done
75
75
  exit 0
76
- `,MC=`${cf}
76
+ `,VC=`${Sf}
77
77
  # \u2500\u2500 bostrat: report the commit (code.committed + rework analysis, node-side).
78
- [ -z "$${zn}" ] && exit 0
79
- [ -z "$${oi}" ] && exit 0
78
+ [ -z "$${Yn}" ] && exit 0
79
+ [ -z "$${pi}" ] && exit 0
80
80
  sha=$(git rev-parse HEAD 2>/dev/null) || exit 0
81
81
  cwd=$(git rev-parse --show-toplevel 2>/dev/null)
82
- printf '{"sha":"%s","cwd":"%s"}' "$sha" "$cwd" | curl -sS -m 5 -X POST "$${oi}/api/git/committed" \\
83
- -H 'content-type: application/json' -H "${Vn}: $${zn}" --data-binary @- >/dev/null 2>&1 || true
82
+ printf '{"sha":"%s","cwd":"%s"}' "$sha" "$cwd" | curl -sS -m 5 -X POST "$${pi}/api/git/committed" \\
83
+ -H 'content-type: application/json' -H "${Xn}: $${Yn}" --data-binary @- >/dev/null 2>&1 || true
84
84
  exit 0
85
- `});import{execFile as gk}from"node:child_process";import{promisify as CC}from"node:util";import Bl from"node:fs";import{randomUUID as yk}from"node:crypto";function So(e){return new Promise(t=>setTimeout(t,e))}function Dl(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 bk(e){return`/tmp/tmux-${e}/default`}function NC({explicit:e,legacyExists:t,runtimeDir:n,uid:r}){if(e)return e;let o=bk(r);return t?o:n?`${n}/bostrat/tmux-default`:o}function ai(){return process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1"?[]:["-e",`${si}=1`]}function ii(e,t,n){let r=To(e),o=/(^|\s)(--session-id|--resume|--continue|-r|-c)(\s|=|$)/.test(e);if(!r||o)return e;let s=`${e} --session-id ${t}`,a=/(^|\s)(--name|-n)(\s|=)/.test(e);return n&&!a&&je(n)&&(s+=` --name ${n}`),s}function To(e){return/(^|\/|\s)claude(\s|$)/.test(String(e||""))}function $r(e){return/(^|\/|\s)claude(\s|$)/.test(e)?"claude":/cursor/.test(e)?"cursor":/codex/.test(e)?"codex":/gemini/.test(e)?"gemini":"agent"}function BC(e){let t=String(e||"").trim();return!t||/fake-|\.sh(\s|$)/.test(t)?!1:To(t)||/(^|\/|\s)codex(\s|$)/.test(t)||/cursor-agent/.test(t)||/(^|\/|\s)gemini(\s|$)/.test(t)}async function kk(e,{loginShell:t=!1,failOpen:n=!1}={}){let r=await xk(e,{loginShell:t});return r===jl?!0:r===Ts?!1:n}async function xk(e,{loginShell:t=!1,timeoutMs:n=uf}={}){if(!e)return Ts;let r=t?process.env.SHELL||"/bin/sh":"sh",o=t?"-lic":"-c";try{return await Ie(r,[o,'command -v "$1" >/dev/null 2>&1',"_",e],{timeout:n}),jl}catch(s){return s?.killed||s?.signal?As:s?.code===1||s?.code===127?Ts:As}}async function Ll(e,{retries:t=jC,sleep:n=LC,probe:r=xk}={}){let o=String(e||"").trim().split(/\s+/)[0],s=await r(o,{timeoutMs:uf});for(let a=0;s===As&&a<t.length;a++)await n(t[a]),s=await r(o,{timeoutMs:uf*2});return s}function Z(...e){return["-S",Rt,...e]}async function Rr(){if(!Bl.existsSync(Rt))return!1;try{return await Ie(Y,Z("list-sessions")),!0}catch(e){let t=e&&e.stderr?String(e.stderr):"";return!/no server running/i.test(t)}}async function ci(){if(await Rr())return!0;try{Bl.mkdirSync(Rt.replace(/\/[^/]+$/,""),{recursive:!0}),await Ie(Y,Z("new-session","-d","-s","keeper","sleep 2147483647"))}catch{}return await Rr()}function je(e){return typeof e=="string"&&FC.test(e)}async function nn(){if(!Bl.existsSync(Rt))return[];try{let e="#{session_name}|#{session_windows}|#{session_attached}|#{session_activity}|#{pane_current_path}|#{@bostrat-session}|#{@bostrat-title}|#{@bostrat-sid}|#{@bostrat-agent}|#{alternate_on}|#{session_created}",{stdout:t}=await Ie(Y,Z("list-sessions","-F",e)),n=Date.now();return t.trim().split(`
86
- `).filter(Boolean).map(r=>{let[o,s,a,i,c,l,u,d,p,f,w]=r.split("|"),m=Number(i),g=Number(w);return{name:o,title:u||null,windows:Number(s),attached:Number(a),lastActivityMs:Number.isFinite(m)?n-m*1e3:null,cwd:c||null,isBostrat:l==="1",sessionId:d||null,agent:p||(l==="1"?"claude":null),alternateOn:f==="1",createdMs:Number.isFinite(g)&&g>0?g*1e3:null}}).filter(r=>!DC.has(r.name)&&!r.name.startsWith("bostrat-view-"))}catch{return[]}}async function ke(e){return(await nn()).find(n=>n.name===e)||null}function qC(e){if(typeof e!="string")return!1;let t=e.trim();return t.length>=1&&t.length<=HC&&UC.test(t)}function Fl(e){return e.trim().replace(/\s+/g,"-").toLowerCase().replace(/[^A-Za-z0-9_.-]/g,"").replace(/^-+|-+$/g,"")}async function vk(e){try{let{stdout:t}=await Ie(Y,Z("list-sessions","-F","#{session_name}"));return t.split(`
87
- `).map(n=>n.trim()).includes(e)}catch{return!1}}function GC(e){let t=String(e||"").trim().split(/\s+/)[0]||"";if(t.includes("/"))return null;let n=[],r=s=>/[A-Za-z0-9_]/.test(s);for(let s=1;s<=t.length-3;s++)r(t[s-1])===r(t[s])&&n.push(t.slice(s));if(!n.length)return null;let o=n.map(s=>s.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));return new RegExp(`\\b(?:${o.join("|")})`)}async function zC(e,t){let n=Date.now()+li(),r=GC(t),o=!1,s=0,a=0;for(;;){if(await So(WC),s+=1,!await vk(e))return;let i=await Be(e,{lines:15}),c=!o&&KC.test(i)&&!!r?.test(i),l=!o&&!!r?.test(i);if(!c&&!l&&s>1&&!await Xn(e)){if(a+=1,a>1)return}else c||(a=0);if(c){o=!0,await ie({flow:"spawn",phase:"launch-retry",sessionName:e,agent:$r(t),promptHead:t.slice(0,120)}).catch(()=>{}),await Ie(Y,Z("send-keys","-t",e,"C-u")),await Ie(Y,Z("send-keys","-t",e,"-l",t)),await Ie(Y,Z("send-keys","-t",e,"Enter"));continue}if(Date.now()>n){await ie({flow:"spawn",phase:"launch-failed",sessionName:e,agent:$r(t),retried:o,error:"agent CLI never started after launch was typed"}).catch(()=>{});return}}}async function Or(e,t=PC,n={}){if(!qC(e))throw new Error("displayName must be 1\u201364 chars (letters, digits, space . _ -)");let r=e.trim(),o=Fl(r);if(!je(o))throw new Error("resulting tmux session name is invalid");if(!await ci())throw new Error(`host tmux server not running on ${Rt} and auto-start failed \u2014 start one: ${Y} -S ${Rt} new-session -d -s keeper "sleep 2147483647"`);if(await vk(o))throw new Error(`tmux session "${o}" already exists`);let s=n.agentCmd||df,a=n.agent||$r(s),i=!!n.resumeSessionId,c=n.resumeSessionId||yk(),l=i?s:ii(s,c,o),u=i?n.pinned===!0:/(^|\s)--session-id(\s|=)/.test(l),d=a==="claude"&&To(s),p=n.firstRun===!0;p||(d&&await vr(t),a==="codex"&&await ms(t),a==="cursor"&&await hs(t),await Wb(t),n.freshWorkspace!==!0&&await Ml(t));let f=d&&!p?fl():null,w=ub(),m=["-e",`${zn}=${w}`];m.push(...mk({nodeUrl:hk()})),f&&m.push("-e",`ANTHROPIC_API_KEY=${f}`),d&&m.push(...ai());try{await Ie(Y,Z("new-session","-d","-s",o,"-c",t,...m))}catch(g){throw Dl(f?Dl(g,f):g,w)}return await Ao(o),await Ie(Y,Z("set-option","-t",o,"@bostrat-session","1")),await Ie(Y,Z("set-option","-t",o,"@bostrat-title",r)),await Ie(Y,Z("set-option","-t",o,"@bostrat-sid",c)),await Ie(Y,Z("set-option","-t",o,"@bostrat-agent",a)),await Ie(Y,Z("send-keys","-t",o,l,"Enter")),BC(l)&&zC(o,l).catch(()=>{}),{name:o,title:r,cwd:t,sessionId:c,agent:a,pinned:u,hookToken:w}}async function rn(e){if(!je(e))throw new Error("invalid session name");await Ie(Y,Z("kill-session","-t",e))}async function Sk(e,t){if(je(e))try{let n=t?Z("set-option","-t",e,"@bostrat-sid",t):Z("set-option","-u","-t",e,"@bostrat-sid");await Ie(Y,n)}catch{}}async function Be(e,{lines:t=40}={}){if(!je(e))return"";try{let n=Z("capture-pane","-t",e,"-p");Number.isFinite(t)&&t>0&&n.push("-S",`-${Math.floor(t)}`);let{stdout:r}=await Ie(Y,n);return String(r||"")}catch{return""}}async function Tk(e){if(!je(e))return[];try{let{stdout:t}=await Ie(Y,Z("list-panes","-s","-t",e,"-F","#{pane_pid}"));return String(t||"").trim().split(`
88
- `).map(n=>Number(n.trim())).filter(n=>Number.isFinite(n)&&n>0)}catch{return[]}}async function Ak(e){if(!je(e))return 0;try{let{stdout:t}=await Ie(Y,Z("list-clients","-t",e,"-F","1"));return String(t||"").trim().split(`
89
- `).filter(Boolean).length}catch{return 0}}async function Ao(e,{cols:t=YC,rows:n=XC}={}){if(!je(e))return!0;if(await Ak(e))return!1;try{let r=await Ek(e);if(r.cols===t&&r.rows===n)return!0;await Ie(Y,Z("resize-window","-t",e,"-x",String(t),"-y",String(n))),await Ie(Y,Z("set-window-option","-t",e,"window-size","latest")),await So(80)}catch{}return!0}async function ZC(e){if(!je(e))return 0;try{let{stdout:t}=await Ie(Y,Z("display-message","-t",e,"-p","#{pane_pid}"));return Number(String(t||"").trim())||0}catch{return 0}}async function Xn(e){let t=await ZC(e);if(!t)return!1;try{return await Ie("pgrep",["-P",String(t)]),!1}catch(n){return n?.code===1}}async function Ek(e){if(!je(e))return{cols:0,rows:0};try{let{stdout:t}=await Ie(Y,Z("display-message","-t",e,"-p","#{window_width} #{window_height}")),[n,r]=String(t||"").trim().split(/\s+/).map(o=>Number(o)||0);return{cols:n,rows:r}}catch{return{cols:0,rows:0}}}async function Ul(e,{cols:t=VC,rows:n=JC}={}){if(je(e)&&!await Ak(e))try{let r=await Ek(e),o=Math.max(r.cols,t),s=Math.max(r.rows,n);(o>r.cols||s>r.rows)&&(await Ie(Y,Z("resize-window","-t",e,"-x",String(o),"-y",String(s))),await Ie(Y,Z("set-window-option","-t",e,"window-size","latest")),await So(80))}catch{}}async function on(e){return await Ul(e),Be(e,{lines:Ze})}async function We(e,t,{settleMs:n=40,kind:r}={}){if(!je(e))throw new Error("invalid session name");let o=(Array.isArray(t)?t:[t]).filter(s=>_k.has(s));for(let s=0;s<o.length;s++)await Ie(Y,Z("send-keys","-t",e,o[s])),n>0&&s<o.length-1&&await So(n);return ie({flow:"tmux",phase:"send-keys",sessionName:e,kind:r||"keys",keys:o.join(" ")}).catch(()=>{}),o.length}async function mf(e,t,{settleMs:n=40,kind:r}={}){if(!je(e))throw new Error("invalid session name");let o=(Array.isArray(t)?t:[]).filter(s=>s&&(typeof s.key=="string"&&_k.has(s.key)||typeof s.text=="string"&&s.text.length>0));for(let s=0;s<o.length;s++){let a=o[s];a.text!=null?await Ie(Y,Z("send-keys","-t",e,"-l",a.text)):await Ie(Y,Z("send-keys","-t",e,a.key)),n>0&&s<o.length-1&&await So(n)}return ie({flow:"tmux",phase:"send-sequence",sessionName:e,kind:r||"sequence",steps:o.map(s=>s.text!=null?`\u2039text:${s.text.length}\u203A`:s.key).join(" ")}).catch(()=>{}),o.length}async function Es(e,t,{kind:n}={}){if(!je(e))throw new Error("invalid session name");let r=Math.max(0,Math.floor(Number(t)||0));return r>0&&await Ie(Y,Z("send-keys","-t",e,"-N",String(r),"BSpace")),ie({flow:"tmux",phase:"send-keys",sessionName:e,kind:n||"wipe",keys:`BSpace x${r}`}).catch(()=>{}),r}async function ql(e,t,{perCharDelayMs:n=120,kind:r}={}){if(!je(e))throw new Error("invalid session name");let o=[...String(t)];for(let s of o)await Ie(Y,Z("send-keys","-t",e,"-l",s)),n>0&&await So(n);ie({flow:"tmux",phase:"type",sessionName:e,kind:r||"type",textLen:o.length,textHead:String(t).slice(0,120)}).catch(()=>{})}function QC(e,t){return new Promise((n,r)=>{let o=gk(Y,Z(...e),(s,a,i)=>{s?r(s):n({stdout:a,stderr:i})});o.stdin.on("error",()=>{}),o.stdin.end(t)})}async function eN(e,t){let n=`bostrat-${yk().slice(0,8)}`;await QC(["load-buffer","-b",n,"-"],t),await Ie(Y,Z("paste-buffer","-p","-d","-b",n,"-t",e))}async function ot(e,t,{enter:n=!0,submitDelayMs:r=0,kind:o,paste:s=!1}={}){if(!je(e))throw new Error("invalid session name");if(typeof t=="string"&&t.length>0&&(s?await eN(e,t):await Ie(Y,Z("send-keys","-t",e,"-l",t))),n){let a=Number(r);Number.isFinite(a)&&a>0&&await So(a),await Ie(Y,Z("send-keys","-t",e,"Enter"))}ie({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 Ie,Y,wk,Rt,PC,df,si,pf,DC,jl,Ts,As,uf,jC,LC,ff,FC,UC,HC,li,WC,KC,VC,JC,Ze,YC,XC,_k,Hl,ct=G(()=>{Wa();hl();wl();Xa();Cl();Tn();fs();lf();Ie=CC(gk);Y=process.env.BOSTRAT_TMUX_BIN||"/usr/bin/tmux";wk=typeof process.getuid=="function"?process.getuid():0,Rt=NC({explicit:process.env.BOSTRAT_TMUX_SOCKET,legacyExists:(()=>{try{return Bl.existsSync(bk(wk))}catch{return!1}})(),runtimeDir:process.env.XDG_RUNTIME_DIR,uid:wk}),PC=process.env.BOSTRAT_DEFAULT_CWD||process.env.HOME||"/",df=process.env.BOSTRAT_AGENT_CMD||"claude --dangerously-skip-permissions",si="CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN";pf="bostrat-usage-probe",DC=new Set([pf]);jl="present",Ts="absent",As="unknown",uf=5e3,jC=[250,1e3,3e3],LC=e=>new Promise(t=>setTimeout(t,e));ff={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"};FC=/^[A-Za-z0-9_.-]{1,64}$/;UC=/^[A-Za-z0-9 ._↻-]+$/,HC=64;li=()=>Number(process.env.BOSTRAT_LAUNCH_VERIFY_MS)||12e3,WC=1e3,KC=/not found|Unknown command/i;VC=Number(process.env.BOSTRAT_PROMPT_CAPTURE_COLS)||100,JC=Number(process.env.BOSTRAT_PROMPT_CAPTURE_ROWS)||40,Ze=Number(process.env.BOSTRAT_PROMPT_CAPTURE_LINES)||80,YC=Number(process.env.BOSTRAT_BOX_COLS)||120,XC=Number(process.env.BOSTRAT_BOX_ROWS)||40;_k=new Set(["Up","Down","Left","Right","Space","Enter","Tab","BTab","Escape","BSpace"]);Hl=1600});import ui from"node:fs";import aN from"node:fs/promises";import _s from"node:path";import iN from"node:os";function gf(e){return e.replace(/[^A-Za-z0-9]/g,"-")}function yf(e){let t=_s.join(wf,gf(e)),n;try{n=ui.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return null}let r=null;for(let o of n){let s=_s.join(t,o);try{let{mtimeMs:a}=ui.statSync(s);(!r||a>r.mtimeMs)&&(r={full:s,mtimeMs:a})}catch{}}return r?r.full:null}function sn(e,t){if(!t)return null;let n=_s.join(wf,gf(e),`${t}.jsonl`);return ui.existsSync(n)?n:null}function Nk(e){if(!e)return[];let t=_s.join(wf,gf(e)),n;try{n=ui.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return[]}let r=[];for(let o of n)try{let s=ui.statSync(_s.join(t,o));r.push({id:o.slice(0,-6),birthMs:s.birthtimeMs||s.ctimeMs||s.mtimeMs})}catch{}return r}async function _t(e,t=131072){let n=await aN.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 lN(e){let t=e.split(`
90
- `);for(let n=t.length-1;n>=0;n--){let r=t[n].trim();if(!r||r[0]!=="{")continue;let o;try{o=JSON.parse(r)}catch{continue}let s=o?.message?.usage;if(!s)continue;let a=(s.input_tokens||0)+(s.cache_creation_input_tokens||0)+(s.cache_read_input_tokens||0);if(a>0)return{occupancy:a,model:o.message.model||o.model||null}}return null}async function di(e,t=null,{fallbackNewest:n=!0}={}){if(!e)return null;let r,o;if(t){if(r=sn(e,t),o=!0,!r)return null}else if(n){if(r=yf(e),o=!1,!r)return null}else return null;let s;try{s=lN(await _t(r))}catch{return null}if(!s)return null;let a=Object.prototype.hasOwnProperty.call(Ck,s.model),i=Ck[s.model]||cN;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 Ck,cN,wf,an=G(()=>{Ck={"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},cN=2e5,wf=process.env.BOSTRAT_CLAUDE_PROJECTS||_s.join(iN.homedir(),".claude","projects")});function uN(e){let t=[],n="",r=null;for(let o=0;o<e.length;o++){let s=e[o];if(r){n+=s,s===r&&e[o-1]!=="\\"&&(r=null);continue}if(s==="'"||s==='"'||s==="`"){r=s,n+=s;continue}if(s==="&"&&e[o+1]==="&"){t.push(n),n="",o++;continue}if(s==="|"&&e[o+1]==="|"){t.push(n),n="",o++;continue}if(s==="|"||s===";"||s===`
91
- `){t.push(n),n="";continue}n+=s}return t.push(n),t.map(o=>o.trim()).filter(Boolean)}function pi(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 fi(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 Pe(e,t=new Set){let n=[];for(let r=1;r<e.length;r++){let o=e[r];if(o==="<<")break;if(Bk(o)){t.has(o)&&r++;continue}n.push(o)}return n}function jk(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 fN(e){let t=jk(e),n=ft(Pe(e).find(r=>!/^\d+(,\d+)?p$/.test(r)));return t&&n?t.from===t.to?`Read line ${t.from} of ${ze(n)}`:`Read lines ${t.from}\u2013${t.to} of ${ze(n)}`:e.includes("-i")&&n?`Edit ${ze(n)}`:null}function bf(e){if(e.includes("--files")){let s=ft(Pe(e,Pk)[0]);return s&&s!=="."?`List files in ${Is(s)}`:"List files"}let t=Pe(e,Pk),n=t[0];if(!n)return null;let r=ft(t.slice(1).find(s=>s!==".")),o=$s(n,40);return r?`Search for \u201C${o}\u201D in ${Is(r)}`:`Search for \u201C${o}\u201D`}function kf(e){let t=Pe(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 xf(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=Pe(e)[0];return n?`Run ${ze(n)}`:null}function mN(e){let t=Pe(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 Dk(e){return e.find(t=>/^https?:\/\//.test(t))||null}function gN(e){let t=fi(pi(e));if(!t.length)return null;if(/^(ba|z)?sh$/.test(ze(t[0]))&&(t[1]==="-lc"||t[1]==="-c")&&t[2])return vf(t[2]);let n=ze(t[0]);if(wN.has(n))return null;if(t.includes("--version"))return`Check ${n} version`;if(n.endsWith(".sh"))return`Run ${n}`;let r=hN[n];return r?r(t.map((o,s)=>s===0?n:o)):null}function vf(e){let t=String(e||"").trim();if(!t)return null;let n=t.indexOf("<<");if(n!==-1){let i=t.indexOf(`
92
- `,n);i!==-1&&(t=t.slice(0,i))}let r=uN(t);for(let i=0;i<r.length-1;i++){let c=fi(pi(r[i])),l=fi(pi(r[i+1]));if(!(!c.length||!l.length)&&["nl","cat"].includes(ze(c[0]))&&ze(l[0])==="sed"){let u=jk(l),d=Pe(c)[0];if(u&&d)return $s(u.from===u.to?`Read line ${u.from} of ${ze(d)}`:`Read lines ${u.from}\u2013${u.to} of ${ze(d)}`,88)}}let o=[];for(let i of r){let c=gN(i);c&&o.push({d:c,head:ze(fi(pi(i))[0]||""),sub:Pe(fi(pi(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":$s(s?s.d:o[0].d,88)}var $s,ft,ze,Is,Bk,Pk,dN,pN,hN,wN,Lk=G(()=>{$s=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,ft=e=>e&&!/[$`]/.test(e)?e:null,ze=e=>e.replace(/\/+$/,"").split("/").pop()||e,Is=e=>{let t=e.replace(/\/+$/,"").split("/").filter(Boolean);return t.length>3?t.slice(-2).join("/"):e},Bk=e=>e.startsWith("-"),Pk=new Set(["-g","--glob","-t","--type","-A","-B","-C","-m","--max-count","-e","--regexp","-f","--file"]);dN={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 ${ze(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"},pN={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"};hN={git:e=>{let t=Pe(e,new Set(["-C","-c"])),n=dN[t[0]];return n?n(t,e):null},gh:e=>{let t=Pe(e),n=pN[t[0]];return n?n(t):null},sed:fN,rg:bf,grep:bf,egrep:bf,nl:e=>{let t=ft(Pe(e)[0]);return t?`Read ${ze(t)}`:null},cat:e=>{let t=ft(Pe(e)[0]);return t?`Read ${ze(t)}`:null},head:e=>{let t=ft(Pe(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the start of ${ze(t)}`:null},tail:e=>{let t=ft(Pe(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the end of ${ze(t)}`:null},wc:e=>{let t=ft(Pe(e)[0]);return t?`Count lines in ${ze(t)}`:"Count input lines"},ls:e=>{let t=ft(Pe(e)[0]);return t&&t!=="."?`List files in ${Is(t)}`:"List files"},find:e=>ft(e[1])&&!Bk(e[1])&&e[1]!=="."?`Find files in ${Is(e[1])}`:"Find files",tree:()=>"List the directory tree",mkdir:e=>{let t=ft(Pe(e)[0]);return t?`Create directory ${Is(t)}`:null},touch:e=>{let t=ft(Pe(e)[0]);return t?`Create ${ze(t)}`:null},rm:e=>{let t=ft(Pe(e)[0]);return t?`Delete ${Is(t)}`:null},mv:e=>{let t=ft(Pe(e)[0]);return t?`Move ${ze(t)}`:null},cp:e=>{let t=ft(Pe(e)[0]);return t?`Copy ${ze(t)}`:null},chmod:e=>{let t=ft(Pe(e)[1]);return t?`Change permissions on ${ze(t)}`:null},diff:e=>{let t=Pe(e);return t.length>=2?`Compare ${ze(t[0])} and ${ze(t[1])}`:null},curl:e=>{let t=Dk(e);return t?`Fetch ${$s(t,56)}`:"Fetch a URL"},wget:e=>{let t=Dk(e);return t?`Fetch ${$s(t,56)}`:"Fetch a URL"},npm:kf,pnpm:kf,yarn:kf,npx:e=>{let t=Pe(e)[0];return t?`Run ${t}`:null},node:e=>xf(e,"Node"),python:e=>xf(e,"Python"),python3:e=>xf(e,"Python"),make:e=>{let t=Pe(e)[0];return t?`Run make ${t}`:"Run make"},systemctl:mN,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=Pe(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=Pe(e)[0];return t?`Locate ${t}`:null},command:e=>e[1]==="-v"&&e[2]?`Locate ${e[2]}`:null,fly:e=>{let t=Pe(e)[0];return t==="deploy"?"Deploy to Fly":t?`Run fly ${t}`:null}},wN=new Set(["pwd","echo","cd","sleep","true","false","test","[","set","export","exit","read"])});function Rs(e){let t=e.split(`
93
- `).map(n=>n.trim()).find(Boolean)||e;return t.length>88?`${t.slice(0,88).trimEnd()}\u2026`:t}function Mr(e,t=""){let n=t.trim();return n||vf(e)||Rs(e)}function Sf(e,t){if(e){if(Array.isArray(e)){for(let n of e)Sf(n,t);return}if(typeof e=="object"){if(e.type==="tool_use"&&Tf.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))Sf(n,t)}}}async function Fk(e,{maxBytes:t=1048576,limit:n=400}={}){let r;try{r=await _t(e,t)}catch{return[]}let o=[];for(let s of r.split(`
94
- `)){let a=s.trim();if(!a||a[0]!=="{")continue;let i;try{i=JSON.parse(a)}catch{continue}let c=i.message;if(!c)continue;let l=[];if(Sf(c.content,l),!l.length)continue;let u=i.timestamp?Date.parse(i.timestamp):null;for(let d of l)o.push({...d,summary:Mr(d.command,d.description),ts:u})}return o.slice(-n)}function Uk(e,t){let n=a=>a?.box??null,r=new Map;for(let a of t||[]){if(a.role!=="assistant"||!(a.text||"").trim())continue;let i=n(a);r.has(i)||r.set(i,[]),r.get(i).push(a)}let o=new Map;for(let a of e||[]){let i=n(a);o.has(i)||o.set(i,[]),o.get(i).push(a)}let s=[];for(let[a,i]of o)s.push(...yN(i,r.get(a)||[]));return s.sort((a,i)=>(a.ts||0)-(i.ts||0))}function yN(e,t){let n=[...t].sort((l,u)=>(l.ts||0)-(u.ts||0)),r=[...e].sort((l,u)=>(l.ts||0)-(u.ts||0)),o=[],s=0,a=0,i=l=>{let u=l.n??a+1;return u>a&&(a=u),u};for(let l of n){let u=r.findIndex((w,m)=>m>=s&&(w.ts||0)>(l.ts||0)),d=u===-1?r.length:u,p=r.slice(s,d);if(s=d,!p.length)continue;let f=p.map(w=>({...w,n:i(w)}));o.push({id:`batch-${l.ts}-${l.box}`,anchorTs:l.ts,anchorBox:l.box,agent:l.agent,boxRole:l.boxRole,commands:f,ts:Math.max(...f.map(w=>w.ts||0)),pending:!1})}let c=r.slice(s);if(c.length){let l=c.map(u=>({...u,n:i(u)}));o.push({id:`batch-pending-${l[0]?.box||"lead"}`,anchorTs:null,anchorBox:l[l.length-1]?.box??null,agent:l[l.length-1]?.agent??"claude",boxRole:l[l.length-1]?.boxRole??"lead",commands:l,ts:Math.max(...l.map(u=>u.ts||0)),pending:!0})}return o}var Tf,Os=G(()=>{an();Lk();Tf=new Set(["Bash"])});import Hk from"node:fs";import Ef from"node:fs/promises";import Af from"node:path";import bN from"node:os";async function qk(e){try{return await Ef.realpath(e)}catch{return e}}function xN(e=kN){let t=[],n=r=>{let o;try{o=Hk.readdirSync(r,{withFileTypes:!0})}catch{return}for(let s of o){let a=Af.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:Hk.statSync(a).mtimeMs})}catch{}}}};return n(e),t.sort((r,o)=>o.mtimeMs-r.mtimeMs)}async function vN(e,t=1048576){let n;try{n=await Ef.open(e,"r")}catch{return""}try{let r=Buffer.alloc(Math.min(t,65536)),o="",s=0;for(;;){let{bytesRead:a}=await n.read(r,0,r.length,s);if(!a)break;o+=r.toString("utf8",0,a);let i=o.indexOf(`
95
- `);if(i!==-1)return o.slice(0,i);if(s+=a,o.length>=t)break}return o}finally{await n.close()}}async function SN(e){let t=await vN(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 Eo(e,t){if(!e&&!t)return null;let n=xN();if(t){let o=n.find(s=>s.id===t);return o||null}let r=await qk(e);for(let o of n){let s=await SN(o.file);if(s&&(s===e||await qk(s)===r))return o}return null}async function Wk(e,t,{limit:n=80,maxBytes:r=524288}={}){let o=await Eo(e,t);if(!o)return[];let s;try{s=await _t(o.file,r)}catch{return[]}let a=[],i=null,c=[],l=!1,u=!1,d=null;for(let p of s.split(`
96
- `)){let f=p.trim();if(!f||f[0]!=="{")continue;let w;try{w=JSON.parse(f)}catch{continue}if((w.type==="turn_context"&&w.payload?.model||w.type==="session_meta"&&w.payload?.model)&&(i=w.payload.model),w.type==="event_msg"){let x=w.payload?.type;x==="task_started"?(l=!0,u=!1,d=w.payload?.turn_id||null):x==="task_complete"&&l&&(l=!1,!u&&w.payload?.last_agent_message==null&&a.push({role:"assistant",failed:!0,text:_o,sourceId:w.payload?.turn_id||d||void 0,ts:w.timestamp?Date.parse(w.timestamp):null,model:i}));continue}if(w.type!=="response_item")continue;let m=w.payload;if(!m)continue;if((m.type==="function_call"||m.type==="custom_tool_call")&&m.name){u=!0,_f.has(m.name)||c.push(m.name);continue}if(m.type!=="message"||m.role!=="assistant")continue;u=!0;let g=AN(m.content),y=c.length?c.slice():null;c=[],!(!g&&!y)&&a.push({role:"assistant",text:g,tools:y||void 0,ts:w.timestamp?Date.parse(w.timestamp):null,model:i})}if(i)for(let p of a)p.model||(p.model=i);return a.slice(-n)}function EN(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 _N(e){let t=e[0];if(t!=='"'&&t!=="'"&&t!=="`")return null;let n="";for(let r=1;r<e.length;r++){let o=e[r];if(o==="\\"){let s=e[++r];if(s===void 0)return null;if(s==="n")n+=`
97
- `;else if(s==="t")n+=" ";else if(s==="r")n+="\r";else if(s==="u")if(e[r+1]==="{"){let a=e.indexOf("}",r+2);if(a===-1)return null;n+=String.fromCodePoint(parseInt(e.slice(r+2,a),16)),r=a}else n+=String.fromCharCode(parseInt(e.slice(r+1,r+5),16)),r+=4;else n+=s}else{if(o===t)return n;if(t==="`"&&o==="$"&&e[r+1]==="{")return null;n+=o}}return null}function IN(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=_N(i.slice(c.index+c[0].length).trimStart());l&&l.trim()&&o.push(l.trim())}),o}async function Kk(e,t,{limit:n=400,maxBytes:r=524288}={}){let o=await Eo(e,t);if(!o)return[];let s;try{s=await _t(o.file,r)}catch{return[]}let a=[];for(let i of s.split(`
98
- `)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.type!=="response_item")continue;let u=l.payload;if(!u)continue;let d=[];if(u.type==="function_call"&&mi.has(u.name)){let f;try{f=JSON.parse(u.arguments||"{}")}catch{continue}let w=EN(f);w&&(d=[w])}else u.type==="custom_tool_call"&&u.name==="exec"&&(d=IN(u.input));if(!d.length)continue;let p=u.call_id||u.id||null;d.forEach((f,w)=>{a.push({id:p?w?`${p}:${w}`:p:null,tool:u.name,command:f,description:"",summary:Mr(f),ts:l.timestamp?Date.parse(l.timestamp):null})})}return a.slice(-n)}async function Gk(e,t){let n=await Eo(e,t);if(!n)return null;try{return Math.round((await Ef.stat(n.file)).mtimeMs)}catch{return n.mtimeMs||null}}var kN,TN,AN,mi,_f,_o,Io=G(()=>{an();Os();kN=process.env.BOSTRAT_CODEX_SESSIONS||Af.join(process.env.CODEX_HOME||Af.join(bN.homedir(),".codex"),"sessions");TN=new Set(["output_text","text"]),AN=e=>typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&typeof t.text=="string"&&TN.has(t.type)).map(t=>t.text).join(`
99
- `).trim():"";mi=new Set(["exec_command","shell","exec"]),_f=new Set(["wait","write_stdin"]),_o="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 hi({error:e=null,status:t=null,text:n=""}={}){let r=String(e||"").trim().toLowerCase();if(r&&zk.has(r))return zk.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 Vk(e){if(!e||e.role!=="assistant")return null;if(e.apiError){let t=e.apiError;return{cls:t.cls||hi({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===_o?"other":hi({text:t}),code:null,status:null,requestId:null}}return null}function Jk(e,{codexFailedText:t=null}={}){let n=String(e?.text||"").trim();return n?e?.model==="<synthetic>"?/^No response requested\.$/.test(n)?null:{cls:hi({text:n}),code:null,status:$N(n),requestId:null,text:n}:t&&n===t?{cls:"other",code:null,status:null,requestId:null,text:n}:null:null}function $N(e){let t=/^API Error:\s*(\d{3})\b/.exec(e);return t?Number(t[1]):null}var _z,zk,Kl=G(()=>{Io();_z=Object.freeze(["entitlement","auth","rate_limit","overloaded","server","other"]),zk=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 RN(e,t){return!e||!t?null:sn(e,t)}function ON(e){return typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&t.type==="text"&&typeof t.text=="string").map(t=>t.text).join(`
100
- `).trim():""}function MN(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 CN(e){return Array.isArray(e)&&e.length>0&&e.every(t=>t&&t.type==="tool_result")}function If(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 Yk(e,t){if(!e.uuid)return null;let n=If(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 $f(e,{maxBytes:t=524288,limit:n=80}={}){let r;try{r=await _t(e,t)}catch{return[]}let o=[],s=new Map,a=new Map;for(let i of r.split(`
101
- `)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.type==="attachment"){let y=l.attachment;y?.type==="queued_command"&&y.commandMode==="task-notification"&&typeof y.prompt=="string"&&y.prompt.trim()&&o.push({role:"user",text:y.prompt.trim(),ts:l.timestamp?Date.parse(l.timestamp):null,model:null});continue}let u=l.message;if(!u)continue;let d=u.role||l.type;if(d!=="user"&&d!=="assistant"||d==="assistant"&&u.model==="<synthetic>"&&!l.isApiErrorMessage)continue;if(d==="assistant"&&Array.isArray(u.content))for(let y of u.content){let x=y?.type==="tool_use"?y.input?.file_path||y.input?.path:null;typeof x=="string"&&NN.test(x)&&s.set(y.id,x.split("/").pop()),y?.type==="tool_use"&&y.name==="Skill"&&y.id&&a.set(y.id,String(y.input?.skill||"").trim().replace(/^\//,"")||null)}if(CN(u.content)){let y=Yk(l,s);y&&o.push({role:"assistant",text:"",images:y,ts:l.timestamp?Date.parse(l.timestamp):null,model:null});continue}let p=ON(u.content),f=d==="assistant"?MN(u.content):null,w=d==="user"?Yk(l,s):null;if(!p&&!f&&!w)continue;let m=d==="user"&&l.isMeta&&typeof l.sourceToolUseID=="string"&&l.sourceToolUseID?{toolUseId:l.sourceToolUseID,skill:a.get(l.sourceToolUseID)??null}:null,g=d==="assistant"&&l.isApiErrorMessage?{code:typeof l.error=="string"?l.error:null,status:Number(l.apiErrorStatus)||null,requestId:l.requestId||null,cls:hi({error:l.error,status:l.apiErrorStatus,text:p})}:null;o.push({role:d,text:p,tools:f||void 0,images:w||void 0,injected:m||void 0,ts:l.timestamp?Date.parse(l.timestamp):null,model:u.model||null,apiError:g||void 0})}return o.slice(-n)}async function Xk(e,t,{turns:n=16}={}){let r=RN(e,t);if(!r)return"";let o=await $f(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}:** ${PN(s.text||c,700)} ${i}`.trim()}).join(`
102
-
103
- `):""}var NN,PN,Gl=G(()=>{Kl();an();NN=/\.(png|jpe?g|gif|webp|bmp|svg|tiff?|avif|heic|heif|ico)$/i;PN=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e});import DN from"node:fs/promises";import{execFile as BN}from"node:child_process";import{promisify as jN}from"node:util";function t0(e){Of=typeof e=="function"?e:null}function Mf(e){let t=String(e||""),n=t.indexOf("/lib/node_modules/");return n>0?t.slice(0,n):null}function n0({sessionName:e,from:t,to:n}={}){let r=String(n||"").trim();!r||Zk.has(r)||(Zk.add(r),Qk=Qk.then(()=>FN({sessionName:e,from:t,to:r})).catch(()=>{}))}async function FN({sessionName:e,from:t,to:n}){await ie({flow:"codex-update",phase:"start",sessionName:e,from:t,to:n}).catch(()=>{});try{let r=(await Rf("/bin/sh",["-c","command -v codex"])).stdout.trim();if(!r)throw new Error("codex not on PATH");let o=await DN.realpath(r),s=Mf(o),a=s?{...process.env,PATH:`${s}/bin:${process.env.PATH||""}`}:process.env;await Rf("npm",["install","-g","@openai/codex"],{env:a,timeout:LN});let i=(await Rf(r,["--version"])).stdout.trim().replace(/^codex-cli\s*/,"")||n;await ie({flow:"codex-update",phase:"done",sessionName:e,from:t,to:n,version:i}).catch(()=>{}),await e0({sessionName:e,from:t,to:n,version:i,status:"updated"})}catch(r){let o=String(r?.message||r).slice(0,300);await ie({flow:"codex-update",phase:"failed",sessionName:e,from:t,to:n,error:o}).catch(()=>{}),await e0({sessionName:e,from:t,to:n,status:"failed",error:o})}}async function e0(e){if(Of)try{await Of(e)}catch{}}var Rf,LN,Zk,Qk,Of,zl=G(()=>{Tn();Rf=jN(BN),LN=Number(process.env.BOSTRAT_CODEX_UPDATE_TIMEOUT_MS)||5*6e4,Zk=new Set,Qk=Promise.resolve(),Of=null});function HN(e,{provider:t,box:n}){let r=String(e).replace(/\r/g,"").split(`
104
- `);if(!r0.test(e))return null;let o=[],s=!1;for(let l=r.length-1;l>=0;l--){let u=r[l].match(UN);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"&&r0.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 $o(e){let t=String(e??"").replace(/\r/g,""),n=t.split(`
105
- `);for(let r=n.length-1;r>=0;r--)if(a0.test(n[r]))return n.slice(r).join(`
106
- `);return t}function qN(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 WN(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 KN(e,t=""){let n=$o(e);if(wi.test(n)||!/Sign in with ChatGPT/.test(n)||!/Press enter to continue/.test(n))return null;let r=n.split(`
107
- `),o=[],s=-1;for(let l=0;l<r.length;l++){let u=r[l].match(o0);if(!u)continue;s<0&&(s=l);let d="";for(let p=l+1;p<Math.min(l+3,r.length);p++){let f=r[p].trim();if(f){if(o0.test(r[p])||/^Press enter/.test(f))break;d=f;break}}o.push({n:Number(u[2]),cursor:!!u[1],label:u[3].trim(),desc:d})}let a=o.sort((l,u)=>l.n-u.n);if(a.length<2||a.some((l,u)=>l.n!==u+1)||!a.some(l=>/Sign in with ChatGPT/.test(l.label)))return null;let i=[];for(let l=0;l<s;l++){let u=r[l].trim();u&&!a0.test(r[l])&&qN(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=WN(l.label);return{label:l.label,description:[l.desc,u].filter(Boolean).join(" \xB7 ")}})}]}}function VN(e,t=""){let n=$o(e);if(wi.test(n)||!GN.test(n))return null;let r=n.trimEnd().split(`
108
- `).pop()||"";return zN.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 YN(e,t=""){let n=$o(e);if(wi.test(n)||!s0.test(n))return null;let r=n.split(`
109
- `),o=r.findIndex(i=>s0.test(i)),s="";for(let i=o+1;i<r.length;i++){let c=r[i].match(JN);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 XN(e,t=""){let n=$o(e);return wi.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 ZN(e,t=""){let n=$o(e);return wi.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 QN(e,t=""){let n=String(e);if(!/Press any key to log in/.test(n)||Cf.test(n))return null;let r=n.replace(/\r/g,"").split(`
110
- `).map(a=>a.trim()),o=r.findIndex(a=>/Press any key to log in/.test(a)),s=r.slice(0,o<0?r.length:o).filter(a=>a&&!/^Cursor Agent$/i.test(a)&&!/^v?\d{4}\.\d{2}\.\d{2}/.test(a)).join(" ");return{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,answerMode:"keys",promptId:"cursor:signin-start",questions:[{question:(s?`${s} `:"")+"Cursor isn't signed in on this box \u2014 start the sign-in to get a login link you can open from any device.",header:"Sign in",multiSelect:!1,options:[{label:"Start sign-in",description:"Shows a login link (and a QR option) \u2014 your login goes to cursor.com, never through bostrat"}]}]}}function tP(e,t=""){let n=String(e);if(!eP.test(n)||Cf.test(n))return null;let r=n.replace(/\r/g,"").split(`
111
- `),o="",s=r.findIndex(a=>/https:\/\//.test(a));if(s>=0){o=r[s].slice(r[s].indexOf("https://")).trim();for(let a=s+1;a<r.length;a++){let i=r[a].trim();if(!i||!/^[A-Za-z0-9~%&=?/_.-]+$/.test(i))break;o+=i}}return{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,promptId:`cursor:signin-link:${(o.match(/[?&]challenge=([\w-]+)/)||[])[1]?.slice(0,16)||o.slice(-24)||"pending"}`,questions:[{question:o?`Cursor is waiting for you to finish signing in: open ${o} on any device and log in. Your login goes straight to cursor.com \u2014 bostrat never sees it. This card clears once sign-in completes.`:"Cursor is waiting for you to finish signing in \u2014 open the login link shown in the Terminal tab. This card clears once sign-in completes.",header:"Sign in",multiSelect:!1,options:[]}]}}function nP(e,t=""){let n=String(e);return!/Scan this QR code to log in/.test(n)||Cf.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 i0(e,t,n=""){if(e!=="cursor"&&e!=="codex")return null;if(e==="codex"){let r=VN(t,n)||YN(t,n)||XN(t,n)||ZN(t,n)||KN(t,n);if(r)return r}if(e==="cursor"){let r=tP(t,n)||nP(t,n)||QN(t,n);if(r)return r}return HN(t,{provider:e,box:n})}function c0(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 UN,r0,wi,a0,o0,GN,zN,s0,JN,Cf,eP,Vl=G(()=>{UN=/^\s*[›>*\-❯]?\s*(\d+)[.)]\s+(.+?)\s*$/,r0=/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i;wi=/(^|\n)\s*›/,a0=/^\s*Welcome to Codex\b/;o0=/^\s*(>)?\s*(\d+)\.\s+(.+?)\s*$/;GN=/Successfully logged in\./,zN=/^\s*Press Enter to continue\.\s*$/;s0=/Enter this one-time code/,JN=/^\s*([A-Z0-9]{2,10}-[A-Z0-9]{2,10})\s*$/;Cf=/Run Everything|Add a follow-up|Plan, search, build anything/;eP=/click this link to log in|Signing in with the browser/});function aP(e){let t=String(e||"").replace(/\r/g,"").split(`
112
- `),n=-1;for(let c=t.length-1;c>=0;c--)if(t[c].trim()){n=c;break}if(n<0)return!1;let r=t[n];if(oP.test(r)||sP.test(r)){for(let c=n-1;c>=0&&n-c<=64;c--)if(/^\s*›/.test(t[c]))return!0}let s=String(e||""),a=s.split(`
113
- `).filter(c=>/^\s*›/.test(c)),i=a.some(c=>/^\s*›\s+(?:Ask Codex to do anything|Implement \{feature\})\s*$/.test(c));return a.length>0&&!i&&/esc to interrupt|\bWorking \(/.test(s)}function dP(e){let t=String(e||"");if(!Ye.codex.block.test(t))return null;let n=$o(t);if(!Ye.codex.block.test(n))return null;let r=n.match(uP);return{from:r?.[1]||null,to:r?.[2]||null}}function An(e){return new Promise(t=>setTimeout(t,e))}function Nf(e,t){let n=Date.now(),r=pP();for(let[s,a]of Yl)n-a>=r&&Yl.delete(s);let o=`${e}::${t}`;return Yl.has(o)?!1:(Yl.set(o,n),!0)}function p0(e,t){if(e?.busyScope!=="footer")return t;let n=String(t||"").split(`
114
- `),r=-1;for(let o=n.length-1;o>=0;o--)if(d0.test(n[o])){r=o;break}return r<0?t:n.slice(r+1).join(`
115
- `)}function mP(e){let t=0;for(let n of String(e).split(`
116
- `))d0.test(n)&&(t=Math.max(t,n.trimEnd().length));return t}function Pf(e,t){let n=Ye[e];if(!n?.busy)return{state:"idle",reason:null};if(Bf(e,t))return{state:"unknown",reason:"blocked"};if(n.up&&!n.up.test(t))return{state:"idle",reason:null};if(n.busy.test(p0(n,t)))return{state:"busy",reason:null};if(n.busyAlt&&n.busyAlt.test(t))return{state:"busy",reason:null};let r=mP(t);return e==="claude"&&r>0&&r<fP?{state:"unknown",reason:"narrow"}:{state:"idle",reason:null}}function Df(e,t){return Pf(e,t).state}function f0(e,t){if(e!=="claude")return!1;let n=String(t||"").split(`
117
- `).slice(-wP).join(`
118
- `);return hP.test(n)}function Cs(e,t){return Df(e,t)==="busy"}function gi(e,t){return Df(e,t)!=="idle"}function Ns(e,t){let n=Ye[e];return n?.up?n.up.test(t):!0}function gP(e,t){let n=Ye[e];return n?Bf(e,t)?!1:n.up.test(t)&&Df(e,t)==="idle":!0}function Bf(e,t){let n=Ye[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 jf(e,t){let n=String(t||"").trim();if(!n)return e;let r=String(e||"").split(`
85
+ `});import{execFile as Ck}from"node:child_process";import{promisify as JC}from"node:util";import Hl from"node:fs";import{randomUUID as Nk}from"node:crypto";function $o(e){return new Promise(t=>setTimeout(t,e))}function Ul(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 Pk(e){return`/tmp/tmux-${e}/default`}function YC({explicit:e,legacyExists:t,runtimeDir:n,uid:r}){if(e)return e;let o=Pk(r);return t?o:n?`${n}/bostrat/tmux-default`:o}function mi(){return process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1"?[]:["-e",`${fi}=1`]}function hi(e,t,n){let r=Ro(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&&De(n)&&(s+=` --name ${n}`),s}function Ro(e){return/(^|\/|\s)claude(\s|$)/.test(String(e||""))}function Nr(e){return/(^|\/|\s)claude(\s|$)/.test(e)?"claude":/cursor/.test(e)?"cursor":/codex/.test(e)?"codex":/gemini/.test(e)?"gemini":"agent"}function QC(e){let t=String(e||"").trim();return!t||/fake-|\.sh(\s|$)/.test(t)?!1:Ro(t)||/(^|\/|\s)codex(\s|$)/.test(t)||/cursor-agent/.test(t)||/(^|\/|\s)gemini(\s|$)/.test(t)}async function Dk(e,{loginShell:t=!1,failOpen:n=!1}={}){let r=await Bk(e,{loginShell:t});return r===Wl?!0:r===Ds?!1:n}async function Bk(e,{loginShell:t=!1,timeoutMs:n=Tf}={}){if(!e)return Ds;let r=t?process.env.SHELL||"/bin/sh":"sh",o=t?"-lic":"-c";try{return await $e(r,[o,'command -v "$1" >/dev/null 2>&1',"_",e],{timeout:n}),Wl}catch(s){return s?.killed||s?.signal?Bs:s?.code===1||s?.code===127?Ds:Bs}}async function ql(e,{retries:t=eN,sleep:n=tN,probe:r=Bk}={}){let o=String(e||"").trim().split(/\s+/)[0],s=await r(o,{timeoutMs:Tf});for(let a=0;s===Bs&&a<t.length;a++)await n(t[a]),s=await r(o,{timeoutMs:Tf*2});return s}function ne(...e){return["-S",Dt,...e]}async function Pr(){if(!Hl.existsSync(Dt))return!1;try{return await $e(ee,ne("list-sessions")),!0}catch(e){let t=e&&e.stderr?String(e.stderr):"";return!/no server running/i.test(t)}}async function wi(){if(await Pr())return!0;try{Hl.mkdirSync(Dt.replace(/\/[^/]+$/,""),{recursive:!0}),await $e(ee,ne("new-session","-d","-s","keeper","sleep 2147483647"))}catch{}return await Pr()}function De(e){return typeof e=="string"&&nN.test(e)}async function on(){if(!Hl.existsSync(Dt))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 $e(ee,ne("list-sessions","-F",e)),n=Date.now();return t.trim().split(`
86
+ `).filter(Boolean).map(r=>{let[o,s,a,i,c,l,u,d,p,f,w]=r.split("|"),m=Number(i),g=Number(w);return{name:o,title:u||null,windows:Number(s),attached:Number(a),lastActivityMs:Number.isFinite(m)?n-m*1e3:null,cwd:c||null,isBostrat:l==="1",sessionId:d||null,agent:p||(l==="1"?"claude":null),alternateOn:f==="1",createdMs:Number.isFinite(g)&&g>0?g*1e3:null}}).filter(r=>!ZC.has(r.name)&&!r.name.startsWith("bostrat-view-"))}catch{return[]}}async function be(e){return(await on()).find(n=>n.name===e)||null}function sN(e){if(typeof e!="string")return!1;let t=e.trim();return t.length>=1&&t.length<=oN&&rN.test(t)}function Kl(e){return e.trim().replace(/\s+/g,"-").toLowerCase().replace(/[^A-Za-z0-9_.-]/g,"").replace(/^-+|-+$/g,"")}async function jk(e){try{let{stdout:t}=await $e(ee,ne("list-sessions","-F","#{session_name}"));return t.split(`
87
+ `).map(n=>n.trim()).includes(e)}catch{return!1}}function cN(e){let t=String(e||"").trim().split(/\s+/)[0]||"";if(t.includes("/"))return null;let n=[],r=s=>/[A-Za-z0-9_]/.test(s);for(let s=1;s<=t.length-3;s++)r(t[s-1])===r(t[s])&&n.push(t.slice(s));if(!n.length)return null;let o=n.map(s=>s.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));return new RegExp(`\\b(?:${o.join("|")})`)}async function lN(e,t){let n=Date.now()+gi(),r=cN(t),o=!1,s=0,a=0;for(;;){if(await $o(aN),s+=1,!await jk(e))return;let i=await Pe(e,{lines:15}),c=!o&&iN.test(i)&&!!r?.test(i),l=!o&&!!r?.test(i);if(!c&&!l&&s>1&&!await er(e)){if(a+=1,a>1)return}else c||(a=0);if(c){o=!0,await ue({flow:"spawn",phase:"launch-retry",sessionName:e,agent:Nr(t),promptHead:t.slice(0,120)}).catch(()=>{}),await $e(ee,ne("send-keys","-t",e,"C-u")),await $e(ee,ne("send-keys","-t",e,"-l",t)),await $e(ee,ne("send-keys","-t",e,"Enter"));continue}if(Date.now()>n){await ue({flow:"spawn",phase:"launch-failed",sessionName:e,agent:Nr(t),retried:o,error:"agent CLI never started after launch was typed"}).catch(()=>{});return}}}async function _n(e,t=XC,n={}){if(!sN(e))throw new Error("displayName must be 1\u201364 chars (letters, digits, space . _ -)");let r=e.trim(),o=Kl(r);if(!De(o))throw new Error("resulting tmux session name is invalid");if(!await wi())throw new Error(`host tmux server not running on ${Dt} and auto-start failed \u2014 start one: ${ee} -S ${Dt} new-session -d -s keeper "sleep 2147483647"`);if(await jk(o))throw new Error(`tmux session "${o}" already exists`);let s=n.agentCmd||Ef,a=n.agent||Nr(s),i=!!n.resumeSessionId,c=n.resumeSessionId||Nk(),l=i?s:hi(s,c,o),u=i?n.pinned===!0:/(^|\s)--session-id(\s|=)/.test(l),d=a==="claude"&&Ro(s),p=n.firstRun===!0;p||(d&&await _r(t),a==="codex"&&await Es(t),a==="cursor"&&await _s(t),await ak(t),n.freshWorkspace!==!0&&await Bl(t));let f=d&&!p?gl():null,w=Eb(),m=["-e",`${Yn}=${w}`];m.push(...Rk({nodeUrl:Ok()})),f&&m.push("-e",`ANTHROPIC_API_KEY=${f}`),d&&m.push(...mi());try{await $e(ee,ne("new-session","-d","-s",o,"-c",t,...m))}catch(g){throw Ul(f?Ul(g,f):g,w)}return await Oo(o),await $e(ee,ne("set-option","-t",o,"@bostrat-session","1")),await $e(ee,ne("set-option","-t",o,"@bostrat-title",r)),await $e(ee,ne("set-option","-t",o,"@bostrat-sid",c)),await $e(ee,ne("set-option","-t",o,"@bostrat-agent",a)),await $e(ee,ne("send-keys","-t",o,l,"Enter")),QC(l)&&lN(o,l).catch(()=>{}),{name:o,title:r,cwd:t,sessionId:c,agent:a,pinned:u,hookToken:w}}async function $t(e){if(!De(e))throw new Error("invalid session name");await $e(ee,ne("kill-session","-t",e))}async function Lk(e,t){if(De(e))try{let n=t?ne("set-option","-t",e,"@bostrat-sid",t):ne("set-option","-u","-t",e,"@bostrat-sid");await $e(ee,n)}catch{}}async function Pe(e,{lines:t=40}={}){if(!De(e))return"";try{let n=ne("capture-pane","-t",e,"-p");Number.isFinite(t)&&t>0&&n.push("-S",`-${Math.floor(t)}`);let{stdout:r}=await $e(ee,n);return String(r||"")}catch{return""}}async function Fk(e){if(!De(e))return[];try{let{stdout:t}=await $e(ee,ne("list-panes","-s","-t",e,"-F","#{pane_pid}"));return String(t||"").trim().split(`
88
+ `).map(n=>Number(n.trim())).filter(n=>Number.isFinite(n)&&n>0)}catch{return[]}}async function Uk(e){if(!De(e))return 0;try{let{stdout:t}=await $e(ee,ne("list-clients","-t",e,"-F","1"));return String(t||"").trim().split(`
89
+ `).filter(Boolean).length}catch{return 0}}async function Oo(e,{cols:t=pN,rows:n=fN}={}){if(!De(e))return!0;if(await Uk(e))return!1;try{let r=await Hk(e);if(r.cols===t&&r.rows===n)return!0;await $e(ee,ne("resize-window","-t",e,"-x",String(t),"-y",String(n))),await $e(ee,ne("set-window-option","-t",e,"window-size","latest")),await $o(80)}catch{}return!0}async function mN(e){if(!De(e))return 0;try{let{stdout:t}=await $e(ee,ne("display-message","-t",e,"-p","#{pane_pid}"));return Number(String(t||"").trim())||0}catch{return 0}}async function er(e){let t=await mN(e);if(!t)return!1;try{return await $e("pgrep",["-P",String(t)]),!1}catch(n){return n?.code===1}}async function Hk(e){if(!De(e))return{cols:0,rows:0};try{let{stdout:t}=await $e(ee,ne("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 Gl(e,{cols:t=uN,rows:n=dN}={}){if(De(e)&&!await Uk(e))try{let r=await Hk(e),o=Math.max(r.cols,t),s=Math.max(r.rows,n);(o>r.cols||s>r.rows)&&(await $e(ee,ne("resize-window","-t",e,"-x",String(o),"-y",String(s))),await $e(ee,ne("set-window-option","-t",e,"window-size","latest")),await $o(80))}catch{}}async function sn(e){return await Gl(e),Pe(e,{lines:Ye})}async function qe(e,t,{settleMs:n=40,kind:r}={}){if(!De(e))throw new Error("invalid session name");let o=(Array.isArray(t)?t:[t]).filter(s=>Wk.has(s));for(let s=0;s<o.length;s++)await $e(ee,ne("send-keys","-t",e,o[s])),n>0&&s<o.length-1&&await $o(n);return ue({flow:"tmux",phase:"send-keys",sessionName:e,kind:r||"keys",keys:o.join(" ")}).catch(()=>{}),o.length}async function $f(e,t,{settleMs:n=40,kind:r}={}){if(!De(e))throw new Error("invalid session name");let o=(Array.isArray(t)?t:[]).filter(s=>s&&(typeof s.key=="string"&&Wk.has(s.key)||typeof s.text=="string"&&s.text.length>0));for(let s=0;s<o.length;s++){let a=o[s];a.text!=null?await $e(ee,ne("send-keys","-t",e,"-l",a.text)):await $e(ee,ne("send-keys","-t",e,a.key)),n>0&&s<o.length-1&&await $o(n)}return ue({flow:"tmux",phase:"send-sequence",sessionName:e,kind:r||"sequence",steps:o.map(s=>s.text!=null?`\u2039text:${s.text.length}\u203A`:s.key).join(" ")}).catch(()=>{}),o.length}async function js(e,t,{kind:n}={}){if(!De(e))throw new Error("invalid session name");let r=Math.max(0,Math.floor(Number(t)||0));return r>0&&await $e(ee,ne("send-keys","-t",e,"-N",String(r),"BSpace")),ue({flow:"tmux",phase:"send-keys",sessionName:e,kind:n||"wipe",keys:`BSpace x${r}`}).catch(()=>{}),r}async function Vl(e,t,{perCharDelayMs:n=120,kind:r}={}){if(!De(e))throw new Error("invalid session name");let o=[...String(t)];for(let s of o)await $e(ee,ne("send-keys","-t",e,"-l",s)),n>0&&await $o(n);ue({flow:"tmux",phase:"type",sessionName:e,kind:r||"type",textLen:o.length,textHead:String(t).slice(0,120)}).catch(()=>{})}function hN(e,t){return new Promise((n,r)=>{let o=Ck(ee,ne(...e),(s,a,i)=>{s?r(s):n({stdout:a,stderr:i})});o.stdin.on("error",()=>{}),o.stdin.end(t)})}async function wN(e,t){let n=`bostrat-${Nk().slice(0,8)}`;await hN(["load-buffer","-b",n,"-"],t),await $e(ee,ne("paste-buffer","-p","-d","-b",n,"-t",e))}async function ot(e,t,{enter:n=!0,submitDelayMs:r=0,kind:o,paste:s=!1}={}){if(!De(e))throw new Error("invalid session name");if(typeof t=="string"&&t.length>0&&(s?await wN(e,t):await $e(ee,ne("send-keys","-t",e,"-l",t))),n){let a=Number(r);Number.isFinite(a)&&a>0&&await $o(a),await $e(ee,ne("send-keys","-t",e,"Enter"))}ue({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 $e,ee,Mk,Dt,XC,Ef,fi,_f,ZC,Wl,Ds,Bs,Tf,eN,tN,If,nN,rN,oN,gi,aN,iN,uN,dN,Ye,pN,fN,Wk,zl,ct=G(()=>{Za();bl();kl();si();jl();En();Ts();Af();$e=JC(Ck);ee=process.env.BOSTRAT_TMUX_BIN||"/usr/bin/tmux";Mk=typeof process.getuid=="function"?process.getuid():0,Dt=YC({explicit:process.env.BOSTRAT_TMUX_SOCKET,legacyExists:(()=>{try{return Hl.existsSync(Pk(Mk))}catch{return!1}})(),runtimeDir:process.env.XDG_RUNTIME_DIR,uid:Mk}),XC=process.env.BOSTRAT_DEFAULT_CWD||process.env.HOME||"/",Ef=process.env.BOSTRAT_AGENT_CMD||"claude --dangerously-skip-permissions",fi="CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN";_f="bostrat-usage-probe",ZC=new Set([_f]);Wl="present",Ds="absent",Bs="unknown",Tf=5e3,eN=[250,1e3,3e3],tN=e=>new Promise(t=>setTimeout(t,e));If={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"};nN=/^[A-Za-z0-9_.-]{1,64}$/;rN=/^[A-Za-z0-9 ._↻-]+$/,oN=64;gi=()=>Number(process.env.BOSTRAT_LAUNCH_VERIFY_MS)||12e3,aN=1e3,iN=/not found|Unknown command/i;uN=Number(process.env.BOSTRAT_PROMPT_CAPTURE_COLS)||100,dN=Number(process.env.BOSTRAT_PROMPT_CAPTURE_ROWS)||40,Ye=Number(process.env.BOSTRAT_PROMPT_CAPTURE_LINES)||80,pN=Number(process.env.BOSTRAT_BOX_COLS)||120,fN=Number(process.env.BOSTRAT_BOX_ROWS)||40;Wk=new Set(["Up","Down","Left","Right","Space","Enter","Tab","BTab","Escape","BSpace"]);zl=1600});import yi from"node:fs";import vN from"node:fs/promises";import Ls from"node:path";import SN from"node:os";function Mf(e){return e.replace(/[^A-Za-z0-9]/g,"-")}function Cf(e){let t=Ls.join(Of,Mf(e)),n;try{n=yi.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return null}let r=null;for(let o of n){let s=Ls.join(t,o);try{let{mtimeMs:a}=yi.statSync(s);(!r||a>r.mtimeMs)&&(r={full:s,mtimeMs:a})}catch{}}return r?r.full:null}function an(e,t){if(!t)return null;let n=Ls.join(Of,Mf(e),`${t}.jsonl`);return yi.existsSync(n)?n:null}function Yk(e){if(!e)return[];let t=Ls.join(Of,Mf(e)),n;try{n=yi.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return[]}let r=[];for(let o of n)try{let s=yi.statSync(Ls.join(t,o));r.push({id:o.slice(0,-6),birthMs:s.birthtimeMs||s.ctimeMs||s.mtimeMs})}catch{}return r}async function Rt(e,t=131072){let n=await vN.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 TN(e){let t=e.split(`
90
+ `);for(let n=t.length-1;n>=0;n--){let r=t[n].trim();if(!r||r[0]!=="{")continue;let o;try{o=JSON.parse(r)}catch{continue}let s=o?.message?.usage;if(!s)continue;let a=(s.input_tokens||0)+(s.cache_creation_input_tokens||0)+(s.cache_read_input_tokens||0);if(a>0)return{occupancy:a,model:o.message.model||o.model||null}}return null}async function bi(e,t=null,{fallbackNewest:n=!0}={}){if(!e)return null;let r,o;if(t){if(r=an(e,t),o=!0,!r)return null}else if(n){if(r=Cf(e),o=!1,!r)return null}else return null;let s;try{s=TN(await Rt(r))}catch{return null}if(!s)return null;let a=Object.prototype.hasOwnProperty.call(Jk,s.model),i=Jk[s.model]||AN;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 Jk,AN,Of,cn=G(()=>{Jk={"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},AN=2e5,Of=process.env.BOSTRAT_CLAUDE_PROJECTS||Ls.join(SN.homedir(),".claude","projects")});function EN(e){let t=[],n="",r=null;for(let o=0;o<e.length;o++){let s=e[o];if(r){n+=s,s===r&&e[o-1]!=="\\"&&(r=null);continue}if(s==="'"||s==='"'||s==="`"){r=s,n+=s;continue}if(s==="&"&&e[o+1]==="&"){t.push(n),n="",o++;continue}if(s==="|"&&e[o+1]==="|"){t.push(n),n="",o++;continue}if(s==="|"||s===";"||s===`
91
+ `){t.push(n),n="";continue}n+=s}return t.push(n),t.map(o=>o.trim()).filter(Boolean)}function ki(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 xi(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 Be(e,t=new Set){let n=[];for(let r=1;r<e.length;r++){let o=e[r];if(o==="<<")break;if(Qk(o)){t.has(o)&&r++;continue}n.push(o)}return n}function e0(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 $N(e){let t=e0(e),n=mt(Be(e).find(r=>!/^\d+(,\d+)?p$/.test(r)));return t&&n?t.from===t.to?`Read line ${t.from} of ${ze(n)}`:`Read lines ${t.from}\u2013${t.to} of ${ze(n)}`:e.includes("-i")&&n?`Edit ${ze(n)}`:null}function Nf(e){if(e.includes("--files")){let s=mt(Be(e,Xk)[0]);return s&&s!=="."?`List files in ${Fs(s)}`:"List files"}let t=Be(e,Xk),n=t[0];if(!n)return null;let r=mt(t.slice(1).find(s=>s!==".")),o=Us(n,40);return r?`Search for \u201C${o}\u201D in ${Fs(r)}`:`Search for \u201C${o}\u201D`}function Pf(e){let t=Be(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 Df(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=Be(e)[0];return n?`Run ${ze(n)}`:null}function RN(e){let t=Be(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 Zk(e){return e.find(t=>/^https?:\/\//.test(t))||null}function CN(e){let t=xi(ki(e));if(!t.length)return null;if(/^(ba|z)?sh$/.test(ze(t[0]))&&(t[1]==="-lc"||t[1]==="-c")&&t[2])return Bf(t[2]);let n=ze(t[0]);if(MN.has(n))return null;if(t.includes("--version"))return`Check ${n} version`;if(n.endsWith(".sh"))return`Run ${n}`;let r=ON[n];return r?r(t.map((o,s)=>s===0?n:o)):null}function Bf(e){let t=String(e||"").trim();if(!t)return null;let n=t.indexOf("<<");if(n!==-1){let i=t.indexOf(`
92
+ `,n);i!==-1&&(t=t.slice(0,i))}let r=EN(t);for(let i=0;i<r.length-1;i++){let c=xi(ki(r[i])),l=xi(ki(r[i+1]));if(!(!c.length||!l.length)&&["nl","cat"].includes(ze(c[0]))&&ze(l[0])==="sed"){let u=e0(l),d=Be(c)[0];if(u&&d)return Us(u.from===u.to?`Read line ${u.from} of ${ze(d)}`:`Read lines ${u.from}\u2013${u.to} of ${ze(d)}`,88)}}let o=[];for(let i of r){let c=CN(i);c&&o.push({d:c,head:ze(xi(ki(i))[0]||""),sub:Be(xi(ki(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":Us(s?s.d:o[0].d,88)}var Us,mt,ze,Fs,Qk,Xk,_N,IN,ON,MN,t0=G(()=>{Us=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,mt=e=>e&&!/[$`]/.test(e)?e:null,ze=e=>e.replace(/\/+$/,"").split("/").pop()||e,Fs=e=>{let t=e.replace(/\/+$/,"").split("/").filter(Boolean);return t.length>3?t.slice(-2).join("/"):e},Qk=e=>e.startsWith("-"),Xk=new Set(["-g","--glob","-t","--type","-A","-B","-C","-m","--max-count","-e","--regexp","-f","--file"]);_N={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 ${ze(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"},IN={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"};ON={git:e=>{let t=Be(e,new Set(["-C","-c"])),n=_N[t[0]];return n?n(t,e):null},gh:e=>{let t=Be(e),n=IN[t[0]];return n?n(t):null},sed:$N,rg:Nf,grep:Nf,egrep:Nf,nl:e=>{let t=mt(Be(e)[0]);return t?`Read ${ze(t)}`:null},cat:e=>{let t=mt(Be(e)[0]);return t?`Read ${ze(t)}`:null},head:e=>{let t=mt(Be(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the start of ${ze(t)}`:null},tail:e=>{let t=mt(Be(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the end of ${ze(t)}`:null},wc:e=>{let t=mt(Be(e)[0]);return t?`Count lines in ${ze(t)}`:"Count input lines"},ls:e=>{let t=mt(Be(e)[0]);return t&&t!=="."?`List files in ${Fs(t)}`:"List files"},find:e=>mt(e[1])&&!Qk(e[1])&&e[1]!=="."?`Find files in ${Fs(e[1])}`:"Find files",tree:()=>"List the directory tree",mkdir:e=>{let t=mt(Be(e)[0]);return t?`Create directory ${Fs(t)}`:null},touch:e=>{let t=mt(Be(e)[0]);return t?`Create ${ze(t)}`:null},rm:e=>{let t=mt(Be(e)[0]);return t?`Delete ${Fs(t)}`:null},mv:e=>{let t=mt(Be(e)[0]);return t?`Move ${ze(t)}`:null},cp:e=>{let t=mt(Be(e)[0]);return t?`Copy ${ze(t)}`:null},chmod:e=>{let t=mt(Be(e)[1]);return t?`Change permissions on ${ze(t)}`:null},diff:e=>{let t=Be(e);return t.length>=2?`Compare ${ze(t[0])} and ${ze(t[1])}`:null},curl:e=>{let t=Zk(e);return t?`Fetch ${Us(t,56)}`:"Fetch a URL"},wget:e=>{let t=Zk(e);return t?`Fetch ${Us(t,56)}`:"Fetch a URL"},npm:Pf,pnpm:Pf,yarn:Pf,npx:e=>{let t=Be(e)[0];return t?`Run ${t}`:null},node:e=>Df(e,"Node"),python:e=>Df(e,"Python"),python3:e=>Df(e,"Python"),make:e=>{let t=Be(e)[0];return t?`Run make ${t}`:"Run make"},systemctl:RN,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=Be(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=Be(e)[0];return t?`Locate ${t}`:null},command:e=>e[1]==="-v"&&e[2]?`Locate ${e[2]}`:null,fly:e=>{let t=Be(e)[0];return t==="deploy"?"Deploy to Fly":t?`Run fly ${t}`:null}},MN=new Set(["pwd","echo","cd","sleep","true","false","test","[","set","export","exit","read"])});function Hs(e){let t=e.split(`
93
+ `).map(n=>n.trim()).find(Boolean)||e;return t.length>88?`${t.slice(0,88).trimEnd()}\u2026`:t}function Dr(e,t=""){let n=t.trim();return n||Bf(e)||Hs(e)}function jf(e,t){if(e){if(Array.isArray(e)){for(let n of e)jf(n,t);return}if(typeof e=="object"){if(e.type==="tool_use"&&Lf.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))jf(n,t)}}}async function n0(e,{maxBytes:t=1048576,limit:n=400}={}){let r;try{r=await Rt(e,t)}catch{return[]}let o=[];for(let s of r.split(`
94
+ `)){let a=s.trim();if(!a||a[0]!=="{")continue;let i;try{i=JSON.parse(a)}catch{continue}let c=i.message;if(!c)continue;let l=[];if(jf(c.content,l),!l.length)continue;let u=i.timestamp?Date.parse(i.timestamp):null;for(let d of l)o.push({...d,summary:Dr(d.command,d.description),ts:u})}return o.slice(-n)}function r0(e,t){let n=a=>a?.box??null,r=new Map;for(let a of t||[]){if(a.role!=="assistant"||!(a.text||"").trim())continue;let i=n(a);r.has(i)||r.set(i,[]),r.get(i).push(a)}let o=new Map;for(let a of e||[]){let i=n(a);o.has(i)||o.set(i,[]),o.get(i).push(a)}let s=[];for(let[a,i]of o)s.push(...NN(i,r.get(a)||[]));return s.sort((a,i)=>(a.ts||0)-(i.ts||0))}function NN(e,t){let n=[...t].sort((l,u)=>(l.ts||0)-(u.ts||0)),r=[...e].sort((l,u)=>(l.ts||0)-(u.ts||0)),o=[],s=0,a=0,i=l=>{let u=l.n??a+1;return u>a&&(a=u),u};for(let l of n){let u=r.findIndex((w,m)=>m>=s&&(w.ts||0)>(l.ts||0)),d=u===-1?r.length:u,p=r.slice(s,d);if(s=d,!p.length)continue;let f=p.map(w=>({...w,n:i(w)}));o.push({id:`batch-${l.ts}-${l.box}`,anchorTs:l.ts,anchorBox:l.box,agent:l.agent,boxRole:l.boxRole,commands:f,ts:Math.max(...f.map(w=>w.ts||0)),pending:!1})}let c=r.slice(s);if(c.length){let l=c.map(u=>({...u,n:i(u)}));o.push({id:`batch-pending-${l[0]?.box||"lead"}`,anchorTs:null,anchorBox:l[l.length-1]?.box??null,agent:l[l.length-1]?.agent??"claude",boxRole:l[l.length-1]?.boxRole??"lead",commands:l,ts:Math.max(...l.map(u=>u.ts||0)),pending:!0})}return o}var Lf,Ws=G(()=>{cn();t0();Lf=new Set(["Bash"])});import o0 from"node:fs";import Uf from"node:fs/promises";import Ff from"node:path";import PN from"node:os";async function s0(e){try{return await Uf.realpath(e)}catch{return e}}function BN(e=DN){let t=[],n=r=>{let o;try{o=o0.readdirSync(r,{withFileTypes:!0})}catch{return}for(let s of o){let a=Ff.join(r,s.name);if(s.isDirectory())n(a);else if(s.isFile()&&s.name.startsWith("rollout-")&&s.name.endsWith(".jsonl")){let i=/-([0-9a-f-]{36})\.jsonl$/i.exec(s.name);try{t.push({id:i?i[1]:null,file:a,mtimeMs:o0.statSync(a).mtimeMs})}catch{}}}};return n(e),t.sort((r,o)=>o.mtimeMs-r.mtimeMs)}async function jN(e,t=1048576){let n;try{n=await Uf.open(e,"r")}catch{return""}try{let r=Buffer.alloc(Math.min(t,65536)),o="",s=0;for(;;){let{bytesRead:a}=await n.read(r,0,r.length,s);if(!a)break;o+=r.toString("utf8",0,a);let i=o.indexOf(`
95
+ `);if(i!==-1)return o.slice(0,i);if(s+=a,o.length>=t)break}return o}finally{await n.close()}}async function LN(e){let t=await jN(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 Mo(e,t){if(!e&&!t)return null;let n=BN();if(t){let o=n.find(s=>s.id===t);return o||null}let r=await s0(e);for(let o of n){let s=await LN(o.file);if(s&&(s===e||await s0(s)===r))return o}return null}async function a0(e,t,{limit:n=80,maxBytes:r=524288}={}){let o=await Mo(e,t);if(!o)return[];let s;try{s=await Rt(o.file,r)}catch{return[]}let a=[],i=null,c=[],l=!1,u=!1,d=null;for(let p of s.split(`
96
+ `)){let f=p.trim();if(!f||f[0]!=="{")continue;let w;try{w=JSON.parse(f)}catch{continue}if((w.type==="turn_context"&&w.payload?.model||w.type==="session_meta"&&w.payload?.model)&&(i=w.payload.model),w.type==="event_msg"){let x=w.payload?.type;x==="task_started"?(l=!0,u=!1,d=w.payload?.turn_id||null):x==="task_complete"&&l&&(l=!1,!u&&w.payload?.last_agent_message==null&&a.push({role:"assistant",failed:!0,text:Co,sourceId:w.payload?.turn_id||d||void 0,ts:w.timestamp?Date.parse(w.timestamp):null,model:i}));continue}if(w.type!=="response_item")continue;let m=w.payload;if(!m)continue;if((m.type==="function_call"||m.type==="custom_tool_call")&&m.name){u=!0,Hf.has(m.name)||c.push(m.name);continue}if(m.type!=="message"||m.role!=="assistant")continue;u=!0;let g=UN(m.content),y=c.length?c.slice():null;c=[],!(!g&&!y)&&a.push({role:"assistant",text:g,tools:y||void 0,ts:w.timestamp?Date.parse(w.timestamp):null,model:i})}if(i)for(let p of a)p.model||(p.model=i);return a.slice(-n)}function HN(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 WN(e){let t=e[0];if(t!=='"'&&t!=="'"&&t!=="`")return null;let n="";for(let r=1;r<e.length;r++){let o=e[r];if(o==="\\"){let s=e[++r];if(s===void 0)return null;if(s==="n")n+=`
97
+ `;else if(s==="t")n+=" ";else if(s==="r")n+="\r";else if(s==="u")if(e[r+1]==="{"){let a=e.indexOf("}",r+2);if(a===-1)return null;n+=String.fromCodePoint(parseInt(e.slice(r+2,a),16)),r=a}else n+=String.fromCharCode(parseInt(e.slice(r+1,r+5),16)),r+=4;else n+=s}else{if(o===t)return n;if(t==="`"&&o==="$"&&e[r+1]==="{")return null;n+=o}}return null}function qN(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=WN(i.slice(c.index+c[0].length).trimStart());l&&l.trim()&&o.push(l.trim())}),o}async function i0(e,t,{limit:n=400,maxBytes:r=524288}={}){let o=await Mo(e,t);if(!o)return[];let s;try{s=await Rt(o.file,r)}catch{return[]}let a=[];for(let i of s.split(`
98
+ `)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.type!=="response_item")continue;let u=l.payload;if(!u)continue;let d=[];if(u.type==="function_call"&&vi.has(u.name)){let f;try{f=JSON.parse(u.arguments||"{}")}catch{continue}let w=HN(f);w&&(d=[w])}else u.type==="custom_tool_call"&&u.name==="exec"&&(d=qN(u.input));if(!d.length)continue;let p=u.call_id||u.id||null;d.forEach((f,w)=>{a.push({id:p?w?`${p}:${w}`:p:null,tool:u.name,command:f,description:"",summary:Dr(f),ts:l.timestamp?Date.parse(l.timestamp):null})})}return a.slice(-n)}async function c0(e,t){let n=await Mo(e,t);if(!n)return null;try{return Math.round((await Uf.stat(n.file)).mtimeMs)}catch{return n.mtimeMs||null}}var DN,FN,UN,vi,Hf,Co,No=G(()=>{cn();Ws();DN=process.env.BOSTRAT_CODEX_SESSIONS||Ff.join(process.env.CODEX_HOME||Ff.join(PN.homedir(),".codex"),"sessions");FN=new Set(["output_text","text"]),UN=e=>typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&typeof t.text=="string"&&FN.has(t.type)).map(t=>t.text).join(`
99
+ `).trim():"";vi=new Set(["exec_command","shell","exec"]),Hf=new Set(["wait","write_stdin"]),Co="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 Si({error:e=null,status:t=null,text:n=""}={}){let r=String(e||"").trim().toLowerCase();if(r&&l0.has(r))return l0.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 u0(e){if(!e||e.role!=="assistant")return null;if(e.apiError){let t=e.apiError;return{cls:t.cls||Si({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===Co?"other":Si({text:t}),code:null,status:null,requestId:null}}return null}function d0(e,{codexFailedText:t=null}={}){let n=String(e?.text||"").trim();return n?e?.model==="<synthetic>"?/^No response requested\.$/.test(n)?null:{cls:Si({text:n}),code:null,status:KN(n),requestId:null,text:n}:t&&n===t?{cls:"other",code:null,status:null,requestId:null,text:n}:null:null}function KN(e){let t=/^API Error:\s*(\d{3})\b/.exec(e);return t?Number(t[1]):null}var zz,l0,Yl=G(()=>{No();zz=Object.freeze(["entitlement","auth","rate_limit","overloaded","server","other"]),l0=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 GN(e,t){return!e||!t?null:an(e,t)}function zN(e){return typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&t.type==="text"&&typeof t.text=="string").map(t=>t.text).join(`
100
+ `).trim():""}function VN(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 JN(e){return Array.isArray(e)&&e.length>0&&e.every(t=>t&&t.type==="tool_result")}function Wf(e){let t=[],n=e?.message?.content;if(!Array.isArray(n))return t;for(let r of n)if(r){if(r.type==="image"&&r.source?.type==="base64"&&r.source.data)t.push({mediaType:r.source.media_type||"image/png",data:r.source.data,toolUseId:null});else if(r.type==="tool_result"&&Array.isArray(r.content))for(let o of r.content)o?.type==="image"&&o.source?.type==="base64"&&o.source.data&&t.push({mediaType:o.source.media_type||"image/png",data:o.source.data,toolUseId:r.tool_use_id||null})}return t}function p0(e,t){if(!e.uuid)return null;let n=Wf(e).map((r,o)=>({uuid:e.uuid,index:o,mediaType:r.mediaType,name:r.toolUseId&&t.get(r.toolUseId)||null}));return n.length?n:null}async function qf(e,{maxBytes:t=524288,limit:n=80}={}){let r;try{r=await Rt(e,t)}catch{return[]}let o=[],s=new Map,a=new Map;for(let i of r.split(`
101
+ `)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.type==="attachment"){let y=l.attachment;y?.type==="queued_command"&&y.commandMode==="task-notification"&&typeof y.prompt=="string"&&y.prompt.trim()&&o.push({role:"user",text:y.prompt.trim(),ts:l.timestamp?Date.parse(l.timestamp):null,model:null});continue}let u=l.message;if(!u)continue;let d=u.role||l.type;if(d!=="user"&&d!=="assistant"||d==="assistant"&&u.model==="<synthetic>"&&!l.isApiErrorMessage)continue;if(d==="assistant"&&Array.isArray(u.content))for(let y of u.content){let x=y?.type==="tool_use"?y.input?.file_path||y.input?.path:null;typeof x=="string"&&YN.test(x)&&s.set(y.id,x.split("/").pop()),y?.type==="tool_use"&&y.name==="Skill"&&y.id&&a.set(y.id,String(y.input?.skill||"").trim().replace(/^\//,"")||null)}if(JN(u.content)){let y=p0(l,s);y&&o.push({role:"assistant",text:"",images:y,ts:l.timestamp?Date.parse(l.timestamp):null,model:null});continue}let p=zN(u.content),f=d==="assistant"?VN(u.content):null,w=d==="user"?p0(l,s):null;if(!p&&!f&&!w)continue;let m=d==="user"&&l.isMeta&&typeof l.sourceToolUseID=="string"&&l.sourceToolUseID?{toolUseId:l.sourceToolUseID,skill:a.get(l.sourceToolUseID)??null}:null,g=d==="assistant"&&l.isApiErrorMessage?{code:typeof l.error=="string"?l.error:null,status:Number(l.apiErrorStatus)||null,requestId:l.requestId||null,cls:Si({error:l.error,status:l.apiErrorStatus,text:p})}:null;o.push({role:d,text:p,tools:f||void 0,images:w||void 0,injected:m||void 0,ts:l.timestamp?Date.parse(l.timestamp):null,model:u.model||null,apiError:g||void 0})}return o.slice(-n)}async function f0(e,t,{turns:n=16}={}){let r=GN(e,t);if(!r)return"";let o=await qf(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}:** ${XN(s.text||c,700)} ${i}`.trim()}).join(`
102
+
103
+ `):""}var YN,XN,Xl=G(()=>{Yl();cn();YN=/\.(png|jpe?g|gif|webp|bmp|svg|tiff?|avif|heic|heif|ico)$/i;XN=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e});import ZN from"node:fs/promises";import{execFile as QN}from"node:child_process";import{promisify as eP}from"node:util";function g0(e){Gf=typeof e=="function"?e:null}function zf(e){let t=String(e||""),n=t.indexOf("/lib/node_modules/");return n>0?t.slice(0,n):null}function y0({sessionName:e,from:t,to:n}={}){let r=String(n||"").trim();!r||m0.has(r)||(m0.add(r),h0=h0.then(()=>nP({sessionName:e,from:t,to:r})).catch(()=>{}))}async function nP({sessionName:e,from:t,to:n}){await ue({flow:"codex-update",phase:"start",sessionName:e,from:t,to:n}).catch(()=>{});try{let r=(await Kf("/bin/sh",["-c","command -v codex"])).stdout.trim();if(!r)throw new Error("codex not on PATH");let o=await ZN.realpath(r),s=zf(o),a=s?{...process.env,PATH:`${s}/bin:${process.env.PATH||""}`}:process.env;await Kf("npm",["install","-g","@openai/codex"],{env:a,timeout:tP});let i=(await Kf(r,["--version"])).stdout.trim().replace(/^codex-cli\s*/,"")||n;await ue({flow:"codex-update",phase:"done",sessionName:e,from:t,to:n,version:i}).catch(()=>{}),await w0({sessionName:e,from:t,to:n,version:i,status:"updated"})}catch(r){let o=String(r?.message||r).slice(0,300);await ue({flow:"codex-update",phase:"failed",sessionName:e,from:t,to:n,error:o}).catch(()=>{}),await w0({sessionName:e,from:t,to:n,status:"failed",error:o})}}async function w0(e){if(Gf)try{await Gf(e)}catch{}}var Kf,tP,m0,h0,Gf,Zl=G(()=>{En();Kf=eP(QN),tP=Number(process.env.BOSTRAT_CODEX_UPDATE_TIMEOUT_MS)||5*6e4,m0=new Set,h0=Promise.resolve(),Gf=null});function oP(e,{provider:t,box:n}){let r=String(e).replace(/\r/g,"").split(`
104
+ `);if(!b0.test(e))return null;let o=[],s=!1;for(let l=r.length-1;l>=0;l--){let u=r[l].match(rP);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"&&b0.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(`
105
+ `);for(let r=n.length-1;r>=0;r--)if(v0.test(n[r]))return n.slice(r).join(`
106
+ `);return t}function sP(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 aP(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 iP(e,t=""){let n=Br(e);if(Ai.test(n)||!/Sign in with ChatGPT/.test(n)||!/Press enter to continue/.test(n))return null;let r=n.split(`
107
+ `),o=[],s=-1;for(let l=0;l<r.length;l++){let u=r[l].match(k0);if(!u)continue;s<0&&(s=l);let d="";for(let p=l+1;p<Math.min(l+3,r.length);p++){let f=r[p].trim();if(f){if(k0.test(r[p])||/^Press enter/.test(f))break;d=f;break}}o.push({n:Number(u[2]),cursor:!!u[1],label:u[3].trim(),desc:d})}let a=o.sort((l,u)=>l.n-u.n);if(a.length<2||a.some((l,u)=>l.n!==u+1)||!a.some(l=>/Sign in with ChatGPT/.test(l.label)))return null;let i=[];for(let l=0;l<s;l++){let u=r[l].trim();u&&!v0.test(r[l])&&sP(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=aP(l.label);return{label:l.label,description:[l.desc,u].filter(Boolean).join(" \xB7 ")}})}]}}function uP(e,t=""){let n=Br(e);if(Ai.test(n)||!cP.test(n))return null;let r=n.trimEnd().split(`
108
+ `).pop()||"";return lP.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 pP(e,t=""){let n=Br(e);if(Ai.test(n)||!x0.test(n))return null;let r=n.split(`
109
+ `),o=r.findIndex(i=>x0.test(i)),s="";for(let i=o+1;i<r.length;i++){let c=r[i].match(dP);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 fP(e,t=""){let n=Br(e);return Ai.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 mP(e,t=""){let n=Br(e);return Ai.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 hP(e,t=""){let n=String(e);if(!/Press any key to log in/.test(n)||Vf.test(n))return null;let r=n.replace(/\r/g,"").split(`
110
+ `).map(a=>a.trim()),o=r.findIndex(a=>/Press any key to log in/.test(a)),s=r.slice(0,o<0?r.length:o).filter(a=>a&&!/^Cursor Agent$/i.test(a)&&!/^v?\d{4}\.\d{2}\.\d{2}/.test(a)).join(" ");return{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,answerMode:"keys",promptId:"cursor:signin-start",questions:[{question:(s?`${s} `:"")+"Cursor isn't signed in on this box \u2014 start the sign-in to get a login link you can open from any device.",header:"Sign in",multiSelect:!1,options:[{label:"Start sign-in",description:"Shows a login link (and a QR option) \u2014 your login goes to cursor.com, never through bostrat"}]}]}}function gP(e,t=""){let n=String(e);if(!wP.test(n)||Vf.test(n))return null;let r=n.replace(/\r/g,"").split(`
111
+ `),o="",s=r.findIndex(a=>/https:\/\//.test(a));if(s>=0){o=r[s].slice(r[s].indexOf("https://")).trim();for(let a=s+1;a<r.length;a++){let i=r[a].trim();if(!i||!/^[A-Za-z0-9~%&=?/_.-]+$/.test(i))break;o+=i}}return{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,promptId:`cursor:signin-link:${(o.match(/[?&]challenge=([\w-]+)/)||[])[1]?.slice(0,16)||o.slice(-24)||"pending"}`,questions:[{question:o?`Cursor is waiting for you to finish signing in: open ${o} on any device and log in. Your login goes straight to cursor.com \u2014 bostrat never sees it. This card clears once sign-in completes.`:"Cursor is waiting for you to finish signing in \u2014 open the login link shown in the Terminal tab. This card clears once sign-in completes.",header:"Sign in",multiSelect:!1,options:[]}]}}function yP(e,t=""){let n=String(e);return!/Scan this QR code to log in/.test(n)||Vf.test(n)?null:{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,promptId:"cursor:signin-qr",questions:[{question:"Cursor is showing a QR sign-in code in the Terminal tab \u2014 scan it from another device to log in. This card clears once sign-in completes.",header:"Sign in",multiSelect:!1,options:[]}]}}function S0(e,t,n=""){if(e!=="cursor"&&e!=="codex")return null;if(e==="codex"){let r=uP(t,n)||pP(t,n)||fP(t,n)||mP(t,n)||iP(t,n);if(r)return r}if(e==="cursor"){let r=gP(t,n)||yP(t,n)||hP(t,n);if(r)return r}return oP(t,{provider:e,box:n})}function A0(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 rP,b0,Ai,v0,k0,cP,lP,x0,dP,Vf,wP,Ql=G(()=>{rP=/^\s*[›>*\-❯]?\s*(\d+)[.)]\s+(.+?)\s*$/,b0=/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i;Ai=/(^|\n)\s*›/,v0=/^\s*Welcome to Codex\b|^\s*(?:│\s*)?>_ OpenAI Codex\b/;k0=/^\s*(>)?\s*(\d+)\.\s+(.+?)\s*$/;cP=/Successfully logged in\./,lP=/^\s*Press Enter to continue\.\s*$/;x0=/Enter this one-time code/,dP=/^\s*([A-Z0-9]{2,10}-[A-Z0-9]{2,10})\s*$/;Vf=/Run Everything|Add a follow-up|Plan, search, build anything/;wP=/click this link to log in|Signing in with the browser/});function vP(e){let t=String(e||"").replace(/\r/g,"").split(`
112
+ `),n=-1;for(let c=t.length-1;c>=0;c--)if(t[c].trim()){n=c;break}if(n<0)return!1;let r=t[n];if(kP.test(r)||xP.test(r)){for(let c=n-1;c>=0&&n-c<=64;c--)if(/^\s*›/.test(t[c]))return!0}let s=String(e||""),a=s.split(`
113
+ `).filter(c=>/^\s*›/.test(c)),i=a.some(c=>/^\s*›\s+(?:Ask Codex to do anything|Implement \{feature\})\s*$/.test(c));return a.length>0&&!i&&/esc to interrupt|\bWorking \(/.test(s)}function _P(e){let t=String(e||"");if(!Xe.codex.block.test(t))return null;let n=Br(t);if(!Xe.codex.block.test(n))return null;let r=n.match(EP);return{from:r?.[1]||null,to:r?.[2]||null}}function In(e){return new Promise(t=>setTimeout(t,e))}function Jf(e,t){let n=Date.now(),r=IP();for(let[s,a]of tu)n-a>=r&&tu.delete(s);let o=`${e}::${t}`;return tu.has(o)?!1:(tu.set(o,n),!0)}function I0(e,t){if(e?.busyScope!=="footer")return t;let n=String(t||"").split(`
114
+ `),r=-1;for(let o=n.length-1;o>=0;o--)if(_0.test(n[o])){r=o;break}return r<0?t:n.slice(r+1).join(`
115
+ `)}function RP(e){let t=0;for(let n of String(e).split(`
116
+ `))_0.test(n)&&(t=Math.max(t,n.trimEnd().length));return t}function Yf(e,t){let n=Xe[e];if(!n?.busy)return{state:"idle",reason:null};if(Zf(e,t))return{state:"unknown",reason:"blocked"};if(n.up&&!n.up.test(t))return{state:"idle",reason:null};if(n.busy.test(I0(n,t)))return{state:"busy",reason:null};if(n.busyAlt&&n.busyAlt.test(t))return{state:"busy",reason:null};let r=RP(t);return e==="claude"&&r>0&&r<$P?{state:"unknown",reason:"narrow"}:{state:"idle",reason:null}}function Xf(e,t){return Yf(e,t).state}function $0(e,t){if(e!=="claude")return!1;let n=String(t||"").split(`
117
+ `).slice(-MP).join(`
118
+ `);return OP.test(n)}function Ks(e,t){return Xf(e,t)==="busy"}function Ti(e,t){return Xf(e,t)!=="idle"}function Po(e,t){let n=Xe[e];return n?.up?n.up.test(t):!0}function CP(e,t){let n=Xe[e];return n?Zf(e,t)?!1:n.up.test(t)&&Xf(e,t)==="idle":!0}function Zf(e,t){let n=Xe[e];if(!n)return!1;let r=e==="codex"?Br(t):t;return n.auth?.test(r)&&!n.up.test(r)?!0:n.block?.test(r)?e==="codex"?!0:!n.up.test(r):!1}function Qf(e,t){let n=String(t||"").trim();if(!n)return e;let r=String(e||"").split(`
119
119
  `);for(let o=r.length-1;o>=0;o--)if(r[o].includes(n))return r.slice(o+1).join(`
120
- `);return e}function m0(e){let t=String(e||"").trim();return t?t.slice(0,32):null}function l0(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 u0(e,t,n,{bailOnDialog:r=!1,launchEcho:o=null,onReady:s}={}){let a=Date.now()+n,i=0,c=null;for(await Ao(e).catch(()=>{});;){let l=jf(await Be(e),o);if(gP(t,l))return await s?.(),await An(Ms),"up";if(Ye[t]?.up&&!Ye[t].up.test(l))if(await Xn(e)){if(c??=Date.now(),Date.now()-c>=li()){let u=l0(t);throw ie({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,idleMs:Date.now()-c,error:u.message}).catch(()=>{}),u}}else c=null;else c=null;if(r&&t==="claude"&&lP.test(l)&&!Ye.claude.up.test(l))return ie({flow:"agent-ready",phase:"dialog",sessionName:e,agent:t,dialog:"resume-confirm"}).catch(()=>{}),"dialog-bail";if(t==="codex"&&cP.test(l)&&!Ye.codex.up.test(l)&&i<3){if(!Nf(e,"codex-trust")){await An(Jl);continue}i+=1,await ie({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,gate:"codex-trust",attempt:i}).catch(()=>{}),await ot(e,"",{enter:!0,kind:"codex-trust-accept"}),await An(Ms);continue}if(t==="cursor"&&iP.test(l)&&!Ye.cursor.up.test(l)&&i<3){if(!Nf(e,"cursor-trust")){await An(Jl);continue}i+=1,await ie({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i}).catch(()=>{}),await ot(e,"a",{enter:!1,kind:"cursor-trust-accept"}),await An(Ms);continue}if(t==="codex"&&i<3){let u=dP(l);if(u){if(!Nf(e,`codex-update:${u.from}->${u.to}`)){await An(Jl);continue}i+=1,await ie({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i,update:`${u.from} -> ${u.to}`}).catch(()=>{}),await ot(e,"3",{enter:!1,kind:"codex-update-skip"}),n0({sessionName:e,from:u.from,to:u.to}),await An(Ms);continue}}if(Date.now()>a){if(Bf(t,l)){let u=`${t} is blocked on an interactive prompt`;throw t==="codex"?u=Ye.codex.auth.test(l)?"codex isn't signed in on this box \u2014 answer the Sign in card in chat (Device Code works from any device) or finish signing in from the Terminal tab, then send again":"codex is stuck on its update prompt (auto-skip didn't clear it) \u2014 open the terminal and choose Skip, then send again":t==="cursor"&&Ye.cursor.auth.test(l)?u="cursor isn't signed in on this box \u2014 answer the Sign in card in chat (the login link works from any device) or finish signing in from the Terminal tab, then send again":t==="claude"&&Ye.claude.auth.test(l)?u="claude isn't signed in on this box \u2014 answer the setup cards in chat (or finish signing in from the Terminal tab), then send again":t==="claude"&&Ye.claude.block.test(l)&&(u='claude is waiting on its "Press Enter to continue" screen \u2014 answer the Continue card in chat (or press Enter in the Terminal tab), then send again'),ie({flow:"agent-ready",phase:"blocked",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:u}).catch(()=>{}),new Error(u)}if(await Xn(e)){let u=l0(t);throw ie({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:u.message}).catch(()=>{}),u}return console.warn(`[agent-ready] ${t} readiness unconfirmed in ${e} after ${n}ms \u2014 driving the box anyway.`),ie({flow:"agent-ready",phase:"timeout",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,paneBlocked:!!Ye[t]?.block?.test(l),paneUp:!!Ye[t]?.up?.test(l),paneBusy:!!Ye[t]?.busy?.test(p0(Ye[t],l))}).catch(()=>{}),await An(Ms),"timeout"}await An(Jl)}}function Lf({agent:e,agentCmd:t}={}){let n=t?$r(t):$r(e||"");return{label:n,realClaude:t?To(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 h0({agent:e,agentCmd:t}={}){let{realClaude:n,realCodex:r,realCursor:o}=Lf({agent:e,agentCmd:t});return n||r||o||process.env.BOSTRAT_FAKE_POLL_READY==="1"}function yi({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o}={}){let{realCodex:s,realCursor:a}=Lf({agent:n,agentCmd:r});return!t||!s&&!a?null:Cr({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o}).then(()=>{},()=>{})}async function Cr({cwd:e,sessionId:t,sessionName:n,agent:r,agentCmd:o,timeoutMs:s=rP(),bailOnDialog:a=!1,launchEcho:i=null,onReady:c}={}){let{label:l,realClaude:u,realCodex:d,realCursor:p}=Lf({agent:r,agentCmd:o});if(u&&e&&await vr(e),d&&e&&await ms(e),p&&e&&await hs(e),(u||d||p)&&n)return await u0(n,l,s,{bailOnDialog:a,launchEcho:i,onReady:c});let f=Ye[r]?r:Ye[l]?l:null;return process.env.BOSTRAT_FAKE_POLL_READY==="1"&&n&&f?await u0(n,f,s,{launchEcho:i}):(await An(Ms),"settle")}var rP,Jl,Ms,oP,sP,Ye,iP,cP,lP,uP,pP,Yl,fP,d0,hP,wP,bi=G(()=>{ct();Wa();hl();wl();zl();Vl();Tn();rP=()=>Number(process.env.BOSTRAT_AGENT_READY_TIMEOUT_MS)||9e4,Jl=Number(process.env.BOSTRAT_AGENT_READY_POLL_MS)||500,Ms=Number(process.env.BOSTRAT_AGENT_READY_SETTLE_MS)||800,oP=/^\s{0,4}[^\s›•■◦╭╰│]\S*(?: \S+){0,3} · \S/,sP=/^\s*tab to queue message\b/;Ye={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:aP},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/}},iP=/Trust this workspace|\[a\]\s*Trust/,cP=/Do you trust the contents of this directory\?[\s\S]*›\s*1\. Yes, continue[\s\S]*Press enter to continue/,lP=/Resume from summary/i,uP=/Update available!\s*([\d][\w.-]*)\s*->\s*([\d][\w.-]*)/;pP=()=>Number(process.env.BOSTRAT_GATE_RESEND_MS)||3e3,Yl=new Map;fP=68,d0=/^\s*[─━]{10,}(?: [^─━\n]+ [─━]+)?\s*$/;hP=/\bWaiting for \d+\b[^\n]*\bto finish\b|\/workflows to (?:stop|monitor)\b/,wP=15});function xP(e){return typeof e!="string"||!e?!1:e.includes(`
121
- `)?!0:Buffer.byteLength(e,"utf8")>=kP}function En(e,t){return e==="codex"?{enter:!0,submitDelayMs:yP,...xP(t)?{paste:!0}:{}}:e==="claude"?{enter:!0,submitDelayMs:bP}:{enter:!0}}var yP,bP,kP,ki=G(()=>{yP=(()=>{let e=Number(process.env.BOSTRAT_CODEX_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),bP=(()=>{let e=Number(process.env.BOSTRAT_CLAUDE_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),kP=(()=>{let e=Number(process.env.BOSTRAT_CODEX_PASTE_MIN_BYTES??512);return Number.isFinite(e)&&e>=0?e:512})()});function xi(e,t){if(e==="codex")return EP(t);if(e!=="claude")return null;let n=String(t).replace(/\r/g,"").split(`
122
- `).map(c=>c.replace(/\s+$/,"")),r=-1;for(let c=n.length-1;c>=0;c--)if(w0.test(n[c])){r=c;break}if(r<=0)return null;let o=-1;for(let c=r-1;c>=0;c--)if(w0.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(vP);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 EP(e){let t=String(e).replace(/\r/g,"").split(`
123
- `).map(o=>o.replace(/\s+$/,"")),n=-1;for(let o=t.length-1;o>=0;o--)if(t[o]){(SP.test(t[o])||TP.test(t[o]))&&!Ff.test(t[o])?n=o:Ff.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(Ff);if(a){r.unshift(a[1]);let i=r.map(c=>c.trim()).filter(Boolean);return i.length?i.join(" "):null}if(AP.test(s))return null;r.unshift(s)}return null}function Uf(e,t){let n=String(t||"");if(!/\[Pasted Content \d+ chars\]/.test(n))return!1;let r=0,o=Fe(n.replace(_P,(i,c)=>(r+=Number(c)," "))),s=[...String(e||"")].length;return o&&!Fe(e).includes(o)?!1:r+o.length<=s+Math.max(4,Math.round(s*.05))}function Fe(e){return String(e||"").replace(/\s+/g," ").trim()}function g0(e,t,{slackMs:n=2e4}={}){let r=Fe(t?.text);if(!r||typeof t?.at!="number")return!1;let o=Array.isArray(e)?e:[],s=o.findIndex(a=>a?.role==="user"&&typeof a.ts=="number"&&a.ts>=t.at-n&&Fe(a.text).includes(r));return s>=0&&s<o.length-1}function y0(e,t,n,{busy:r=!1}={}){let o=xi(e,n);return o&&Xl(t,o)||o&&e==="codex"&&Uf(t,o)?"stuck":r&&e!=="codex"||o?"submitted":"unknown"}function Xl(e,t){let n=Fe(e),r=Fe(t).replace(/^…\s*/,"").replace(/\s*…$/,"");return!n||!r||r.length<Math.min(n.length,12)?!1:n===r||n.includes(r)}var w0,vP,Ff,SP,TP,AP,_P,vi=G(()=>{w0=/^\s*─{8,}(?: [^─\n]+ ─+)?\s*$/,vP=/^❯[  ]?(.*)$/,Ff=/^\s*›[  ]?(.*)$/,SP=/\S+ · \S/,TP=/^\s*(?:\? for shortcuts|tab to queue message)\b/,AP=/^\s*(?:[•■◦✶✻⚠]|╭|╰|│)/;_P=/\[Pasted Content (\d+) chars\](?: #\d+)?/g});async function Ti({sessionName:e,agent:t,agentCmd:n=null,text:r,trackId:o=null,flow:s="say",stats:a=null},i={}){let c=(i.now||Date.now)(),l=(L,q,I={})=>(a&&typeof a=="object"&&Object.assign(a,{verdict:L,retries:I.retries??0,ms:(i.now||Date.now)()-c,sawUp:!!I.sawUp,reason:I.reason??null}),q);if(!IP.has(t))return l("skipped",!0);let u=i.waitForUp??h0({agent:t,agentCmd:n}),d=i.capture||(L=>Be(L,{lines:Ze})),p=i.pressEnter||(L=>We(L,["Enter"],{kind:"submit-retry"})),f=i.sleep||MP,w=i.now||Date.now,m=i.log||(L=>ie(L).catch(()=>{})),g=i.maxMs??OP(),y=w()+g,x={flow:s,trackId:o,sessionName:e,agent:t,textHead:String(r).slice(0,120)},b=0,O=0,$=0,C=!1;for(await f(Si[0]);;){let L=await d(e).catch(()=>""),q=Ns(t,L),I=Cs(t,L),_=y0(t,r,L,{busy:I});if(_==="submitted")return l("submitted",!0,{retries:b,sawUp:!0});if(u&&(!q||_==="stuck"&&I)){if(w()>=y)return _==="stuck"?(m({...x,phase:"submit-failed",reason:"stuck-at-deadline",retries:b}),l("failed",!1,{retries:b,sawUp:C,reason:"stuck-at-deadline"})):(m({...x,phase:"submit-unverified",reason:C?"cli-down":"cli-never-up",retries:b,waitedMs:g}),l("unverified",!0,{retries:b,sawUp:C,reason:C?"cli-down":"cli-never-up"}));await f($P);continue}if(C=!0,_==="stuck"){if(b>=RP)return m({...x,phase:"submit-failed",retries:b}),l("failed",!1,{retries:b,sawUp:!0,reason:"stuck"});b+=1,O=0,$=0,await p(e),m({...x,phase:"submit-retry",attempt:b}),await f(Si[0]);continue}if(O+=1,O>=Si.length||w()>=y)return l("assumed",!0,{retries:b,sawUp:!0});$+=1,await f(Si[Math.min($,Si.length-1)])}}var IP,Si,$P,RP,OP,MP,Hf=G(()=>{ct();bi();vi();Tn();IP=new Set(["claude","codex"]),Si=[250,450,700],$P=500,RP=2,OP=()=>{let e=Number(process.env.BOSTRAT_SUBMIT_VERIFY_MAX_MS);return Number.isFinite(e)&&e>0?e:3e4},MP=e=>new Promise(t=>setTimeout(t,e))});function b0(e){return String(e||"").replace(/[\u2018\u2019\u201A\u02BC\u0060\u00B4]/g,"'").replace(/[\u201C\u201D\u201E]/g,'"')}function Zn(e){let t=b0(e).toLowerCase();if(!t.trim())return null;let n=null;for(let r of CP){let o=0;for(let s of NP[r])s.test(t)&&o++;o>0&&(!n||o>n.score)&&(n={category:r,score:o})}return n}function k0(e){let t=0,n=0;for(let[r,o]of Object.entries(e||{}))PP.has(r)&&(t+=o||0),DP.has(r)&&(n+=o||0);return t>=5&&n===0?{category:"research",score:1}:n>=3?{category:"feature-build",score:1}:null}function Ai(e){return String(e||"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").replace(/[-_/]+/g," ")}function x0(e){let t=b0(e).trim();return t?jP.test(t)?!0:t.split(/\s+/).length<=BP:!1}var CP,NP,PP,DP,BP,jP,Zl=G(()=>{CP=["bug-fix","orchestration","design","ops-infra","docs-writing","research","feature-build"],NP={research:[/\bresearch\b/,/\binvestigat/,/\bverif/,/\bcompar(e|ing|ison)/,/\bcompetit/,/\bdeep[ -]?dive\b/,/\banaly[sz]/,/\bassess/,/\bdiligence\b/,/\bmarket\b/,/\bstrateg/,/\broadmap\b/,/\bnorth star/,/\bwhat('| i)?s the (state|status)\b/,/\bstatus of\b/,/\bexplore\b/,/\bfeasib/,/\bevaluat/,/\bscope (it |this |that |them )?out\b/,/\btalk (me |us )?through\b/,/\b(give|show|tell) me\b/,/\bwhat about\b/,/\bwhy\b/,/\btake a look\b/,/\bwalk (me |us )?through\b/,/\bexplain\b/,/\bdo we (still |even )?need\b/,/\bis there (a|an|any)\b/,/\bhow often\b/,/\bdo we (currently|already)\b/,/\bwould it be (valuable|useful|worth)\b/,/\bis it possible\b/],"bug-fix":[/\bfix(e[sd]|ing)?\b/,/\bbugs?\b/,/\bbroken\b/,/\bregression\b/,/\bcrash/,/\bincident\b/,/\bdebug/,/\bdoesn'?t (work|render|load|start)/,/\bnot working\b/,/\btroubleshoot/,/\bflaky?\b/,/\brepro(duce|duction)?\b/,/\brace condition\b/,/\bleak\b/,/\bkeeps? getting\b/,/\bdoesn'?t (seem|look) right\b/,/\bseems? (wrong|off|broken)\b/,/\b(too slow|slower than|much slower)\b/,/\bfail(ed|ing|s)\b/],"feature-build":[/\bimplement/,/\bbuild(ing)?\b/,/\badd(ing)?\b/,/\bcreate\b/,/\bwire (it |them )?(up|in)\b/,/\bship(ping)?\b/,/\bintegrat/,/\bsupport for\b/,/\bfeature\b/,/\bendpoint\b/,/\badapter\b/,/\bprototype\b/,/\bupdate (the |this |that |my |our )?[\w-]+( [\w-]+){0,3} to\b/,/\bset up\b/],design:[/\bdesign/,/\bui\b/,/\bux\b/,/\bstyl(e|es|ing)\b/,/\bcss\b/,/\blayout\b/,/\bmock-?up/,/\brender(ing|s)?\b/,/\bpolish/,/\btheme\b/,/\bfonts?\b/,/\bresponsive\b/,/\banimation/,/\bvisual/,/\bpopover\b/],orchestration:[/\bhand[ -]?(off|over)/,/\bhand (it|the lead|this) (over|off)\b/,/\bdelegat/,/\bsubtask/,/\bmerge[ -]?back\b/,/\borchestrat/,/\b(switch|change) (the )?model\b/,/\bmodel switch/],"docs-writing":[/\bdocs?\b/,/\bdocument/,/\bmemo\b/,/\breadme\b/,/\bwrite-?up\b/,/\bchangelog\b/,/\bclaude\.md\b/,/\bblog/,/\bproofread/,/\bcopy(edit|writ)/,/\b(linked[ -]?in|social( media)?) post\b/],"ops-infra":[/\bdeploy/,/\bsystemd\b/,/\bdaemon\b/,/\btmux\b/,/\bdns\b/,/\bwireguard\b/,/\brestart/,/\bnginx\b/,/\bprovision/,/\binstall/,/\bupgrade/,/\bcron\b/,/\bbackups?\b/,/\bcertificat/,/\bssh\b/,/\bsecrets?\b/,/\b(unzip|decompress|untar)\b/]};PP=new Set(["Read","Grep","Glob","LS","WebSearch","WebFetch","NotebookRead"]),DP=new Set(["Edit","Write","MultiEdit","NotebookEdit"]);BP=12,jP=/^\s*(ok(ay)?|yes|yep|yeah|sure|go ahead|go|proceed|continue|next|begin|start|do it|do that|try again|try once more|again|ship it|perfect|great|good|nice|thanks|lock(ed)? (it |that |those )?in|option [a-z]\b|where are we|what'?s the status)\b/i});function A0(e){let t=Ai(String(e||"")).toLowerCase(),n=[];for(let r of t.split(/[^a-z0-9]+/))r.length<2||LP.has(r)||n.push(r);return n}function FP(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(T0(n,"user",o))}else if(n.type==="turn.agent"){if(!o)continue;t.push(T0(n,"assistant",o))}}return t}function T0(e,t,n){let r=Zn(n);return{id:e.id,seq:e.seq,ts:e.payload?.ts??e.ts,role:t,boxId:e.boxId??null,provider:e.provider??null,text:n,tags:r?[r.category]:[]}}function Ei(e){let t=FP(e),n=new Map,r=new Array(t.length).fill(0),o=0;t.forEach((a,i)=>{let c=A0(a.text);r[i]=c.length,o+=c.length;let l=new Map;for(let u of c)l.set(u,(l.get(u)||0)+1);for(let[u,d]of l){let p=n.get(u);p||n.set(u,p=new Map),p.set(i,d)}});let s=t.length;return{chunks:t,postings:n,lengths:r,N:s,avgdl:s?o/s:0}}function Ql(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(A0(t))];if(!i.length)return[];let c=new Map;for(let u of i){let d=e.postings.get(u);if(!d)continue;let p=d.size,f=Math.log(1+(e.N-p+.5)/(p+.5));for(let[w,m]of d){let g=e.lengths[w],y=m+v0*(1-S0+S0*(g/(e.avgdl||1))),x=f*(m*(v0+1)/y);c.set(w,(c.get(w)||0)+x)}}let l=[];for(let[u,d]of c){let p=e.chunks[u];o&&p.role!==o||s&&!p.tags.includes(s)||a&&p.boxId!==a||l.push({chunk:p,score:d})}return l.sort((u,d)=>d.score-u.score||d.chunk.seq-u.chunk.seq),l.slice(0,r)}var v0,S0,LP,qf=G(()=>{Zl();v0=1.5,S0=.75,LP=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 eu from"node:fs/promises";import E0 from"node:path";async function UP(e){let t=E0.join(e,".bostrat","events"),n;try{n=await eu.readdir(t)}catch{return Ei([])}let r=[];for(let o of n)if(o.endsWith(".ndjson"))try{let s=await eu.readFile(E0.join(t,o),"utf8");for(let a of s.split(`
124
- `))if(a.trim())try{r.push(JSON.parse(a))}catch{}}catch{}return Ei(r)}function HP(e){let t=String(e||""),n=a=>{let i=t.match(a);return i?i[1].trim():""},r=n(/#+\s*Objective\s*\n([\s\S]*?)(?:\n#+\s|$)/i),o=n(/#+\s*Next steps?[^\n]*\n([\s\S]*?)(?:\n#+\s|$)/i);return`${r}
125
- ${o}`.trim()||t.slice(0,2e3)}function qP(e,t,{k:n=6,maxChars:r=4e3,exclude:o=null}={}){let s=Ql(e,t,{k:n*2+4}),a=[],i=0;for(let{chunk:c}of s){if(o&&o(c))continue;let l=c.role==="user"?"Operator":`Agent${c.provider?` (${c.provider})`:""}`,u=c.text.trim(),d=u.length>800?u.slice(0,800)+"\u2026":u,p=`- **${l}:** ${d}`;if(i+p.length>r||(a.push(p),i+=p.length,a.length>=n))break}return a.length?["",`## ${_0}, not a summary)`,"_Auto-selected from the Track's event log by lexical relevance to the Objective / Next steps. Verbatim excerpts, not re-summarization (docs/memory-segmentation-indexing-scope.md \xA71.3)._","",...a,""].join(`
126
- `):""}async function I0(e,t,n={}){let{k:r=6,maxChars:o=4e3,exclude:s=null}=n;try{let a=await eu.readFile(t,"utf8");if(a.includes(_0))return{appended:!1,reason:"already-enriched"};let i=await UP(e);if(!i.N)return{appended:!1,reason:"empty-index"};let c=qP(i,HP(a),{k:r,maxChars:o,exclude:s});return c?(await eu.appendFile(t,`
120
+ `);return e}function R0(e){let t=String(e||"").trim();return t?t.slice(0,32):null}function T0(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 E0(e,t,n,{bailOnDialog:r=!1,launchEcho:o=null,onReady:s}={}){let a=Date.now()+n,i=0,c=null;for(await Oo(e).catch(()=>{});;){let l=Qf(await Pe(e),o);if(CP(t,l))return await s?.(),await In(qs),"up";if(Xe[t]?.up&&!Xe[t].up.test(l))if(await er(e)){if(c??=Date.now(),Date.now()-c>=gi()){let u=T0(t);throw ue({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,idleMs:Date.now()-c,error:u.message}).catch(()=>{}),u}}else c=null;else c=null;if(r&&t==="claude"&&TP.test(l)&&!Xe.claude.up.test(l))return ue({flow:"agent-ready",phase:"dialog",sessionName:e,agent:t,dialog:"resume-confirm"}).catch(()=>{}),"dialog-bail";if(t==="codex"&&AP.test(l)&&!Xe.codex.up.test(l)&&i<3){if(!Jf(e,"codex-trust")){await In(eu);continue}i+=1,await ue({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,gate:"codex-trust",attempt:i}).catch(()=>{}),await ot(e,"",{enter:!0,kind:"codex-trust-accept"}),await In(qs);continue}if(t==="cursor"&&SP.test(l)&&!Xe.cursor.up.test(l)&&i<3){if(!Jf(e,"cursor-trust")){await In(eu);continue}i+=1,await ue({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i}).catch(()=>{}),await ot(e,"a",{enter:!1,kind:"cursor-trust-accept"}),await In(qs);continue}if(t==="codex"&&i<3){let u=_P(l);if(u){if(!Jf(e,`codex-update:${u.from}->${u.to}`)){await In(eu);continue}i+=1,await ue({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i,update:`${u.from} -> ${u.to}`}).catch(()=>{}),await ot(e,"3",{enter:!1,kind:"codex-update-skip"}),y0({sessionName:e,from:u.from,to:u.to}),await In(qs);continue}}if(Date.now()>a){if(Zf(t,l)){let u=`${t} is blocked on an interactive prompt`;throw t==="codex"?u=Xe.codex.auth.test(l)?"codex isn't signed in on this box \u2014 answer the Sign in card in chat (Device Code works from any device) or finish signing in from the Terminal tab, then send again":"codex is stuck on its update prompt (auto-skip didn't clear it) \u2014 open the terminal and choose Skip, then send again":t==="cursor"&&Xe.cursor.auth.test(l)?u="cursor isn't signed in on this box \u2014 answer the Sign in card in chat (the login link works from any device) or finish signing in from the Terminal tab, then send again":t==="claude"&&Xe.claude.auth.test(l)?u="claude isn't signed in on this box \u2014 answer the setup cards in chat (or finish signing in from the Terminal tab), then send again":t==="claude"&&Xe.claude.block.test(l)&&(u='claude is waiting on its "Press Enter to continue" screen \u2014 answer the Continue card in chat (or press Enter in the Terminal tab), then send again'),ue({flow:"agent-ready",phase:"blocked",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:u}).catch(()=>{}),new Error(u)}if(await er(e)){let u=T0(t);throw ue({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:u.message}).catch(()=>{}),u}return console.warn(`[agent-ready] ${t} readiness unconfirmed in ${e} after ${n}ms \u2014 driving the box anyway.`),ue({flow:"agent-ready",phase:"timeout",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,paneBlocked:!!Xe[t]?.block?.test(l),paneUp:!!Xe[t]?.up?.test(l),paneBusy:!!Xe[t]?.busy?.test(I0(Xe[t],l))}).catch(()=>{}),await In(qs),"timeout"}await In(eu)}}function em({agent:e,agentCmd:t}={}){let n=t?Nr(t):Nr(e||"");return{label:n,realClaude:t?Ro(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 O0({agent:e,agentCmd:t}={}){let{realClaude:n,realCodex:r,realCursor:o}=em({agent:e,agentCmd:t});return n||r||o||process.env.BOSTRAT_FAKE_POLL_READY==="1"}function Do({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o}={}){let{realCodex:s,realCursor:a}=em({agent:n,agentCmd:r});return!t||!s&&!a?null:tr({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o}).then(()=>{},()=>{})}async function tr({cwd:e,sessionId:t,sessionName:n,agent:r,agentCmd:o,timeoutMs:s=bP(),bailOnDialog:a=!1,launchEcho:i=null,onReady:c}={}){let{label:l,realClaude:u,realCodex:d,realCursor:p}=em({agent:r,agentCmd:o});if(u&&e&&await _r(e),d&&e&&await Es(e),p&&e&&await _s(e),(u||d||p)&&n)return await E0(n,l,s,{bailOnDialog:a,launchEcho:i,onReady:c});let f=Xe[r]?r:Xe[l]?l:null;return process.env.BOSTRAT_FAKE_POLL_READY==="1"&&n&&f?await E0(n,f,s,{launchEcho:i}):(await In(qs),"settle")}var bP,eu,qs,kP,xP,Xe,SP,AP,TP,EP,IP,tu,$P,_0,OP,MP,Ei=G(()=>{ct();Za();bl();kl();Zl();Ql();En();bP=()=>Number(process.env.BOSTRAT_AGENT_READY_TIMEOUT_MS)||9e4,eu=Number(process.env.BOSTRAT_AGENT_READY_POLL_MS)||500,qs=Number(process.env.BOSTRAT_AGENT_READY_SETTLE_MS)||800,kP=/^\s{0,4}[^\s›•■◦╭╰│]\S*(?: \S+){0,3} · \S/,xP=/^\s*tab to queue message\b/;Xe={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:vP},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/}},SP=/Trust this workspace|\[a\]\s*Trust/,AP=/Do you trust the contents of this directory\?[\s\S]*›\s*1\. Yes, continue[\s\S]*Press enter to continue/,TP=/Resume from summary/i,EP=/Update available!\s*([\d][\w.-]*)\s*->\s*([\d][\w.-]*)/;IP=()=>Number(process.env.BOSTRAT_GATE_RESEND_MS)||3e3,tu=new Map;$P=68,_0=/^\s*[─━]{10,}(?: [^─━\n]+ [─━]+)?\s*$/;OP=/\bWaiting for \d+\b[^\n]*\bto finish\b|\/workflows to (?:stop|monitor)\b/,MP=15});function BP(e){return typeof e!="string"||!e?!1:e.includes(`
121
+ `)?!0:Buffer.byteLength(e,"utf8")>=DP}function $n(e,t){return e==="codex"?{enter:!0,submitDelayMs:NP,...BP(t)?{paste:!0}:{}}:e==="claude"?{enter:!0,submitDelayMs:PP}:{enter:!0}}var NP,PP,DP,_i=G(()=>{NP=(()=>{let e=Number(process.env.BOSTRAT_CODEX_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),PP=(()=>{let e=Number(process.env.BOSTRAT_CLAUDE_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),DP=(()=>{let e=Number(process.env.BOSTRAT_CODEX_PASTE_MIN_BYTES??512);return Number.isFinite(e)&&e>=0?e:512})()});function Ii(e,t){if(e==="codex")return HP(t);if(e!=="claude")return null;let n=String(t).replace(/\r/g,"").split(`
122
+ `).map(c=>c.replace(/\s+$/,"")),r=-1;for(let c=n.length-1;c>=0;c--)if(M0.test(n[c])){r=c;break}if(r<=0)return null;let o=-1;for(let c=r-1;c>=0;c--)if(M0.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(jP);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 HP(e){let t=String(e).replace(/\r/g,"").split(`
123
+ `).map(o=>o.replace(/\s+$/,"")),n=-1;for(let o=t.length-1;o>=0;o--)if(t[o]){(LP.test(t[o])||FP.test(t[o]))&&!tm.test(t[o])?n=o:tm.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(tm);if(a){r.unshift(a[1]);let i=r.map(c=>c.trim()).filter(Boolean);return i.length?i.join(" "):null}if(UP.test(s))return null;r.unshift(s)}return null}function nm(e,t){let n=String(t||"");if(!/\[Pasted Content \d+ chars\]/.test(n))return!1;let r=0,o=Fe(n.replace(WP,(i,c)=>(r+=Number(c)," "))),s=[...String(e||"")].length;return o&&!Fe(e).includes(o)?!1:r+o.length<=s+Math.max(4,Math.round(s*.05))}function Fe(e){return String(e||"").replace(/\s+/g," ").trim()}function C0(e,t,{slackMs:n=2e4}={}){let r=Fe(t?.text);if(!r||typeof t?.at!="number")return!1;let o=Array.isArray(e)?e:[],s=o.findIndex(a=>a?.role==="user"&&typeof a.ts=="number"&&a.ts>=t.at-n&&Fe(a.text).includes(r));return s>=0&&s<o.length-1}function N0(e,t,n,{busy:r=!1}={}){let o=Ii(e,n);return o&&nu(t,o)||o&&e==="codex"&&nm(t,o)?"stuck":r&&e!=="codex"||o?"submitted":"unknown"}function nu(e,t){let n=Fe(e),r=Fe(t).replace(/^…\s*/,"").replace(/\s*…$/,"");return!n||!r||r.length<Math.min(n.length,12)?!1:n===r||n.includes(r)}var M0,jP,tm,LP,FP,UP,WP,$i=G(()=>{M0=/^\s*─{8,}(?: [^─\n]+ ─+)?\s*$/,jP=/^❯[  ]?(.*)$/,tm=/^\s*›[  ]?(.*)$/,LP=/\S+ · \S/,FP=/^\s*(?:\? for shortcuts|tab to queue message)\b/,UP=/^\s*(?:[•■◦✶✻⚠]|╭|╰|│)/;WP=/\[Pasted Content (\d+) chars\](?: #\d+)?/g});async function Oi({sessionName:e,agent:t,agentCmd:n=null,text:r,trackId:o=null,flow:s="say",stats:a=null},i={}){let c=(i.now||Date.now)(),l=(U,B,T={})=>(a&&typeof a=="object"&&Object.assign(a,{verdict:U,retries:T.retries??0,ms:(i.now||Date.now)()-c,sawUp:!!T.sawUp,reason:T.reason??null}),B);if(!qP.has(t))return l("skipped",!0);let u=i.waitForUp??O0({agent:t,agentCmd:n}),d=i.capture||(U=>Pe(U,{lines:Ye})),p=i.pressEnter||(U=>qe(U,["Enter"],{kind:"submit-retry"})),f=i.sleep||VP,w=i.now||Date.now,m=i.log||(U=>ue(U).catch(()=>{})),g=i.maxMs??zP(),y=w()+g,x={flow:s,trackId:o,sessionName:e,agent:t,textHead:String(r).slice(0,120)},b=0,R=0,_=0,C=!1;for(await f(Ri[0]);;){let U=await d(e).catch(()=>""),B=Po(t,U),T=Ks(t,U),$=N0(t,r,U,{busy:T});if($==="submitted")return l("submitted",!0,{retries:b,sawUp:!0});if(u&&(!B||$==="stuck"&&T)){if(w()>=y)return $==="stuck"?(m({...x,phase:"submit-failed",reason:"stuck-at-deadline",retries:b}),l("failed",!1,{retries:b,sawUp:C,reason:"stuck-at-deadline"})):(m({...x,phase:"submit-unverified",reason:C?"cli-down":"cli-never-up",retries:b,waitedMs:g}),l("unverified",!0,{retries:b,sawUp:C,reason:C?"cli-down":"cli-never-up"}));await f(KP);continue}if(C=!0,$==="stuck"){if(b>=GP)return m({...x,phase:"submit-failed",retries:b}),l("failed",!1,{retries:b,sawUp:!0,reason:"stuck"});b+=1,R=0,_=0,await p(e),m({...x,phase:"submit-retry",attempt:b}),await f(Ri[0]);continue}if(R+=1,R>=Ri.length||w()>=y)return l("assumed",!0,{retries:b,sawUp:!0});_+=1,await f(Ri[Math.min(_,Ri.length-1)])}}var qP,Ri,KP,GP,zP,VP,rm=G(()=>{ct();Ei();$i();En();qP=new Set(["claude","codex"]),Ri=[250,450,700],KP=500,GP=2,zP=()=>{let e=Number(process.env.BOSTRAT_SUBMIT_VERIFY_MAX_MS);return Number.isFinite(e)&&e>0?e:3e4},VP=e=>new Promise(t=>setTimeout(t,e))});function P0(e){return String(e||"").replace(/[\u2018\u2019\u201A\u02BC\u0060\u00B4]/g,"'").replace(/[\u201C\u201D\u201E]/g,'"')}function nr(e){let t=P0(e).toLowerCase();if(!t.trim())return null;let n=null;for(let r of JP){let o=0;for(let s of YP[r])s.test(t)&&o++;o>0&&(!n||o>n.score)&&(n={category:r,score:o})}return n}function D0(e){let t=0,n=0;for(let[r,o]of Object.entries(e||{}))XP.has(r)&&(t+=o||0),ZP.has(r)&&(n+=o||0);return t>=5&&n===0?{category:"research",score:1}:n>=3?{category:"feature-build",score:1}:null}function Mi(e){return String(e||"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").replace(/[-_/]+/g," ")}function B0(e){let t=P0(e).trim();return t?eD.test(t)?!0:t.split(/\s+/).length<=QP:!1}var JP,YP,XP,ZP,QP,eD,ru=G(()=>{JP=["bug-fix","orchestration","design","ops-infra","docs-writing","research","feature-build"],YP={research:[/\bresearch\b/,/\binvestigat/,/\bverif/,/\bcompar(e|ing|ison)/,/\bcompetit/,/\bdeep[ -]?dive\b/,/\banaly[sz]/,/\bassess/,/\bdiligence\b/,/\bmarket\b/,/\bstrateg/,/\broadmap\b/,/\bnorth star/,/\bwhat('| i)?s the (state|status)\b/,/\bstatus of\b/,/\bexplore\b/,/\bfeasib/,/\bevaluat/,/\bscope (it |this |that |them )?out\b/,/\btalk (me |us )?through\b/,/\b(give|show|tell) me\b/,/\bwhat about\b/,/\bwhy\b/,/\btake a look\b/,/\bwalk (me |us )?through\b/,/\bexplain\b/,/\bdo we (still |even )?need\b/,/\bis there (a|an|any)\b/,/\bhow often\b/,/\bdo we (currently|already)\b/,/\bwould it be (valuable|useful|worth)\b/,/\bis it possible\b/],"bug-fix":[/\bfix(e[sd]|ing)?\b/,/\bbugs?\b/,/\bbroken\b/,/\bregression\b/,/\bcrash/,/\bincident\b/,/\bdebug/,/\bdoesn'?t (work|render|load|start)/,/\bnot working\b/,/\btroubleshoot/,/\bflaky?\b/,/\brepro(duce|duction)?\b/,/\brace condition\b/,/\bleak\b/,/\bkeeps? getting\b/,/\bdoesn'?t (seem|look) right\b/,/\bseems? (wrong|off|broken)\b/,/\b(too slow|slower than|much slower)\b/,/\bfail(ed|ing|s)\b/],"feature-build":[/\bimplement/,/\bbuild(ing)?\b/,/\badd(ing)?\b/,/\bcreate\b/,/\bwire (it |them )?(up|in)\b/,/\bship(ping)?\b/,/\bintegrat/,/\bsupport for\b/,/\bfeature\b/,/\bendpoint\b/,/\badapter\b/,/\bprototype\b/,/\bupdate (the |this |that |my |our )?[\w-]+( [\w-]+){0,3} to\b/,/\bset up\b/],design:[/\bdesign/,/\bui\b/,/\bux\b/,/\bstyl(e|es|ing)\b/,/\bcss\b/,/\blayout\b/,/\bmock-?up/,/\brender(ing|s)?\b/,/\bpolish/,/\btheme\b/,/\bfonts?\b/,/\bresponsive\b/,/\banimation/,/\bvisual/,/\bpopover\b/],orchestration:[/\bhand[ -]?(off|over)/,/\bhand (it|the lead|this) (over|off)\b/,/\bdelegat/,/\bsubtask/,/\bmerge[ -]?back\b/,/\borchestrat/,/\b(switch|change) (the )?model\b/,/\bmodel switch/],"docs-writing":[/\bdocs?\b/,/\bdocument/,/\bmemo\b/,/\breadme\b/,/\bwrite-?up\b/,/\bchangelog\b/,/\bclaude\.md\b/,/\bblog/,/\bproofread/,/\bcopy(edit|writ)/,/\b(linked[ -]?in|social( media)?) post\b/],"ops-infra":[/\bdeploy/,/\bsystemd\b/,/\bdaemon\b/,/\btmux\b/,/\bdns\b/,/\bwireguard\b/,/\brestart/,/\bnginx\b/,/\bprovision/,/\binstall/,/\bupgrade/,/\bcron\b/,/\bbackups?\b/,/\bcertificat/,/\bssh\b/,/\bsecrets?\b/,/\b(unzip|decompress|untar)\b/]};XP=new Set(["Read","Grep","Glob","LS","WebSearch","WebFetch","NotebookRead"]),ZP=new Set(["Edit","Write","MultiEdit","NotebookEdit"]);QP=12,eD=/^\s*(ok(ay)?|yes|yep|yeah|sure|go ahead|go|proceed|continue|next|begin|start|do it|do that|try again|try once more|again|ship it|perfect|great|good|nice|thanks|lock(ed)? (it |that |those )?in|option [a-z]\b|where are we|what'?s the status)\b/i});function U0(e){let t=Mi(String(e||"")).toLowerCase(),n=[];for(let r of t.split(/[^a-z0-9]+/))r.length<2||tD.has(r)||n.push(r);return n}function nD(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(F0(n,"user",o))}else if(n.type==="turn.agent"){if(!o)continue;t.push(F0(n,"assistant",o))}}return t}function F0(e,t,n){let r=nr(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 Ci(e){let t=nD(e),n=new Map,r=new Array(t.length).fill(0),o=0;t.forEach((a,i)=>{let c=U0(a.text);r[i]=c.length,o+=c.length;let l=new Map;for(let u of c)l.set(u,(l.get(u)||0)+1);for(let[u,d]of l){let p=n.get(u);p||n.set(u,p=new Map),p.set(i,d)}});let s=t.length;return{chunks:t,postings:n,lengths:r,N:s,avgdl:s?o/s:0}}function ou(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(U0(t))];if(!i.length)return[];let c=new Map;for(let u of i){let d=e.postings.get(u);if(!d)continue;let p=d.size,f=Math.log(1+(e.N-p+.5)/(p+.5));for(let[w,m]of d){let g=e.lengths[w],y=m+j0*(1-L0+L0*(g/(e.avgdl||1))),x=f*(m*(j0+1)/y);c.set(w,(c.get(w)||0)+x)}}let l=[];for(let[u,d]of c){let p=e.chunks[u];o&&p.role!==o||s&&!p.tags.includes(s)||a&&p.boxId!==a||l.push({chunk:p,score:d})}return l.sort((u,d)=>d.score-u.score||d.chunk.seq-u.chunk.seq),l.slice(0,r)}var j0,L0,tD,om=G(()=>{ru();j0=1.5,L0=.75,tD=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 su from"node:fs/promises";import H0 from"node:path";async function rD(e){let t=H0.join(e,".bostrat","events"),n;try{n=await su.readdir(t)}catch{return Ci([])}let r=[];for(let o of n)if(o.endsWith(".ndjson"))try{let s=await su.readFile(H0.join(t,o),"utf8");for(let a of s.split(`
124
+ `))if(a.trim())try{r.push(JSON.parse(a))}catch{}}catch{}return Ci(r)}function oD(e){let t=String(e||""),n=a=>{let i=t.match(a);return i?i[1].trim():""},r=n(/#+\s*Objective\s*\n([\s\S]*?)(?:\n#+\s|$)/i),o=n(/#+\s*Next steps?[^\n]*\n([\s\S]*?)(?:\n#+\s|$)/i);return`${r}
125
+ ${o}`.trim()||t.slice(0,2e3)}function sD(e,t,{k:n=6,maxChars:r=4e3,exclude:o=null}={}){let s=ou(e,t,{k:n*2+4}),a=[],i=0;for(let{chunk:c}of s){if(o&&o(c))continue;let l=c.role==="user"?"Operator":`Agent${c.provider?` (${c.provider})`:""}`,u=c.text.trim(),d=u.length>800?u.slice(0,800)+"\u2026":u,p=`- **${l}:** ${d}`;if(i+p.length>r||(a.push(p),i+=p.length,a.length>=n))break}return a.length?["",`## ${W0}, not a summary)`,"_Auto-selected from the Track's event log by lexical relevance to the Objective / Next steps. Verbatim excerpts, not re-summarization (docs/memory-segmentation-indexing-scope.md \xA71.3)._","",...a,""].join(`
126
+ `):""}async function q0(e,t,n={}){let{k:r=6,maxChars:o=4e3,exclude:s=null}=n;try{let a=await su.readFile(t,"utf8");if(a.includes(W0))return{appended:!1,reason:"already-enriched"};let i=await rD(e);if(!i.N)return{appended:!1,reason:"empty-index"};let c=sD(i,oD(a),{k:r,maxChars:o,exclude:s});return c?(await su.appendFile(t,`
127
127
  `+c),{appended:!0,chars:c.length,chunks:c.split(`
128
- - `).length-1,indexed:i.N}):{appended:!1,reason:"no-hits",indexed:i.N}}catch(a){return{appended:!1,reason:"error",error:a?.message||String(a)}}}var _0,$0=G(()=>{qf();_0="Relevant prior discussion (verbatim, retrieved"});function JP(e){return WP.test(String(e||"").trimStart())}function M0(e){let t=String(e||"");if(!JP(t.trimStart()))return null;let n=t.replace(KP,"").trim(),r=YP(n),o=[];for(let u of zP){let d=u.from.map(p=>Ps(r.get(p))).find(p=>p&&!R0(p));d&&o.push({h:u.h,text:_i(d,GP)})}let s=Ps(r.get("Current Work"))||Ps(r.get("Primary Request and Intent"))||ZP(n),a=nu(s),i=_i(tu(Gf(a[0]||"")),VP)||"Context resumed from summary",c=[],l=a.slice(1).join(" ").trim();l&&c.push(_i(tu(Gf(l)),Kf));for(let u of["Pending Tasks","Optional Next Step"]){let d=nu(Ps(r.get(u)))[0]||"";if(!(!d||R0(d))){c.push(_i(`Left to do: ${tu(Gf(d))}`,Kf));break}}if(!c.length){let u=nu(Ps(r.get("Problem Solving"))||"")[0];u&&c.push(_i(tu(u),Kf))}return{kind:"resume-summary",title:i,bullets:c.slice(0,2),sections:o,rawChars:t.length}}function YP(e){let t=new Map,n=[];Wf.lastIndex=0;for(let r=Wf.exec(e);r;r=Wf.exec(e))n.push({name:XP(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 XP(e){return O0.find(n=>n.toLowerCase()===e.toLowerCase())||e}function Ps(e){return e?String(e).replace(/```[\s\S]*?(?:```|$)/g," ").split(`
129
- `).map(t=>t.replace(/^[ \t]*(?:[-*•]|\d+[.)]|[a-z][.)])[ \t]+/i,"").trim()).filter(t=>t&&!/^#{1,6}[ \t]/.test(t)).join(" ").replace(/\*\*(.+?)\*\*/g,"$1").replace(/`([^`]+)`/g,"$1").replace(/\s+/g," ").trim():""}function ZP(e){let t=e.replace(/^[\s\S]*?\bSummary:\s*/i,"");return Ps(t.split(/\n{2,}/).slice(0,2).join(" "))}function nu(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 Gf(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 tu(e){return String(e||"").replace(/(?<![:\w/])(?:\/[\w.@+-]+){4,}/g,t=>`\u2026/${t.split("/").slice(-2).join("/")}`)}function R0(e){return/^(none|nothing|n\/a|no pending|there are no)\b/i.test(String(e||"").trim())}function _i(e,t){let n=String(e||"").trim();if(n.length<=t)return n;let r=nu(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 WP,O0,Wf,KP,GP,zP,VP,Kf,C0=G(()=>{WP=/^This session is being continued from a previous conversation that ran out of context\./,O0=["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"],Wf=new RegExp(String.raw`^[ \t]*#{0,4}[ \t]*(?:\d+[.)][ \t]*)?\*{0,2}(${O0.join("|")})[:*\t ]*$`,"gim"),KP=/\n+If you need specific details from before compaction[\s\S]*$|\n+Continue the conversation from where it left off[\s\S]*$/,GP=420,zP=[{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"]}],VP=116,Kf=168});function D0(e){return zf.has(String(e||"").replace(/^\//,"").toLowerCase())}function Ii(e){let t=String(e||"").trim();if(!t)return null;let n=M0(t);if(n)return n;let r=t.match(QP);if(r)return{kind:"skill",name:r[1].split("/").filter(Boolean).pop()||"skill"};let o=t.match(eD);if(o)return{kind:"skill",name:o[1]};let s=t.match(tD);if(s)return{kind:"skill",name:s[1].toLowerCase()};let a=t.match(nD);if(a){let c=a[1].toLowerCase();return zf.has(c)?{kind:"suppress"}:{kind:"command",command:`/${c}`}}let i=t.match(pD);if(i&&zf.has(i[1].toLowerCase()))return{kind:"suppress"};if(rD.test(t))return{kind:"suppress"};if(sD.test(t))return{kind:"suppress"};if(oD.test(t))return{kind:"suppress"};if(aD.test(t)){let c=u=>wD(t.match(u)?.[1].trim()||"")||null,l=c(dD);return{kind:"task",summary:c(iD)||"",taskId:c(cD),toolUseId:c(lD),status:c(uD)?.toLowerCase()||null,resultHead:l?l.length>N0?`${l.slice(0,N0).trimEnd()}\u2026`:l:null}}return null}function B0(e){let t=Ii(e?.text);return t||(e?.injected?{kind:"skill",name:e.injected.skill||"skill"}:null)}function j0(e){let t=String(e||""),n=t.match(fD);if(n)return{kind:"shell-input",command:n[1].trim()};let r=t.match(mD);return r?{kind:"shell-output",stdout:P0(r[1]),stderr:P0(r[2])}:null}function wD(e){return e.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&amp;/g,"&")}function L0(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 F0(e){return e?.kind==="skill"?"skill-run":e?.kind==="task"?"task-done":e?.kind==="resume-summary"?"context-resumed":"command-run"}var QP,eD,tD,nD,rD,oD,sD,aD,iD,cD,lD,uD,dD,N0,zf,pD,fD,mD,hD,P0,ru=G(()=>{C0();QP=/^Base directory for this skill:\s*(\S+)/,eD=/^Run the "([^"]+)" workflow\./,tD=/^#\s*\/([a-z0-9:_-]+)\s*[—–:-]/i,nD=/<command-name>\s*\/?([a-z0-9:_-]+)\s*<\/command-name>/i,rD=/^<local-command-(?:stdout|caveat)>/i,oD=/^\[Image: original \d+x\d+, displayed at \d+x\d+\.\s*Multiply coordinates by [\d.]+ to map to original image\.\]$/,sD=/^Continue from where you left off\.$/,aD=/^<task-notification>/i,iD=/<summary>([\s\S]*?)<\/summary>/i,cD=/<task-id>([\s\S]*?)<\/task-id>/i,lD=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i,uD=/<status>([\s\S]*?)<\/status>/i,dD=/<result>([\s\S]*?)(?:<\/result>|$)/i,N0=600,zf=new Set(["model","clear","compact","login","exit","quit"]);pD=/^\/([a-z0-9:_-]+)$/i;fD=/^\s*<bash-input>([\s\S]*?)<\/bash-input>\s*$/i,mD=/^\s*<bash-stdout>([\s\S]*?)<\/bash-stdout>\s*(?:<bash-stderr>([\s\S]*?)<\/bash-stderr>)?\s*$/i,hD=/\x1b\[[0-9;?]*[ -/]*[@-~]/g,P0=e=>String(e||"").replace(hD,"").replace(/^\n+/,"").replace(/\s+$/,"")});import gD from"node:crypto";function xD(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,H0)){let o=Ds(r?.question);if(!o)return null;let s=Array.isArray(r?.options)?r.options:[],a=[];for(let i of s.slice(0,yD)){let c=Ds(i?.label);if(!c)return null;let l=Ds(i?.description);a.push(l?{label:c,description:l}:{label:c})}if(a.length<bD)return null;n.push({question:o,header:Ds(r?.header).slice(0,kD),multiSelect:r?.multiSelect===!0,options:a})}return n.length?n:null}function Vf(e){if(typeof e!="string"||!e.includes("```bostrat-question"))return null;U0.lastIndex=0;let t=null;for(let o;o=U0.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=xD(n);return r?{text:e.slice(0,t.index).trimEnd(),questions:r}:null}function Jf(e,t,n){let r=gD.createHash("sha256").update(JSON.stringify(n)).digest("hex").slice(0,8);return`${e}:ask:${t||"turn"}:${r}`}function Yf(e,{leadBoxId:t,provider:n,isAnswered:r,maxQuestions:o=H0}={}){if(!Array.isArray(e)||!t||!n)return null;let s=null;for(let l=e.length-1;l>=0;l--){let u=e[l];if(u?.kind==="prompt")return null;if(u?.kind==="message"){if(u.role!=="assistant")return null;s=u;break}}if(!s||s.box!==t||s.agent!==n)return null;let a=s.ask?.questions||Vf(s.text)?.questions;if(!a?.length)return null;let i=a.slice(0,Math.max(1,o)),c=Jf(n,s.sourceId||s.id,a);return typeof r=="function"&&r(c)?null:{provider:n,box:t,promptId:c,groupId:c,answerMode:"say",source:"transcript",custom:!0,dismissable:!0,multiSelect:i[0].multiSelect,questionIndex:0,questionTotal:i.length,questions:i}}function q0(e,t,n,r){let o=[];(e?.questions||[]).forEach((i,c)=>{let l=(t?.[c]||[]).map(d=>i.options?.[d]?.label).filter(Boolean),u=Ds(Array.isArray(r)?r[c]:"");u&&l.push(u),l.length&&o.push({name:i.header||i.question,picks:l.join(", ")})});let s=Ds(n),a;return o.length?o.length===1?a=`${o[0].name}: ${o[0].picks}`:a=`Answers:
128
+ - `).length-1,indexed:i.N}):{appended:!1,reason:"no-hits",indexed:i.N}}catch(a){return{appended:!1,reason:"error",error:a?.message||String(a)}}}var W0,K0=G(()=>{om();W0="Relevant prior discussion (verbatim, retrieved"});function dD(e){return aD.test(String(e||"").trimStart())}function V0(e){let t=String(e||"");if(!dD(t.trimStart()))return null;let n=t.replace(iD,"").trim(),r=pD(n),o=[];for(let u of lD){let d=u.from.map(p=>Gs(r.get(p))).find(p=>p&&!G0(p));d&&o.push({h:u.h,text:Ni(d,cD)})}let s=Gs(r.get("Current Work"))||Gs(r.get("Primary Request and Intent"))||mD(n),a=iu(s),i=Ni(au(im(a[0]||"")),uD)||"Context resumed from summary",c=[],l=a.slice(1).join(" ").trim();l&&c.push(Ni(au(im(l)),am));for(let u of["Pending Tasks","Optional Next Step"]){let d=iu(Gs(r.get(u)))[0]||"";if(!(!d||G0(d))){c.push(Ni(`Left to do: ${au(im(d))}`,am));break}}if(!c.length){let u=iu(Gs(r.get("Problem Solving"))||"")[0];u&&c.push(Ni(au(u),am))}return{kind:"resume-summary",title:i,bullets:c.slice(0,2),sections:o,rawChars:t.length}}function pD(e){let t=new Map,n=[];sm.lastIndex=0;for(let r=sm.exec(e);r;r=sm.exec(e))n.push({name:fD(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 fD(e){return z0.find(n=>n.toLowerCase()===e.toLowerCase())||e}function Gs(e){return e?String(e).replace(/```[\s\S]*?(?:```|$)/g," ").split(`
129
+ `).map(t=>t.replace(/^[ \t]*(?:[-*•]|\d+[.)]|[a-z][.)])[ \t]+/i,"").trim()).filter(t=>t&&!/^#{1,6}[ \t]/.test(t)).join(" ").replace(/\*\*(.+?)\*\*/g,"$1").replace(/`([^`]+)`/g,"$1").replace(/\s+/g," ").trim():""}function mD(e){let t=e.replace(/^[\s\S]*?\bSummary:\s*/i,"");return Gs(t.split(/\n{2,}/).slice(0,2).join(" "))}function iu(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 im(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 au(e){return String(e||"").replace(/(?<![:\w/])(?:\/[\w.@+-]+){4,}/g,t=>`\u2026/${t.split("/").slice(-2).join("/")}`)}function G0(e){return/^(none|nothing|n\/a|no pending|there are no)\b/i.test(String(e||"").trim())}function Ni(e,t){let n=String(e||"").trim();if(n.length<=t)return n;let r=iu(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 aD,z0,sm,iD,cD,lD,uD,am,J0=G(()=>{aD=/^This session is being continued from a previous conversation that ran out of context\./,z0=["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"],sm=new RegExp(String.raw`^[ \t]*#{0,4}[ \t]*(?:\d+[.)][ \t]*)?\*{0,2}(${z0.join("|")})[:*\t ]*$`,"gim"),iD=/\n+If you need specific details from before compaction[\s\S]*$|\n+Continue the conversation from where it left off[\s\S]*$/,cD=420,lD=[{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"]}],uD=116,am=168});function Z0(e){return cm.has(String(e||"").replace(/^\//,"").toLowerCase())}function Pi(e){let t=String(e||"").trim();if(!t)return null;let n=V0(t);if(n)return n;let r=t.match(hD);if(r)return{kind:"skill",name:r[1].split("/").filter(Boolean).pop()||"skill"};let o=t.match(wD);if(o)return{kind:"skill",name:o[1]};let s=t.match(gD);if(s)return{kind:"skill",name:s[1].toLowerCase()};let a=t.match(yD);if(a){let c=a[1].toLowerCase();return cm.has(c)?{kind:"suppress"}:{kind:"command",command:`/${c}`}}let i=t.match(ID);if(i&&cm.has(i[1].toLowerCase()))return{kind:"suppress"};if(bD.test(t))return{kind:"suppress"};if(xD.test(t))return{kind:"suppress"};if(kD.test(t))return{kind:"suppress"};if(vD.test(t)){let c=u=>MD(t.match(u)?.[1].trim()||"")||null,l=c(_D);return{kind:"task",summary:c(SD)||"",taskId:c(AD),toolUseId:c(TD),status:c(ED)?.toLowerCase()||null,resultHead:l?l.length>Y0?`${l.slice(0,Y0).trimEnd()}\u2026`:l:null}}return null}function Q0(e){let t=Pi(e?.text);return t||(e?.injected?{kind:"skill",name:e.injected.skill||"skill"}:null)}function ex(e){let t=String(e||""),n=t.match($D);if(n)return{kind:"shell-input",command:n[1].trim()};let r=t.match(RD);return r?{kind:"shell-output",stdout:X0(r[1]),stderr:X0(r[2])}:null}function MD(e){return e.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&amp;/g,"&")}function tx(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 nx(e){return e?.kind==="skill"?"skill-run":e?.kind==="task"?"task-done":e?.kind==="resume-summary"?"context-resumed":"command-run"}var hD,wD,gD,yD,bD,kD,xD,vD,SD,AD,TD,ED,_D,Y0,cm,ID,$D,RD,OD,X0,cu=G(()=>{J0();hD=/^Base directory for this skill:\s*(\S+)/,wD=/^Run the "([^"]+)" workflow\./,gD=/^#\s*\/([a-z0-9:_-]+)\s*[—–:-]/i,yD=/<command-name>\s*\/?([a-z0-9:_-]+)\s*<\/command-name>/i,bD=/^<local-command-(?:stdout|caveat)>/i,kD=/^\[Image: original \d+x\d+, displayed at \d+x\d+\.\s*Multiply coordinates by [\d.]+ to map to original image\.\]$/,xD=/^Continue from where you left off\.$/,vD=/^<task-notification>/i,SD=/<summary>([\s\S]*?)<\/summary>/i,AD=/<task-id>([\s\S]*?)<\/task-id>/i,TD=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i,ED=/<status>([\s\S]*?)<\/status>/i,_D=/<result>([\s\S]*?)(?:<\/result>|$)/i,Y0=600,cm=new Set(["model","clear","compact","login","exit","quit"]);ID=/^\/([a-z0-9:_-]+)$/i;$D=/^\s*<bash-input>([\s\S]*?)<\/bash-input>\s*$/i,RD=/^\s*<bash-stdout>([\s\S]*?)<\/bash-stdout>\s*(?:<bash-stderr>([\s\S]*?)<\/bash-stderr>)?\s*$/i,OD=/\x1b\[[0-9;?]*[ -/]*[@-~]/g,X0=e=>String(e||"").replace(OD,"").replace(/^\n+/,"").replace(/\s+$/,"")});import CD from"node:crypto";function BD(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,ox)){let o=zs(r?.question);if(!o)return null;let s=Array.isArray(r?.options)?r.options:[],a=[];for(let i of s.slice(0,ND)){let c=zs(i?.label);if(!c)return null;let l=zs(i?.description);a.push(l?{label:c,description:l}:{label:c})}if(a.length<PD)return null;n.push({question:o,header:zs(r?.header).slice(0,DD),multiSelect:r?.multiSelect===!0,options:a})}return n.length?n:null}function lm(e){if(typeof e!="string"||!e.includes("```bostrat-question"))return null;rx.lastIndex=0;let t=null;for(let o;o=rx.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=BD(n);return r?{text:e.slice(0,t.index).trimEnd(),questions:r}:null}function um(e,t,n){let r=CD.createHash("sha256").update(JSON.stringify(n)).digest("hex").slice(0,8);return`${e}:ask:${t||"turn"}:${r}`}function dm(e,{leadBoxId:t,provider:n,isAnswered:r,maxQuestions:o=ox}={}){if(!Array.isArray(e)||!t||!n)return null;let s=null;for(let l=e.length-1;l>=0;l--){let u=e[l];if(u?.kind==="prompt")return null;if(u?.kind==="message"){if(u.role!=="assistant")return null;s=u;break}}if(!s||s.box!==t||s.agent!==n)return null;let a=s.ask?.questions||lm(s.text)?.questions;if(!a?.length)return null;let i=a.slice(0,Math.max(1,o)),c=um(n,s.sourceId||s.id,a);return typeof r=="function"&&r(c)?null:{provider:n,box:t,promptId:c,groupId:c,answerMode:"say",source:"transcript",custom:!0,dismissable:!0,multiSelect:i[0].multiSelect,questionIndex:0,questionTotal:i.length,questions:i}}function sx(e,t,n,r){let o=[];(e?.questions||[]).forEach((i,c)=>{let l=(t?.[c]||[]).map(d=>i.options?.[d]?.label).filter(Boolean),u=zs(Array.isArray(r)?r[c]:"");u&&l.push(u),l.length&&o.push({name:i.header||i.question,picks:l.join(", ")})});let s=zs(n),a;return o.length?o.length===1?a=`${o[0].name}: ${o[0].picks}`:a=`Answers:
130
130
  ${o.map(i=>`- ${i.name}: ${i.picks}`).join(`
131
131
  `)}`:a=s,o.length&&s&&(a+=`
132
- ${s}`),a||""}var H0,yD,bD,kD,U0,Ds,W0,Xf=G(()=>{H0=4,yD=4,bD=2,kD=24,U0=/^[ \t]{0,3}(`{3,})bostrat-question[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]{0,3}\1`*[ \t]*$/gm,Ds=e=>typeof e=="string"?e.trim():"";W0=`
132
+ ${s}`),a||""}var ox,ND,PD,DD,rx,zs,ax,pm=G(()=>{ox=4,ND=4,PD=2,DD=24,rx=/^[ \t]{0,3}(`{3,})bostrat-question[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]{0,3}\1`*[ \t]*$/gm,zs=e=>typeof e=="string"?e.trim():"";ax=`
133
133
  When you are BLOCKED on a decision only the operator can make \u2014 an ambiguous
134
134
  requirement, an irreversible choice, several valid approaches \u2014 do not bury the
135
135
  question in prose. End your message with exactly ONE fenced code block tagged
@@ -150,101 +150,105 @@ your turn. The operator sees the questions as an interactive card in their chat
150
150
  They may instead reply in free text \u2014 treat that as the answer. Never use the block for rhetorical questions, progress updates, or
151
151
  anything you can decide yourself; keep asking in prose for questions without
152
152
  enumerable options.
153
- `});function vD(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 G0(e,t,n){let r=Zf(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 _n(e){let t=[],n=new Set,r=new Set,o=new Map,s=new Map,a=new Set,i=new Map,c=new Map,l=new Set,u=new Map,d=new Map,p=(k,h)=>{d.set(k,h),t.push(h)},f=k=>{let h=d.get(k);h&&(h.retired=!0)},w=/^Agent "([\s\S]+)" finished$/,m=new Map;for(let k of e||[]){if(k.type!=="tool.called"||k.source!=="transcript")continue;let h=String(k.payload?.command||"");if(/\bbostrat-mock\s+(?:add|update)\b/.test(h))for(let v of h.matchAll(/[\w./~-]+\.(?:png|jpe?g|gif|webp|bmp|svg)\b/gi)){let P=v[0].split("/").pop().toLowerCase();m.has(P)||m.set(P,[]),m.get(P).push(k.payload?.ts??k.ts)}}let g=3*6e4,y=20*6e4,x=(k,h)=>!!(k?.name&&m.get(String(k.name).toLowerCase()))?.some(P=>P>=h-g&&P<=h+y);for(let k of e||[])if(k.type==="turn.retracted"){r.add(`${k.boxId}|${k.payload?.saidTs}`);let h=Fe(k.payload?.text);h&&(o.has(k.boxId)||o.set(k.boxId,[]),o.get(k.boxId).push(h))}else if(k.type==="turn.user"&&k.source==="orchestrator"){let h=Fe(k.payload?.text);h&&(s.has(k.boxId)||s.set(k.boxId,new Set),s.get(k.boxId).add(h))}else if(k.type==="job.stalled"&&k.payload?.id)i.set(k.payload.id,{ts:pe(k),quietMs:Number(k.payload.quietMs)||null});else if(k.type==="job.started"&&k.payload?.id)a.add(k.payload.id),(k.payload.kind||"agent")==="agent"&&k.payload.name&&l.add(k.payload.name);else if(k.type==="turn.user"&&k.payload?.note?.kind==="task"){let h=k.payload.note,v={status:h.status||null,summary:h.summary||null,resultHead:h.resultHead??null,ts:pe(k)};h.toolUseId&&c.set(h.toolUseId,v);let P=String(h.summary||"").match(w);P&&u.set(P[1],v)}let b=new Map,O=new Map,$=null,C=new Map,L=new Map,q=new Map,I=new Map,_=new Map,F=new Map,V=new Map,A=new Map,E=new Map,N=new Map,H=new Map,z=new Map,fe=new Map,me=new Map,Se=new Map,Ae=[],W=k=>Ae.push(k),te=k=>{if(!Ae.length)return;let h=pe(k);for(let v of Ae){if(v.status!=="open"||v.box&&v.box!==k.boxId||(v.ts??0)>h)continue;let P=t.indexOf(v);P>=0&&t.splice(P,1),v.ts=h,t.push(v)}},le=new Map,J=new Map,ye=new Map,Ce=new Map,Ne=new Map,R=new Map,D=new Map,ue=new Map,Le=()=>{for(let k of ue.values())k.questions.length&&t.push(k);ue.clear()},Me=null,Ht=new Map,St=6e4,Gn=new Map,xn=(k,h)=>{let v=o.get(k);if(!v?.length)return!1;let P=Fe(h),ne=s.get(k);return v.some(ge=>{if(!P.startsWith(ge))return!1;let Oe=Fe(P.slice(ge.length));return!!Oe&&!!ne?.has(Oe)})};for(let k of e||[]){let h=k.payload||{};switch(k.type){case"turn.user":{if(k.source==="hook"||(Ae.length=0,!String(h.text||"").trim()&&!h.images?.length&&!h.attachments?.length))break;{let v=j0(h.text);if(v){if(v.kind==="shell-input"){let P={id:k.id,kind:"shell",command:v.command,stdout:null,stderr:null,done:!1,ts:pe(k),box:k.boxId,agent:k.provider};t.push(P),Ht.set(k.boxId,P)}else{let P=Ht.get(k.boxId);P?(P.stdout=v.stdout||null,P.stderr=v.stderr||null,P.done=!0,Ht.delete(k.boxId)):t.push({id:k.id,kind:"shell",command:null,stdout:v.stdout||null,stderr:v.stderr||null,done:!0,ts:pe(k),box:k.boxId,agent:k.provider})}break}}{let v=h.note||Ii(h.text);if(v){if(v.kind==="task"){if(v.toolUseId&&a.has(v.toolUseId))break;let P=String(v.summary||"").match(w);if(!v.toolUseId&&P&&l.has(P[1]))break}if(v.kind==="command"&&D0(v.command))break;if(v.kind==="resume-summary"){t.push({id:k.id,kind:"resume-summary",title:v.title||"Context resumed from summary",bullets:v.bullets||[],sections:v.sections||[],rawChars:v.rawChars??null,ts:pe(k),box:k.boxId,agent:k.provider});break}v.kind!=="suppress"&&t.push({id:k.id,kind:"event",type:F0(v),name:v.name??null,command:v.command??null,summary:v.summary??null,status:v.status??null,ts:pe(k),box:k.boxId,agent:k.provider});break}}if(r.has(`${k.boxId}|${pe(k)}`)||k.source==="transcript"&&xn(k.boxId,h.text))break;if(h.kind==="merge-notify"||h.kind==="ship-notify"){t.push({id:k.id,kind:"event",type:h.kind==="ship-notify"?"ship-notified":"merge-notified",text:h.text,ts:pe(k),box:k.boxId,agent:k.provider});break}if(h.kind==="mock-picked"||h.kind==="ci-fix"||h.kind==="reconcile"||h.kind==="pr-go"||h.kind==="push-go"||h.kind==="spin-up-view"||h.kind==="prompt-answer"||h.kind==="followup-go"){h.kind==="prompt-answer"&&(Me=null);break}for(let v of C.values())v.status="stale";C.clear();for(let v of q.values())v.status="stale";q.clear();for(let v of fe.values())v.status="stale";fe.clear(),Me&&Me.box===k.boxId&&(t.push(vD(Me)),Me=null),t.push({id:k.id,kind:"message",role:"user",text:h.text,ts:pe(k),box:k.boxId,agent:k.provider,boxRole:h.boxRole,...k.actor==="orchestrator"?{orchestration:h.kind||!0}:{},...h.sourceId?{sourceId:h.sourceId}:{},...h.attachments?.length?{attachments:h.attachments}:{},...h.images?.length?{images:h.images}:{}});break}case"peer.message":{let v=h.from||{};t.push({id:k.id,kind:"event",type:"peer-message",text:h.text,from:v.trackName||v.boxId||v.name||null,fromTrackId:v.trackId||null,ts:pe(k),box:k.boxId,agent:k.provider});break}case"turn.agent":{if(h.model==="<synthetic>"&&/^No response requested\.$/.test(String(h.text||"").trim()))break;let v=Jk(h,{codexFailedText:_o});if(v){t.push({id:k.id,kind:"event",type:"provider-error",cls:v.cls,status:v.status??void 0,text:v.text,provider:k.provider,legacy:!0,at:pe(k),ts:pe(k),box:k.boxId,agent:k.provider});break}Le();let P=(h.images||[]).filter(Ge=>!x(Ge,pe(k)));if(!String(h.text||"").trim()&&!P.length)break;if(k.provider==="cursor"){let Ge=`${k.boxId}|${h.text}`;if(n.has(Ge))break;n.add(Ge)}(!Me||Me.box===k.boxId)&&(Me=null);let ne=k.provider==="codex"?(h.tools||[]).filter(Ge=>!_f.has(Ge)&&!mi.has(Ge)):h.tools||[],ge=h.text,Oe=null,tt=Vf(String(h.text||""));tt&&(ge=tt.text,Oe={questions:tt.questions}),t.push({id:k.id,kind:"message",role:"assistant",text:ge,ts:pe(k),box:k.boxId,agent:k.provider,boxRole:h.boxRole,...Oe?{ask:Oe}:{},...ne.length?{tools:ne}:{},...h.model?{model:h.model}:{},...h.sourceId?{sourceId:h.sourceId}:{},...P.length?{images:P}:{}}),te(k),Oe&&(Me={id:k.id,groupId:Jf(k.provider,h.sourceId||k.id,Oe.questions),provider:k.provider,box:k.boxId,questions:Oe.questions,ts:pe(k)});break}case"job.started":{if(!h.id)break;let v=pe(k),P=c.get(h.id);if(!P&&(h.kind||"agent")==="agent"&&h.name){let qt=u.get(h.name);qt&&qt.ts>=v&&(P=qt)}let ne=P?null:i.get(h.id)||null,ge={jobId:h.id,jobKind:h.kind||"agent",name:h.name||null,detail:h.detail||null,status:P?P.status==="killed"?"stopped":P.status&&P.status!=="completed"?"failed":"done":ne?"stalled":"running",startedTs:v,finishedTs:P?.ts??ne?.ts??null,quietMs:ne?.quietMs??null,summary:P?.summary??null,resultHead:P?.resultHead??null},Oe=Gn.get(k.boxId),tt=Oe?.jobs[Oe.jobs.length-1]?.startedTs;if(Oe&&tt!=null&&v-tt<=St)Oe.jobs.push(ge);else{let qt={id:k.id,kind:"job-dock",dockId:h.id,ts:v,box:k.boxId,agent:k.provider,jobs:[ge]};Gn.set(k.boxId,qt),t.push(qt)}break}case"handoff.done":t.push(lt(k,"lead-handoff"));break;case"subtask.delegated":t.push({...lt(k,"subtask-delegated"),to:k.boxId,toAgent:k.provider});break;case"subtask.merged":t.push(lt(k,"subtask-merged"));break;case"pr.state.changed":{if(!h.change)break;if(h.change==="opened"){for(let P of C.values())P.status="stale";C.clear();for(let P of q.values())P.status="stale";q.clear()}let v=lt(k,`pr-${h.change}`);if(v.box=k.boxId??null,K0.has(h.change)&&h.number!=null){let P=G0(b,O,h);if(b.size>=2){for(let ge of O.values())for(let Oe of ge)Oe.grouped=!0;v.groupPrs=[...b.values()];let ne=[v];for(let ge of b.keys())O.set(ge,ne)}else{let ne=O.get(P)??[];ne.push(v),O.set(P,ne)}}else if(h.change==="merged"||h.change==="closed"||h.change==="lost"){let P=Zf(h),ne=$&&!$.complete||b.size>=2;if(b.has(P))b.delete(P),O.delete(P);else if(h.number!=null)for(let ge of[...b.keys()])ge.endsWith(`#${h.number}`)&&(b.delete(ge),O.delete(ge));if(ne&&h.number!=null){(!$||$.complete)&&($={id:k.id,kind:"event",type:"pr-group-settled",prs:[],remaining:[],complete:!1,at:pe(k),ts:pe(k),box:k.boxId,agent:k.provider},t.push($)),$.prs.push({number:h.number,url:h.url??null,title:h.title??null,repo:h.repo??null,branch:h.branch??null,change:h.change,ts:pe(k)}),$.remaining=[...b.values()],$.complete=b.size===0;break}}t.push(v);break}case"pr.offered":{if(!h.offerId)break;for(let P of C.values())P.status="stale";C.clear();for(let P of q.values())P.status="stale";q.clear();let v={id:k.id,kind:"pr-offer",offerId:h.offerId,excerpt:h.excerpt||null,branch:h.branch||null,base:h.base||null,offered:Array.isArray(h.offered)&&h.offered.length?h.offered:null,toPr:h.toPr&&typeof h.toPr=="object"?{number:h.toPr.number??null}:null,available:Array.isArray(h.available)?h.available:null,defaults:Array.isArray(h.defaults)?h.defaults:null,prState:h.prState||null,openPr:h.openPr&&typeof h.openPr=="object"?h.openPr:null,repos:Array.isArray(h.repos)&&h.repos.length?h.repos:null,status:"open",source:k.source==="cli"||h.via==="cli"?"cli":"transcript",ts:pe(k),box:k.boxId,agent:k.provider};C.set(h.offerId,v),L.set(h.offerId,v),t.push(v),v.source==="cli"&&W(v);break}case"pr.offer.answered":{let v=L.get(h.offerId);v&&(v.status=h.action||"dismiss",v.actions=Array.isArray(h.actions)?h.actions:null,v.notify=h.notify===!0,h.existingPr&&typeof h.existingPr=="object"&&(v.existingPr={number:h.existingPr.number??null}),C.delete(h.offerId));break}case"pr.exists.offered":{if(!h.offerId)break;for(let P of q.values())P.status="stale";q.clear();let v={id:k.id,kind:"pr-exists-offer",offerId:h.offerId,srcOfferId:h.srcOfferId??null,branch:h.branch||null,base:h.base||null,pr:h.pr&&typeof h.pr=="object"?{number:h.pr.number??null,url:h.pr.url??null,title:h.pr.title??null}:null,actions:Array.isArray(h.actions)&&h.actions.length?h.actions:null,notify:h.notify===!0,status:"open",ts:pe(k),box:k.boxId,agent:k.provider};q.set(h.offerId,v),I.set(h.offerId,v),t.push(v);break}case"pr.exists.answered":{let v=I.get(h.offerId);v&&(v.status=h.choice||"dismiss",q.delete(h.offerId));break}case"box.state.changed":{let v=h.change==="model"?"model-change":h.change;if(!v)break;let P=lt(k,v);if(v==="model-change"&&(P.to=h.model),v==="node-update"&&P.latest){let ne=t.findIndex(ge=>ge.kind==="event"&&ge.type==="node-update"&&ge.latest===P.latest);if(ne>=0){let ge=t[ne];t[ne]={...P,ts:ge.ts,at:ge.at,firstAt:ge.firstAt??ge.ts,updatedAt:P.ts};break}}t.push(P);break}case"track.transferred":case"track.recovered":t.push(lt(k,"track-moved"));break;case"view.state.changed":{if(h.change==="deleted"){f(`view:${h.viewId}`);break}if(h.change!=="created"||h.restarted)break;p(`view:${h.viewId}`,{id:k.id,kind:"view-card",viewId:h.viewId,name:h.name,slug:h.slug,port:h.port,origin:h.origin,ts:pe(k),box:k.boxId,agent:k.provider});break}case"view.spinup.failed":{t.push({id:k.id,kind:"view-spinup-failed",name:h.name||null,reason:h.reason||"no-view",ts:pe(k),box:k.boxId,agent:k.provider});break}case"mock.state.changed":{if(h.change==="picked"){t.push({id:k.id,kind:"mock-picked",mockId:h.mockId,name:h.name,group:h.group??null,version:h.version??null,siblings:h.siblings??[],ts:pe(k),box:k.boxId,agent:k.provider});break}if(h.change==="deleted"){f(`mock:${h.mockId}`);break}if(h.change!=="created")break;p(`mock:${h.mockId}`,{id:k.id,kind:"mock-card",mockId:h.mockId,name:h.name,group:h.group??null,ts:pe(k),box:k.boxId,agent:k.provider});break}case"flow.state.changed":{if(h.change==="deleted"){f(`flow:${h.flowId}`);break}if(h.change!=="created")break;p(`flow:${h.flowId}`,{id:k.id,kind:"flow-card",flowId:h.flowId,name:h.name,stepCount:h.stepCount??null,mockIds:h.mockIds??[],ts:pe(k),box:k.boxId,agent:k.provider});break}case"runbook.state.changed":{if(h.change==="deleted"){f(`runbook:${h.runbookId}`);break}if(h.change!=="created")break;p(`runbook:${h.runbookId}`,{id:k.id,kind:"runbook-card",runbookId:h.runbookId,name:h.name,ts:pe(k),box:k.boxId,agent:k.provider});break}case"ticket.linked":{t.push({id:k.id,kind:"ticket-card",provider:h.provider||"linear",key:h.key,url:h.url,title:h.title??null,linkSource:h.linkSource??null,ts:pe(k),box:k.boxId,agent:k.provider});break}case"box.fullscreen.detected":{if(!h.offerId)break;for(let P of V.values())P.box===(h.box||k.boxId)&&(P.status="stale",V.delete(P.offerId));let v={id:k.id,kind:"fullscreen-offer",offerId:h.offerId,status:"open",ts:pe(k),box:h.box||k.boxId,agent:h.agent||k.provider};V.set(h.offerId,v),A.set(h.offerId,v),t.push(v);break}case"box.fullscreen.answered":{let v=A.get(h.offerId);v&&(v.status=h.action==="restarted"?"restarted":h.action==="cleared"?"cleared":"dismiss",V.delete(h.offerId));break}case"ticket.move.offered":{if(!h.offerId)break;for(let P of _.values())P.key===h.key&&(P.status="stale",_.delete(P.offerId));let v={id:k.id,kind:"ticket-offer",offerId:h.offerId,provider:h.provider||"linear",key:h.key,url:h.url??null,phase:h.phase??null,from:h.from??null,to:h.to?.name??null,prNumber:h.prNumber??null,status:"open",ts:pe(k),box:k.boxId,agent:k.provider};_.set(h.offerId,v),F.set(h.offerId,v),t.push(v);break}case"ticket.move.answered":{let v=F.get(h.offerId);v&&(v.status=h.action==="moved"?"moved":"dismiss",_.delete(h.offerId));break}case"ticket.state.changed":{for(let v of _.values())v.key===h.key&&v.to===h.to&&(v.status="stale",_.delete(v.offerId));if(h.mode==="offer")break;t.push(lt(k,"ticket-state"));break}case"ticket.commented":{t.push({id:k.id,kind:"ticket-comment",key:h.key,url:h.url??null,excerpt:h.excerpt??null,ts:pe(k),box:k.boxId,agent:k.provider});break}case"ticket.flow.changed":t.push(lt(k,"ticket-flow"));break;case"ticket.create.offered":{if(!h.proposalId)break;for(let P of E.values())P.status="stale";E.clear();let v={id:k.id,kind:"ticket-create-offer",proposalId:h.proposalId,provider:h.provider||"linear",epic:h.epic??null,issues:Array.isArray(h.issues)?h.issues:[],team:h.team??null,needsTeam:!!h.needsTeam,linkCurrentTrack:!!h.linkCurrentTrack,status:"open",ts:pe(k),box:k.boxId,agent:k.provider};E.set(h.proposalId,v),N.set(h.proposalId,v),t.push(v),W(v);break}case"ticket.create.answered":{let v=N.get(h.proposalId);v&&(v.status=h.action==="created"?"created":"dismiss",v.createdCount=h.createdCount??null,v.failedCount=h.failedCount??null,E.delete(h.proposalId));break}case"loop.create.offered":{if(!h.proposalId)break;for(let P of H.values())P.status="stale";H.clear();let v={id:k.id,kind:"loop-create-offer",proposalId:h.proposalId,name:h.name??"",schedule:h.schedule??"",prompt:h.prompt??"",expectation:h.expectation??null,notify:h.notify??"off",assignment:h.assignment??{provider:"claude"},repo:h.repo??null,nodeId:h.nodeId??null,nodeName:h.nodeName??null,status:"open",ts:pe(k),box:k.boxId,agent:k.provider};H.set(h.proposalId,v),z.set(h.proposalId,v),t.push(v),W(v);break}case"loop.create.answered":{let v=z.get(h.proposalId);v&&(v.status=h.action==="created"?"created":"dismiss",H.delete(h.proposalId));break}case"followup.armed":{if(!h.armId)break;let v=h.replaces?Se.get(h.replaces):null;v&&v.status==="armed"&&(v.status="replaced");let P={id:k.id,kind:"followup-armed",armId:h.armId,trigger:h.trigger??"now",label:h.label??"",prompt:h.prompt??"",why:h.why??null,status:"armed",ts:pe(k),box:k.boxId,agent:k.provider};Se.set(h.armId,P),P.trigger!=="now"&&t.push(P);break}case"followup.armed.cancelled":{let v=Se.get(h.armId);v&&v.status==="armed"&&(v.status="cancelled");break}case"followup.offered":{if(!h.offerId)break;for(let ne of fe.values())ne.trigger===h.trigger&&(ne.status="stale",fe.delete(ne.offerId));let v=Array.isArray(h.rows)?h.rows:[];for(let ne of v){let ge=ne.armId?Se.get(ne.armId):null;ge&&ge.status==="armed"&&(ge.status="offered")}let P={id:k.id,kind:"followup-offer",offerId:h.offerId,trigger:h.trigger??"now",repo:h.repo??null,context:h.context&&typeof h.context=="object"?h.context:{},rows:v.map(ne=>({followupId:ne.followupId??null,armId:ne.armId??null,label:ne.label??"",prompt:ne.prompt??null,promptPreview:ne.promptPreview??null,promptHash:ne.promptHash??null,origin:ne.origin??"operator",why:ne.why??null})),status:"open",answer:null,ts:pe(k),box:k.boxId,agent:k.provider};fe.set(h.offerId,P),me.set(h.offerId,P),t.push(P),P.trigger==="now"&&W(P);break}case"followup.answered":{let v=me.get(h.offerId);v&&(v.status=h.action==="sent"?"sent":h.action==="removed"?"removed":"dismiss",v.answer={followupId:h.followupId??null,armId:h.armId??null,label:h.label??null,promoted:h.promoted??null,revived:h.revived===!0},fe.delete(h.offerId));break}case"followup.create.offered":{if(!h.proposalId)break;for(let P of le.values())P.status="stale";le.clear();let v={id:k.id,kind:"followup-create-offer",proposalId:h.proposalId,label:h.label??"",prompt:h.prompt??"",trigger:h.trigger??"pr.merged",repo:h.repo??null,why:h.why??null,status:"open",created:null,ts:pe(k),box:k.boxId,agent:k.provider};le.set(h.proposalId,v),J.set(h.proposalId,v),t.push(v),W(v);break}case"followup.create.answered":{let v=J.get(h.proposalId);v&&(v.status=h.action==="created"?"created":"dismiss",le.delete(h.proposalId));break}case"followup.created":{let v=h.proposalId?J.get(h.proposalId):null;v&&(v.created={followupId:h.followupId??null});break}case"loop.created":{let v=h.proposalId?z.get(h.proposalId):null;v&&(v.created={loopId:h.loopId??null,nextFireAt:Number.isFinite(Number(h.nextFireAt))?Number(h.nextFireAt):null}),t.push(lt(k,"loop-created"));break}case"loop.update.offered":case"loop.delete.offered":{if(!h.proposalId||!h.loopId)break;for(let ne of ye.values())ne.loopId===h.loopId&&(ne.status="stale",ne.staleReason="superseded",ye.delete(ne.proposalId));let v=k.type==="loop.update.offered",P={id:k.id,kind:v?"loop-update-offer":"loop-delete-offer",proposalId:h.proposalId,loopId:String(h.loopId),name:h.name??h.base?.name??"",base:h.base??null,...v?{patch:h.patch??{},changed:Array.isArray(h.changed)?h.changed:Object.keys(h.patch||{})}:{reason:h.reason??""},selfEdit:!!h.selfEdit,status:"open",staleReason:null,ts:pe(k),box:k.boxId,agent:k.provider};ye.set(h.proposalId,P),Ce.set(h.proposalId,P),t.push(P),W(P);break}case"loop.update.answered":{let v=Ce.get(h.proposalId);v&&(h.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=h.action==="applied"?"applied":"dismiss",ye.delete(h.proposalId));break}case"loop.delete.answered":{let v=Ce.get(h.proposalId);v&&(h.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=h.action==="delete"?"deleted":h.action==="pause"?"paused":"keep",ye.delete(h.proposalId));break}case"loop.updated":{let v=h.proposalId?Ce.get(h.proposalId):null;v&&(v.applied={changed:Array.isArray(h.changed)?h.changed:[],nextFireAt:Number.isFinite(Number(h.nextFireAt))?Number(h.nextFireAt):null}),t.push(lt(k,"loop-updated"));break}case"loop.deleted":t.push(lt(k,"loop-deleted"));break;case"loop.paused":t.push(lt(k,"loop-paused"));break;case"planning.change.offered":{if(!h.proposalId||!Array.isArray(h.ops)||!h.ops.length)break;for(let P of Ne.values())P.status="stale",P.staleReason="superseded",Ne.delete(P.proposalId);let v={id:k.id,kind:"planning-offer",proposalId:h.proposalId,why:h.why??"",ops:h.ops,base:h.base??{},resolved:h.resolved??{},snapped:!!h.snapped,createsMeRow:!!h.createsMeRow,status:"open",staleReason:null,applied:null,ts:pe(k),box:k.boxId,agent:k.provider};Ne.set(h.proposalId,v),R.set(h.proposalId,v),t.push(v),W(v);break}case"planning.change.answered":{let v=R.get(h.proposalId);v&&(h.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=h.action==="applied"?"applied":"dismiss",Ne.delete(h.proposalId));break}case"planning.changed":{let v=h.proposalId?R.get(h.proposalId):null;v&&(v.applied={results:Array.isArray(h.results)?h.results:[]}),t.push(lt(k,"planning-changed"));break}case"rework.cause.offered":{if(!h.sha||D.has(h.sha))break;let v={id:k.id,kind:"rework-cause-offer",sha:h.sha,subject:h.subject??"",linesReworked:Number(h.linesReworked)||0,origins:Array.isArray(h.origins)?h.origins:[],heuristic:h.heuristic??null,intent:h.intent??null,shas:Array.isArray(h.shas)?h.shas:null,pr:h.pr??null,retracts:0,status:"open",cause:null,ts:pe(k),box:k.boxId,agent:k.provider};D.set(h.sha,v),t.push(v);break}case"rework.cause.answered":{let v=h.sha?D.get(h.sha):null;v&&(v.status="answered",v.cause=h.cause??null);break}case"rework.cause.retracted":{let v=h.sha?D.get(h.sha):null;v&&(v.status="open",v.cause=null,v.retracts=(v.retracts??0)+1);break}case"ticket.created":{let v={items:Array.isArray(h.items)?h.items:[],failed:Array.isArray(h.failed)?h.failed:[],team:h.team??null},P=h.proposalId?N.get(h.proposalId):null;if(P){P.created=v;break}t.push({id:k.id,kind:"ticket-created",...v,ts:pe(k),box:k.boxId,agent:k.provider});break}case"error":{if(!h.kind)break;t.push(lt(k,h.kind));break}case"provider.error":t.push({...lt(k,"provider-error"),provider:k.provider,box:k.boxId,agent:k.provider});break;case"usage.cap.hit":t.push(lt(k,"usage-cap-hit"));break;case"usage.cap.warning":t.push(lt(k,"usage-cap-warning"));break;case"provider.connected":{t.push({id:k.id,kind:"event",type:"provider-connected",provider:h.provider||k.provider,ts:pe(k),at:pe(k),box:k.boxId,agent:k.provider});break}case"prompt.answered":{if(Me=null,h.control||!h.question)break;let v=h.groupId||h.promptId;if(!v)break;let P=ue.get(v);P||(P={id:k.id,kind:"prompt",groupId:v,provider:k.provider,box:k.boxId,agent:k.provider,questionTotal:h.questionTotal??1,questions:[],ts:pe(k)},ue.set(v,P));let ne=h.questionIndex??0,ge={index:ne,header:h.header||"",question:h.question,multiSelect:!!h.multiSelect,chosen:Array.isArray(h.chosen)?h.chosen:[]},Oe=P.questions.findIndex(Ge=>Ge.index===ne&&Fe(Ge.question)===Fe(ge.question));Oe>=0?P.questions[Oe]=ge:P.questions.push(ge),P.questions.sort((Ge,qt)=>Ge.index-qt.index),P.questionTotal=Math.max(P.questionTotal,h.questionTotal??1),P.questions.length>=P.questionTotal&&(t.push(P),ue.delete(v));break}case"prompt.dismissed":{Me=null;let v=h.groupId||h.promptId;if(!v||!h.question)break;let ne=ue.get(v)||{id:k.id,kind:"prompt",groupId:v,provider:k.provider,box:k.boxId,agent:k.provider,questionTotal:h.questionTotal??1,questions:[],ts:pe(k)},ge=h.questionIndex??0;ne.questions.some(Oe=>Oe.index===ge&&Fe(Oe.question)===Fe(h.question))||(ne.questions.push({index:ge,header:h.header||"",question:h.question,multiSelect:!!h.multiSelect,chosen:[]}),ne.questions.sort((Oe,tt)=>Oe.index-tt.index)),ne.answeredVia="chat",t.push(ne),ue.delete(v);break}default:break}}let yt=d.size?t.filter(k=>!k.retired):t;return TD(yt.sort((k,h)=>(k.ts??0)-(h.ts??0)))}function TD(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<=SD){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 Qf(e,t=null){let n=[];for(let o of e||[]){if(o.type!=="tool.called"||o.source!=="transcript")continue;let s=o.payload||{};String(s.command||"").trim()&&n.push({id:s.id??null,tool:s.tool||null,command:s.command,description:s.description||"",summary:AD(s),ts:s.ts??o.ts,n:s.n,box:o.boxId,agent:o.provider,boxRole:s.boxRole})}if(!n.length)return[];let r=(t??_n(e)).filter(o=>o.kind==="message");return Uk(n,r)}function AD(e){let t=String(e.summary||"").trim();return t&&t!==e.command&&t!==Rs(e.command)?t:Mr(e.command,e.description||"")}function lt(e,t){let{ts:n,change:r,...o}=e.payload||{};return{id:e.id,kind:"event",type:t,...o,at:pe(e),ts:pe(e)}}function z0(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)+ED,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||a?.kind==="event"&&_D.has(a.type))break;s++}s>n&&t.splice(s,0,...t.splice(n,1)),n=s}return t}function V0(e){let t=[...e];for(let n=0;n<t.length;n++){let r=t[n];if(r?.kind!=="event"||!$D.has(r.type)||!r.box)continue;let o=(r.ts??0)+ID,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||!(a?.kind==="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 ou(e){return(e||[]).filter(t=>RD.has(t?.kind)&&t.status==="open")}function J0(e){let t=new Map,n=new Map;for(let r of e||[]){if(r.type!=="pr.state.changed")continue;let o=r.payload||{};if(K0.has(o.change)&&o.number!=null)G0(t,n,o);else if(o.change==="merged"||o.change==="closed"||o.change==="lost"){let s=Zf(o);if(t.has(s))t.delete(s);else if(o.number!=null)for(let a of[...t.keys()])a.endsWith(`#${o.number}`)&&t.delete(a)}}return[...t.values()]}var pe,K0,Zf,SD,ED,_D,ID,$D,RD,su=G(()=>{Os();Io();Kl();vi();ru();Xf();pe=e=>e.payload?.ts??e.ts;K0=new Set(["opened","ci-fixed","reconciled","pushed"]),Zf=e=>`${e.repo??""}#${e.number}`;SD=2*6e4;ED=12e4,_D=new Set(["archived","unarchived","opened"]);ID=2500,$D=new Set(["pr-opened","pr-merged","pr-auto-armed"]);RD=new Set(["pr-offer","pr-exists-offer","ticket-offer","ticket-create-offer","loop-create-offer","loop-update-offer","loop-delete-offer","planning-offer","fullscreen-offer","followup-create-offer"])});function PD(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 BD(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 jD(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<CD&&(o.add(c.path),n.push(c.path)),c.head&&!s.has(c.head)&&r.length<ND&&(s.add(c.head),r.push(c.head))}return{files:n,heads:r}}function Q0(e,{trackName:t="this Track",now:n=null,mode:r="failover"}={}){let o=PD(e),s=BD(e),a=s?.payload?.content??null,i=s?s.payload?.ts??s.ts??null:null,c=_n(e??[]).filter(p=>p?.kind==="message"&&typeof p.text=="string"&&p.text.trim()).slice(-OD);if(!a&&!c.length)return null;let l=[];if(l.push(`# Reconstructed resume brief \u2014 ${t}`),l.push(""),l.push(Z0[r]??Z0.failover),l.push(""),o.lastPush?.sha){let p=X0(n,o.lastPush.ts),f=p?` (~${p} min before the loss)`:"";l.push(`**Code state:** last pushed ref \`${o.lastPush.ref}\` @ \`${o.lastPush.sha.slice(0,12)}\`${f}`+(o.lastPush.wip?" \u2014 a bostrat WIP snapshot (full working tree incl. uncommitted edits at push time).":"."))}else r==="in-place"?l.push("**Code state:** no push recorded \u2014 the working tree in this workspace is the only copy; commit early."):l.push("**Code state:** no push was ever recorded for this Track \u2014 work since the branch's last known state stayed on the offline node.");if(l.push(""),a){let p=X0(n,i);l.push(`## Last real checkpoint (written by the previous agent${p?`, ~${p} min before this reconstruction`:""})`),l.push(""),l.push(a.trim()),l.push("")}let u=jD(e??[],i);if((u.files.length||u.heads.length)&&(l.push(`## Work since ${a?"that checkpoint":"the start of the log"} (from the event log)`),l.push(""),u.files.length&&l.push(`Files touched (most recent first): ${u.files.map(p=>`\`${p}\``).join(", ")}`),u.heads.length&&(u.files.length&&l.push(""),l.push(`Commands run (most recent first): ${u.heads.map(p=>`\`${p}\``).join(" \xB7 ")}`)),l.push("")),c.length){l.push(`## Recent conversation (last ${c.length} message${c.length===1?"":"s"})`),l.push("");for(let p of c)l.push(`**${p.role==="user"?"operator":"agent"}:** ${DD(p.text,MD)}`),l.push("")}l.push("---"),l.push("Resume: continue the objective above from the verified repository state; ask the operator before redoing anything the log says was already done.");let d=l.join(`
154
- `);return d.length<=Y0?d:`${d.slice(0,Y0)}
155
-
156
- [\u2026 brief truncated]`}var OD,MD,Y0,CD,ND,DD,X0,Z0,ex=G(()=>{su();OD=12,MD=2e3,Y0=48e3,CD=30,ND=10;DD=(e,t)=>{let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1)}\u2026`},X0=(e,t)=>e&&t?Math.max(1,Math.round((e-t)/6e4)):null;Z0={failover:"**This is a reconstruction, not a checkpoint.** The node this Track lived on went offline without a clean handoff; bostrat assembled this brief from the durable event log. Treat every claim below as a lead, not a fact \u2014 **verify the repository state first** (git status, git log, the diff against the last pushed ref) before continuing work.","in-place":"**This is a reconstruction, not a checkpoint.** The previous lead ended without writing one (out of credits, capped, or unresponsive); bostrat assembled this status from the Track's event log. You are in the SAME live workspace \u2014 uncommitted work is present locally. **Run git status and git log first** and treat every claim below as a lead, not a fact.",get recover(){return this.failover},transfer:"**This Track was MOVED to a new machine while it was alive.** The previous node checkpointed and pushed its work as part of the move; this workspace was re-created from that push (uncommitted work re-applied when possible). **Run git status and git log to confirm what carried over**, then continue the objective below."}});import LD from"node:fs";import Nr from"node:fs/promises";import Pr from"node:path";function cx(e){let t=vo(String(e??"")),n=Buffer.byteLength(t,"utf8");return n<=tx?{content:t,bytes:n,truncated:!1}:{content:`${Buffer.from(t,"utf8").subarray(0,tx).toString("utf8").replace(/�+$/,"")}
157
-
158
- [\u2026 truncated by bostrat at 32 KiB \u2014 full artifact in the workspace]`,bytes:n,truncated:!0}}function VD(e){let t=String(e||"").split(/\r?\n/).map(s=>s.trim()).filter(Boolean),n=[],r=[];for(let s of t)if(rx.test(s)){if(r.length>=mx)continue;let a=zD(s.replace(rx,"").replace(/[.;,:]+$/,""),hx,KD);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>nx&&(o=`${o.slice(0,nx-1).trimEnd()}\u2026`),{text:o,items:r.length>1?r:[]}}async function wx(e,t,{timeoutMs:n=9e4}={}){let r=Pr.join(t,qD),o=Pr.join(r,WD);await Nr.mkdir(r,{recursive:!0});let s=await au(o),a=await ke(e);if(!a)throw new Error(`session "${e}" not found`);return await iu(e,a,GD(o)),await Sx(o,s,n),VD(await Nr.readFile(o,"utf8"))}function gx(e,t){let n=(t||"").trim();if(!n)return!1;if(e==="assistant")return n===ux||n===fx;let r=n.replace(/^\/[a-z0-9:_-]+\s+/i,"");return r.startsWith(lx)||n===FD||r.startsWith(dx)||r.startsWith(px)}function yx(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-JD;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 bx(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 kx(e,{windows:t=[]}={}){if(gx(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 cu(e){return em.get(e)||null}async function xx(e){let t=em.get(e);if(t&&!t.finishedAt)throw new Error("a handoff is already running for this session");let n=await ke(e);if(!n)throw new Error(`session "${e}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${e}"`);let r={name:e,step:"summarize",startedAt:Date.now(),finishedAt:null,error:null,file:Pr.join(n.cwd,ax,ix)};return em.set(e,r),ZD(r,n.cwd).catch(o=>{r.error=o?.message||String(o),r.finishedAt=Date.now()}),r}async function ZD(e,t){e.step="summarize",await vx(e.name,t),e.step="clear";let n=await ke(e.name);await iu(e.name,n,"/clear"),await rm(YD),e.step="resume",await iu(e.name,n,HD),e.step="done",e.finishedAt=Date.now()}async function vx(e,t,{timeoutMs:n=XD}={}){let r=Pr.join(t,ax),o=Pr.join(r,ix);await Nr.mkdir(r,{recursive:!0});let s=await au(o),a=await ke(e);await ie({flow:"checkpoint",phase:"summarize-start",sessionName:e,cwd:t,file:o,beforeMtime:s}),await iu(e,a,UD(o)),await Sx(o,s,n),await ie({flow:"checkpoint",phase:"summarize-done",sessionName:e,file:o,afterMtime:await au(o)});let i=await I0(t,o,{exclude:u=>gx(u.role,u.text)});await ie({flow:"checkpoint",phase:"seed-enriched",sessionName:e,file:o,...i});let c=/workspaces[/\\]([0-9a-f]{8})$/.exec(t||"")?.[1];if(c){await M({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 Nr.readFile(o,"utf8");await M({id:c,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...cx(u),ts:Date.now()}})}catch{}}await ef(t);let l=await QD(r,o);return c&&await ik(c,l||o,{box:e,agent:a?.agent??null}),o}async function tm(e,{timeoutMs:t}={}){let n=await ke(e);if(!n)throw new Error(`session "${e}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${e}"`);return vx(e,n.cwd,t?{timeoutMs:t}:void 0)}async function nm(e,t,{trackName:n="this Track"}={}){let r=await K({id:e,cwd:t}),o=Q0(r,{trackName:n,now:Date.now(),mode:"in-place"});if(!o)return null;let s=Pr.join(t,ox);return await Nr.mkdir(Pr.dirname(s),{recursive:!0}),await Nr.writeFile(s,o,"utf8"),await M({id:e,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...cx(o),reconstructed:!0,ts:Date.now()}}).catch(()=>{}),ox}async function au(e){try{return(await Nr.stat(e)).mtimeMs}catch{return 0}}async function Sx(e,t,n){let r=Date.now()+n;for(;;){if(await au(e)>t)return;if(Date.now()>r)throw new Error(`timed out waiting for the handoff file to be written (${e})`);await rm(2e3)}}async function QD(e,t){try{if(!LD.existsSync(t))return null;let n=new Date().toISOString().replace(/[:.]/g,"-"),r=Pr.join(e,`${n}.md`);return await Nr.copyFile(t,r),r}catch{return null}}function rm(e){return new Promise(t=>setTimeout(t,e))}function sx(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 iu(e,t,n){if(t){let o=sx(t.agent);await Cr({cwd:t.cwd,sessionId:t.sessionId,sessionName:e,agent:t.agent,agentCmd:o})}let r=await ke(e);if(!r)throw new Error(`session "${e}" disappeared before the orchestration prompt could be sent`);await We(e,["Escape"],{kind:"drive-wipe"}),await rm(150),await Es(e,Hl,{kind:"drive-wipe"}),await ot(e,n,{kind:"orchestration-drive",...En(r.agent,n)}),await Ti({sessionName:e,agent:r.agent,agentCmd:sx(r.agent),text:n,flow:"orchestration-drive"})}var ax,ix,tx,lx,ux,dx,FD,UD,HD,px,fx,qD,WD,nx,mx,hx,KD,GD,rx,zD,JD,YD,XD,em,ox,om=G(()=>{ct();bi();Tn();ki();Hf();$0();Xa();de();Cl();ex();ax=".bostrat/handoff",ix="latest.md",tx=32*1024;lx="Checkpoint: write a work-in-progress handoff",ux="HANDOFF WRITTEN",dx="Resume from .bostrat/handoff/latest.md",FD="/clear",UD=e=>`${lx} 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 ${ux} and take no further action.`,HD=`${dx}: read it, restate the Objective and the single next step in one line, then continue the work from 'Next steps'.`,px="Beat: write a",fx="BEAT WRITTEN",qD=".bostrat/arc",WD="beat.txt",nx=200,mx=4,hx=5,KD=36,GD=e=>`${px} 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 ${mx} further lines, each starting with "- " and naming ONE piece in at most ${hx} 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 ${fx} and take no further action.`,rx=/^(?:[-–—*•·]|\d+[.)])\s+/,zD=(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};JD=6e5;YD=3500,XD=3e5,em=new Map;ox=".bostrat/handoff/status-latest.md"});function Br(e,t,n){if(e==null)return t==="from"?-1/0:1/0;if(!lu.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 Ex(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:Br(o.from,"from",n),toMs:Br(o.to,"to",n)}))}return t}function am(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 t1(e){if(!e)return null;let t=String(e).trim();return Dr[t]?t:Tx[t]?Tx[t]:Object.keys(Dr).find(r=>t.startsWith(r))||null}function n1(e){if(!e||e===Dr)return e1;let t=Ax.get(e);return t||(t=Ex(e),Ax.set(e,t)),t}function _x(e,t,n={}){let{table:r,speed:o}=n,s=n1(r),a=r&&r!==Dr?s[e]?e:null:t1(e);if(!a)return null;let i=am(t);if(i===null)return null;let c=s[a].find(l=>i>=l.fromMs&&i<=l.toMs)||null;return c?o==null||o==="standard"?c:o==="fast"&&c.fast?{...c.fast,fromMs:c.fromMs,toMs:c.toMs,verifiedAt:c.verifiedAt,note:c.note,speed:"fast"}:null:null}function In(e,t={},n,r){let o=_x(e,n,r);return o?((t.input||0)*o.input+(t.output||0)*o.output+(t.cacheWrite||0)*o.cacheWrite+(t.cacheRead||0)*o.cacheRead)/1e6:0}function r1(e=Dr){let t=[];for(let[n,r]of Object.entries(e)){if(!Array.isArray(r)||r.length===0){t.push(`${n}: must be a non-empty array of windows`);continue}let o;try{o=r.map(a=>({fromMs:Br(a.from,"from",n),toMs:Br(a.to,"to",n)}))}catch(a){t.push(String(a.message));continue}let s=r.filter(a=>a.to==null);s.length!==1?t.push(`${n}: expected exactly 1 open-ended window (to: null), found ${s.length}`):r[r.length-1].to!=null&&t.push(`${n}: the open-ended window must be last`),r[0].from!=null&&t.push(`${n}: the first window must be open at the start (from: null)`);for(let a=0;a<o.length;a++){if(o[a].fromMs>o[a].toMs&&t.push(`${n}: window ${a} ends before it begins (${r[a].from} \u2192 ${r[a].to})`),a===0)continue;let i=o[a-1],c=o[a];c.fromMs<=i.toMs?t.push(`${n}: windows ${a-1} and ${a} overlap (${r[a-1].to} / ${r[a].from})`):c.fromMs-i.toMs>2&&t.push(`${n}: gap between windows ${a-1} and ${a} (${r[a-1].to} \u2192 ${r[a].from})`),r[a].from||t.push(`${n}: window ${a} must declare a from bound`)}for(let a of r){a.note||t.push(`${n}: every window needs a note recording what was verified and when`),lu.test(String(a.verifiedAt??""))||t.push(`${n}: every window needs a verifiedAt (YYYY-MM-DD) \u2014 the date its rates were checked against the vendor's published page`);for(let i of["input","output","cacheWrite","cacheRead"])(typeof a[i]!="number"||!Number.isFinite(a[i])||a[i]<0)&&t.push(`${n}: window ${i} must be a non-negative number, got ${JSON.stringify(a[i])}`),a.fast&&(typeof a.fast[i]!="number"||!Number.isFinite(a.fast[i])||a.fast[i]<0)&&t.push(`${n}: fast variant ${i} must be a non-negative number, got ${JSON.stringify(a.fast?.[i])}`)}}return t}function s1({now:e=Date.now(),table:t=Dr,...n}={}){let{staleDays:r,leadDays:o,confirmDays:s}={...o1,...n},a=[],i=am(e);if(i===null)return[`pricingFreshness: unparseable now ${JSON.stringify(e)}`];for(let[c,l]of Object.entries(t)){if(!Array.isArray(l))continue;let u;try{u=l.map(d=>({...d,fromMs:Br(d.from,"from",c),toMs:Br(d.to,"to",c),verifiedMs:lu.test(String(d.verifiedAt??""))?Date.parse(`${d.verifiedAt}T00:00:00.000Z`):NaN}))}catch(d){a.push(String(d.message));continue}for(let d of u){if(!Number.isFinite(d.verifiedMs)){a.push(`${c}: window ${d.from??"\u2026"} \u2192 ${d.to??"now"} has no verifiedAt`);continue}let p=i>=d.fromMs&&i<=d.toMs,f=d.fromMs>i&&d.fromMs-i<=o*sm;p&&i-d.verifiedMs>r*sm&&a.push(`${c}: current rate last verified ${d.verifiedAt} (>${r}d) \u2014 re-check the vendor page and bump verifiedAt`),f&&d.fromMs-d.verifiedMs>s*sm&&a.push(`${c}: scheduled rate change on ${d.from} was last verified ${d.verifiedAt} \u2014 confirm it is still happening (vendors cancel; sonnet-5 did) and bump verifiedAt`)}}return a}function Bs({now:e=Date.now(),table:t=Dr,...n}={}){let r=am(e)??Date.now(),o=null,s=[];for(let[i,c]of Object.entries(t))for(let l of c){let u=Br(l.from,"from",i),d=Br(l.to,"to",i);r>=u&&r<=d&&lu.test(String(l.verifiedAt??""))&&(!o||l.verifiedAt<o)&&(o=l.verifiedAt),u>r&&s.push({model:i,from:l.from,verifiedAt:l.verifiedAt??null})}s.sort((i,c)=>i.from<c.from?-1:1);let a=[...r1(t),...s1({now:r,table:t,...n})];return{tableVerifiedAt:o,upcomingChanges:s,problems:a,ok:a.length===0}}var Dr,Tx,lu,e1,Ax,Ix,o1,sm,Qn=G(()=>{Dr={"claude-opus-5":[{from:null,to:null,input:5,output:25,cacheWrite:10,cacheRead:.5,fast:{input:10,output:50,cacheWrite:20,cacheRead:1},verifiedAt:"2026-08-20",note:"GA rates; verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); fast-mode variant added 2026-08-20."}],"claude-opus-4-8":[{from:null,to:null,input:5,output:25,cacheWrite:10,cacheRead:.5,fast:{input:10,output:50,cacheWrite:20,cacheRead:1},verifiedAt:"2026-08-20",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); fast-mode variant added 2026-08-20."}],"claude-sonnet-5":[{from:null,to:null,input:2,output:10,cacheWrite:4,cacheRead:.2,verifiedAt:"2026-08-17",note:"$2/$10 is the standard price (intro pricing made permanent; the 2026-09-01 $3/$15 increase was cancelled) \u2014 verified 2026-08-17 against platform.claude.com/docs/en/about-claude/pricing."}],"claude-sonnet-4-6":[{from:null,to:null,input:3,output:15,cacheWrite:6,cacheRead:.3,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page)."}],"claude-haiku-4-5":[{from:null,to:null,input:1,output:5,cacheWrite:2,cacheRead:.1,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page)."}],"claude-fable-5":[{from:null,to:null,input:10,output:50,cacheWrite:20,cacheRead:1,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); 83% of fleet spend."}],"gpt-5.5":[{from:null,to:null,input:5,output:30,cacheWrite:5,cacheRead:.5,verifiedAt:"2026-08-17",note:"verified 2026-07-03, re-verified 2026-08-17 (developers.openai.com pricing); no cache-write premium on 5.5-and-earlier."}],"gpt-5.6-sol":[{from:null,to:"2026-08-23",input:5,output:30,cacheWrite:6.25,cacheRead:.5,verifiedAt:"2026-08-17",note:"verified 2026-07-18, re-verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL). Superseded 2026-08-24 by the vendor's promotional cut (window below)."},{from:"2026-08-24",to:null,input:4,output:20,cacheWrite:5,cacheRead:.4,verifiedAt:"2026-08-24",note:"promotional pricing verified 2026-08-24 (developers.openai.com pricing), 'at least through November 21, 2026'; cacheWrite = 1.25\xD7 input (30-min TTL)."}],"gpt-5.6-terra":[{from:null,to:"2026-08-16",input:2.5,output:15,cacheWrite:3.125,cacheRead:.25,verifiedAt:"2026-07-18",note:"as verified 2026-07-18; superseded by the 2026-08-17 sweep (0 corpus rows in this window)."},{from:"2026-08-17",to:null,input:2,output:12,cacheWrite:2.5,cacheRead:.2,verifiedAt:"2026-08-17",note:"verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL)."}],"gpt-5.6-luna":[{from:null,to:"2026-08-16",input:1,output:6,cacheWrite:1.25,cacheRead:.1,verifiedAt:"2026-07-18",note:"as verified 2026-07-18; superseded by the 2026-08-17 sweep (0 corpus rows in this window)."},{from:"2026-08-17",to:null,input:.2,output:1.2,cacheWrite:.25,cacheRead:.02,verifiedAt:"2026-08-17",note:"verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL)."}]},Tx={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"},lu=/^\d{4}-\d{2}-\d{2}$/;e1=Ex(Dr);Ax=new WeakMap;Ix=(e,t,n)=>_x(e,t,n)!==null;o1=Object.freeze({staleDays:90,leadDays:14,confirmDays:30}),sm=864e5});function a1(e){return e?{input:e.input||0,output:e.output||0,cacheRead:e.cacheRead||0,cacheWrite:e.cacheWrite??e.cacheCreation??0}:null}function Rx(e,t){t&&(e.input+=t.input,e.output+=t.output,e.cacheRead+=t.cacheRead,e.cacheCreation+=t.cacheWrite)}function Kt(e){let t=e.payload?.model||"unknown",n=a1(e.payload?.tokens),r=Number(e.payload?.usd)||0,o=e.payload?.speed||void 0,s=e.source==="vendor",a=r,i=!1;if(n&&!s){let u=In(t,n,e.ts,o?{speed:o}:void 0);u>0&&(a=u,i=Math.abs(u-r)>1e-9)}let c=n?n.input+n.output+n.cacheRead+n.cacheWrite:0,l=!a&&c>0&&!Ix(t,e.ts,o?{speed:o}:void 0);return{usd:a,model:t,tokens:n,repriced:i,unpriced:l,asRecorded:r}}function jr(e,{boxLabels:t={}}={}){let n=(e||[]).filter(p=>p.type==="cost.recorded"),r={},o={},s={},a=0,i=0,c=0,l=0,u=new Set,d=$x();for(let p of n){let{usd:f,model:w,tokens:m,repriced:g,unpriced:y,asRecorded:x}=Kt(p);i+=x;let b=p.provider||"unknown",O=p.boxId||"unattributed";if(g&&c++,y&&(l++,u.add(w)),a+=f,Rx(d,m),r[w]||={usd:0,tokens:$x(),events:0},r[w].usd+=f,r[w].events+=1,Rx(r[w].tokens,m),o[b]||={usd:0,events:0},o[b].usd+=f,o[b].events+=1,s[O]||={usd:0,events:0,provider:b,models:new Set,label:t[O]||O},s[O].usd+=f,s[O].events+=1,w!=="unknown"&&s[O].models.add(w),p.epoch!=null){let $=(s[O].epochs||={})[p.epoch]||={usd:0,events:0,provider:b,models:new Set};$.usd+=f,$.events+=1,$.provider=b,w!=="unknown"&&$.models.add(w)}}return{totalUsd:js(a),asRecordedUsd:js(i),totalTokens:d,turns:n.length,repricedTurns:c,unpricedTurns:l,unpricedModels:[...u],byModel:uu(r,p=>({...p,usd:js(p.usd)})),byProvider:uu(o,p=>({...p,usd:js(p.usd)})),byBox:uu(s,p=>({usd:js(p.usd),events:p.events,provider:p.provider,label:p.label,models:[...p.models],...p.epochs?{epochs:uu(p.epochs,f=>({usd:js(f.usd),events:f.events,provider:f.provider,models:[...f.models]}))}:{}}))}}var $x,js,uu,Lr=G(()=>{Qn();$x=()=>({input:0,output:0,cacheRead:0,cacheCreation:0});js=e=>Math.round(e*1e4)/1e4,uu=(e,t)=>Object.fromEntries(Object.entries(e).map(([n,r])=>[n,t(r)]))});function i1(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 Ox(e,t=[]){let n=[],r=e?.events||[],o=new Map,s=0;for(let u of t){if(u.type!=="pr.state.changed")continue;let d=u.payload||{};!d.repo||d.number==null||(d.change==="merged"?o.set(`${d.repo}#${d.number}`,d):d.change==="opened"&&s++)}if(o.size){let u=[...o.keys()].map(d=>{let[p,f]=d.split("#");return`${p.split("/").pop()}#${f}`});n.push(`Merged ${u.slice(0,4).join(", ")}${u.length>4?` +${u.length-4}`:""}`)}else s&&n.push(im(s,"PR")+" opened");let a=Object.keys(e?.subtasks||{}).length||r.filter(u=>u.type==="subtask-delegated").length;a&&n.push(im(a,"subtask"));let i=r.filter(u=>u.type==="lead-handoff"&&u.fromAgent&&u.toAgent);if(i.length){let u=i.slice(0,3).map(d=>`${d.fromAgent}\u2192${d.toAgent}`).join(", ");n.push(`${im(i.length,"handoff")} ${u}${i.length>3?"\u2026":""}`)}let c=jr(t);c.totalUsd>=.01&&n.push(`$${c.totalUsd.toFixed(2)}`);let l=Number.isFinite(e?.archivedAt)&&Number.isFinite(e?.createdAt)?i1(e.archivedAt-e.createdAt):null;return n.length&&l&&n.push(l),n.length?n.join(" \xB7 "):null}var im,Mx=G(()=>{Lr();im=(e,t)=>`${e} ${t}${e===1?"":"s"}`});import{execFile as c1}from"node:child_process";import{promisify as l1}from"node:util";import{randomUUID as u1}from"node:crypto";async function cm(e,t){let n=Date.now()+t;for(;;){if(await Xn(e))return!0;if(Date.now()>n)return!1;await $i(p1)}}async function m1(e,t){let n=Nx[t]||Nx.default;n.escape&&(await We(e,["Escape"],{kind:"swap-exit"}),await $i(150)),n.wipe&&await Es(e,Hl,{kind:"swap-exit"}),await ql(e,n.text,{perCharDelayMs:90,kind:"swap-exit"});let r=En(t).submitDelayMs||0;await $i(Math.max(r,250)),await We(e,["Enter"],{kind:"swap-exit"})}async function Px(e,t){try{let{stdout:n}=await Ro(Y,Z("show-environment","-t",e,t));return!String(n||"").trimStart().startsWith("-")}catch{return!1}}async function Dx(e){await Ro(Y,Z("respawn-pane","-k","-t",e))}async function lm(e,t={}){if(!je(e))throw new Error("invalid session name");let n=String(t.agentCmd||"").trim();if(!n)throw new Error("agentCmd is required");let r=await ke(e);if(!r)throw new Error(`session "${e}" not found`);if(!r.cwd)throw new Error(`can't resolve cwd for "${e}"`);let o=r.agent||"agent",s=t.agent||$r(n),a=Number(t.exitTimeoutMs)||d1;await ie({flow:"swap",phase:"start",sessionName:e,from:o,to:s,cwd:r.cwd});let i=!1;if(!await Xn(e)&&(await m1(e,o),!await cm(e,a)&&(i=!0,await ie({flow:"swap",phase:"respawn-forced",sessionName:e,from:o}),await Dx(e),!await cm(e,Cx))))throw new Error(`pane shell did not come back after respawn-pane in "${e}"`);let c=s==="claude"&&To(n),l=c?fl():null,u=await Px(e,"ANTHROPIC_API_KEY"),d=!1;try{l?(await Ro(Y,Z("set-environment","-t",e,"ANTHROPIC_API_KEY",l)),d=!0):u&&(await Ro(Y,Z("set-environment","-u","-t",e,"ANTHROPIC_API_KEY")),d=!0)}catch(g){throw l?Dl(g,l):g}if(d&&!i&&(await Dx(e),!await cm(e,Cx)))throw new Error(`pane shell did not come back after env respawn in "${e}"`);let p=!!t.resumeSessionId,f=t.resumeSessionId||u1(),w=p?n:ii(n,f,e),m=p?t.pinned===!0:/(^|\s)--session-id(\s|=)/.test(w);return c&&await vr(r.cwd),s==="codex"&&await ms(r.cwd),s==="cursor"&&await hs(r.cwd),await Ao(e),await Ro(Y,Z("set-option","-t",e,"@bostrat-sid",f)),await Ro(Y,Z("set-option","-t",e,"@bostrat-agent",s)),await $i(f1),c&&ai().length&&(await Px(e,si)||await Ro(Y,Z("set-environment","-t",e,si,"1")).catch(()=>{}),await ot(e,`export ${si}=1`,{kind:"swap-env"}),await $i(150)),await ot(e,w,{kind:"swap-launch"}),await ie({flow:"swap",phase:"done",sessionName:e,from:o,to:s,sid:f,forced:i,envRespawned:d}),{name:e,cwd:r.cwd,sessionId:f,agent:s,pinned:m,forced:i,envRespawned:d,launchCmd:w}}var Ro,$i,d1,Cx,p1,f1,Nx,Bx=G(()=>{ct();Wa();hl();wl();ki();Tn();Ro=l1(c1),$i=e=>new Promise(t=>setTimeout(t,e)),d1=Number(process.env.BOSTRAT_SWAP_EXIT_TIMEOUT_MS)||15e3,Cx=Number(process.env.BOSTRAT_SWAP_SHELL_TIMEOUT_MS)||8e3,p1=250,f1=400,Nx={claude:{escape:!0,wipe:!0,text:"/exit"},codex:{escape:!0,wipe:!0,text:"/quit"},cursor:{escape:!0,wipe:!0,text:"/quit"},default:{escape:!1,wipe:!1,text:"exit"}}});function b1(e){if(e.type==="queue-operation"&&e.operation==="enqueue")return jx.test(String(e.content||""))?String(e.content):null;if(e.type==="attachment"){let n=e.attachment;return n?.type==="queued_command"&&n.commandMode==="task-notification"&&typeof n.prompt=="string"?n.prompt:null}let t=e.message?.content;return typeof t=="string"&&jx.test(t)?t:null}async function Lx(e,t={}){return(await Ux(e,t)).launches}async function Fx(e,t={}){let{launches:n,done:r}=await Ux(e,t);return n.filter(o=>!r.has(o.id))}async function Ux(e,{maxBytes:t=2097152,limit:n=100}={}){let r;try{r=await _t(e,t)}catch{return{launches:[],done:new Set}}let o=new Map,s=new Set,a=new Set,i=new Map;for(let l of r.split(`
159
- `)){let u=l.trim();if(!u||u[0]!=="{")continue;let d;try{d=JSON.parse(u)}catch{continue}if(d.isSidechain)continue;let p=b1(d);if(p){let m=p.match(y1)?.[1]?.trim();m&&a.add(m);continue}let f=d.message?.content;if(!Array.isArray(f))continue;let w=d.timestamp?Date.parse(d.timestamp):null;for(let m of f)if(!(!m||typeof m!="object")){if(m.type==="tool_use"&&m.id){if(m.name==="Agent"){let g=m.input||{};o.set(m.id,{id:m.id,kind:"agent",name:String(g.description||"").trim()||null,detail:String(g.subagent_type||"").trim()||null,ts:w,proven:!1})}else if(m.name==="Bash"){let g=String(m.input?.command||"").trim(),y={id:m.id,kind:"command",name:String(m.input?.description||"").trim()||(g?Rs(g):null),detail:g?Rs(g):null,ts:w,proven:m.input?.run_in_background===!0};y.proven?o.set(m.id,y):i.set(m.id,y)}}else if(m.type==="tool_result"&&m.tool_use_id){let g=k1(m.content);if(h1.test(g)&&s.add(m.tool_use_id),g.match(w1)){let x=i.get(m.tool_use_id);x&&(i.delete(m.tool_use_id),x.proven=!0,x.outputFile=g.match(g1)?.[1]?.replace(/\.$/,"")||null,o.set(x.id,x))}}}}let c=[];for(let l of o.values()){if(!l.proven&&!s.has(l.id))continue;let{proven:u,...d}=l;c.push(d)}return{launches:c.slice(-n),done:a}}var h1,w1,g1,jx,y1,k1,Hx=G(()=>{an();Os();h1=/^Async (?:agent|task) launched/i,w1=/^Command did not complete within its [^\n]*?moved to the background \(ID: ([^)]+)\)/i,g1=/Output is being written to:\s*(\S+)/i,jx=/^\s*<task-notification>/i,y1=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i;k1=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 Fr(e,t){if(!e)return null;let n=String(e);if(t){let o=t.endsWith("/")?t:`${t}/`;if(n===t)return".";if(n.startsWith(o))return n.slice(o.length)||"."}let r=n.split("/").filter(Boolean);return n.startsWith("/")&&r.length>2?r.slice(-2).join("/"):n}function x1(e){let t=typeof e=="string"?e:String(e?.patch??e?.input??""),n=[];for(let r of t.matchAll(/^\*{3} (?:Update|Add|Delete) File: (.+)$/gm))n.push(r[1].trim());return n}function qx(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:cn(`read ${Fr(r,n)}${o?` (lines ${o}\u2013${s??"end"})`:""}`,140),description:o?`Read lines ${o}\u2013${s??"end"} of ${Ls(r)}`:`Read ${Ls(r)}`}}case"Grep":{let r=t?.pattern;if(!r)return null;let o=t?.path?Fr(t.path,n):null,s=t?.glob?` --glob ${um(t.glob)}`:"",a=cn(String(r),40);return{command:cn(`grep ${um(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?Fr(t.target_directory,n):null;return{command:cn(`glob ${um(r)}${o&&o!=="."?` ${o}`:""}`,140),description:`Find files matching \u201C${cn(String(r),40)}\u201D`}}case"StrReplace":return t?.path?{command:cn(`edit ${Fr(t.path,n)}`,140),description:`Edit ${Ls(t.path)}`}:null;case"Write":return t?.path?{command:cn(`write ${Fr(t.path,n)}`,140),description:`Write ${Ls(t.path)}`}:null;case"Delete":return t?.path?{command:cn(`delete ${Fr(t.path,n)}`,140),description:`Delete ${Ls(t.path)}`}:null;case"ReadLints":{let o=(Array.isArray(t?.paths)?t.paths:[]).map(s=>Fr(s,n)).filter(Boolean);return{command:cn(o.length?`lints ${o.join(" ")}`:"lints",140),description:"Check lints"}}case"ApplyPatch":{let r=x1(t);if(!r.length)return null;let o=r.length>1?` (+${r.length-1} more)`:"";return{command:cn(`apply_patch ${Fr(r[0],n)}${o}`,140),description:r.length>1?`Patch ${r.length} files`:`Patch ${Ls(r[0])}`}}case"Await":{let r=t?.shell_id??t?.task_id;return{command:cn(`await ${r??"background output"}`,140),description:"Wait for a background command"}}default:return null}}var du,cn,Ls,um,Wx=G(()=>{du=new Set(["Shell","Read","Grep","Glob","StrReplace","Write","ReadLints","Delete","ApplyPatch","Await"]),cn=(e,t=88)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,Ls=e=>String(e).replace(/\/+$/,"").split("/").pop()||String(e);um=e=>`"${String(e).replace(/"/g,'\\"')}"`});import Ri from"node:fs";import v1 from"node:fs/promises";import Oo from"node:path";import S1 from"node:os";import T1 from"node:crypto";import A1 from"node:zlib";function zx(e){let t=T1.createHash("md5").update(String(e)).digest("hex");return Oo.join(E1,t)}function Vx(e){try{let t=JSON.parse(Ri.readFileSync(Oo.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 _1(e){let t=zx(e),n;try{n=Ri.readdirSync(t,{withFileTypes:!0}).filter(o=>o.isDirectory())}catch{return null}let r=null;for(let o of n){let s=Oo.join(t,o.name),a=Oo.join(s,"store.db");if(!Ri.existsSync(a))continue;let i=Vx(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 pu(e,t){if(!e)return null;if(t){let n=Oo.join(zx(e),t),r=Oo.join(n,"store.db");if(Ri.existsSync(r))return{id:t,dir:n,store:r,...Vx(n)||{createdAtMs:null,updatedAtMs:null}}}return _1(e)}function Kx(e,t){let n=e.prepare("SELECT data FROM blobs WHERE id = ?").get(t);return n?Buffer.from(n.data):null}function I1(e){if(!e)return null;let t=e;if(t.length>1&&t[0]===31&&t[1]===139)try{t=A1.gunzipSync(t)}catch{}try{return JSON.parse(t.toString("utf8"))}catch{return null}}function $1(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 R1(e,t){if(!Array.isArray(e))return[];let n=[];for(let r of e){if(!r||r.type!=="tool-call"||!du.has(r.toolName))continue;let o=qx(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 dm(e,t){if(!Gx)return Fs;let{DatabaseSync:n}=Gx,r;try{r=new n(e,{readOnly:!0})}catch{return Fs}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 Fs;let s;try{s=JSON.parse(Buffer.from(String(o.value),"hex").toString("utf8"))}catch{return Fs}let a=s.lastUsedModel||null,i=s.latestRootBlobId?Kx(r,s.latestRootBlobId):null;if(!i)return{...Fs,model:a};let c=[],l=[],u=[],d=null,p=[];for(let f of $1(i)){let w=I1(Kx(r,f));if(!w)continue;let m=w.providerOptions?.cursor;if(m?.requestId&&p.push(m.requestId),m?.modelProviderMessageId&&p.push(m.modelProviderMessageId),w.role!=="assistant")continue;if(Array.isArray(w.content))for(let x of w.content){let b=x?.providerOptions?.cursor?.modelName;b&&(d=b)}l.push(...R1(w.content,t).map((x,b)=>({...x,id:x.id||`${f}:${b}`}))),u.push(...M1(w.content));let g=O1(w.content);if(!g)continue;let y=[...new Set(u)];u=[],c.push({id:f,text:g,tools:y.length?y:void 0,commands:l,model:d}),l=[]}return{turns:c,trailingCommands:l,model:a,requestIds:p}}catch{return Fs}finally{try{r.close()}catch{}}}function Jx(e,t){let n=e.updatedAtMs;if(!n)try{n=Math.round(Ri.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 Yx(e,t,{limit:n=80}={}){let r=pu(e,t);if(!r)return[];let{turns:o,model:s}=await dm(r.store,e);if(!o.length)return[];let a=o.slice(-n),{tsAt:i}=Jx(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 Xx(e,t){let n=pu(e,t);if(!n)return null;let{turns:r,requestIds:o,model:s}=await dm(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 Zx(e,t,{limit:n=80}={}){let r=pu(e,t);if(!r)return[];let{turns:o,trailingCommands:s}=await dm(r.store,e);if(!o.length&&!s.length)return[];let a=o.slice(-n),{end:i,tsAt:c}=Jx(r,a.length||1),l=[];a.forEach((u,d)=>{for(let p of u.commands)l.push({...p,summary:Mr(p.command,p.description),ts:c(d)})});for(let u of s)l.push({...u,summary:Mr(u.command,u.description),ts:i+1});return l}async function Qx(e,t){let n=pu(e,t);if(!n)return null;if(n.updatedAtMs)return n.updatedAtMs;try{return Math.round((await v1.stat(n.store)).mtimeMs)}catch{return null}}var E1,O1,M1,Gx,Fs,pm=G(()=>{Os();Wx();E1=process.env.BOSTRAT_CURSOR_CHATS||Oo.join(S1.homedir(),".cursor","chats");O1=e=>typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&t.type==="text"&&typeof t.text=="string").map(t=>t.text).join(`
160
- `).trim():"",M1=e=>Array.isArray(e)?e.filter(t=>t&&t.type==="tool-call"&&t.toolName).map(t=>t.toolName):[],Gx=process.getBuiltinModule?.("node:sqlite"),Fs={turns:[],trailingCommands:[],model:null,requestIds:[]}});import C1 from"node:fs/promises";function wm(e){return ev.set(e.agent,e),e}function Ur(e){return ev.get(e)||N1}async function gm(e,t={}){return(await Ur(e.agent).readMessages(e,t)).map(fu(e))}async function tv(e,t={}){return(await Ur(e.agent).readCommands(e,t)).map(fu(e))}async function nv(e,t={}){return(await Ur(e.agent).readJobs(e,t)).map(fu(e))}async function rv(e,t={}){return(await Ur(e.agent).readOpenJobs(e,t)).map(fu(e))}var Us,fm,mm,hm,N1,ev,fu,ym=G(()=>{an();Gl();Os();Hx();pm();Io();Us=class{constructor(t,n=new Set){this.agent=t,this.cliTools=n}async readMessages(){return[]}async readCommands(){return[]}async readJobs(){return[]}async readOpenJobs(){return[]}async updatedAt(){return null}},fm=class extends Us{transcript(t){return!t?.cwd||!t?.sessionId?null:sn(t.cwd,t.sessionId)}async readMessages(t,n){let r=this.transcript(t);return r?$f(r,n):[]}async readCommands(t,n){let r=this.transcript(t);return r?Fk(r,n):[]}async readJobs(t,n){let r=this.transcript(t);return r?Lx(r,n):[]}async readOpenJobs(t,n){let r=this.transcript(t);return r?Fx(r,n):[]}async updatedAt(t){let n=this.transcript(t);if(!n)return null;try{return Math.round((await C1.stat(n)).mtimeMs)}catch{return null}}},mm=class extends Us{async readMessages(t,n){return Yx(t.cwd,t.sessionId,n)}async readCommands(t,n){return Zx(t.cwd,t.sessionId,n)}async updatedAt(t){return Qx(t.cwd,t.sessionId)}},hm=class extends Us{sessionId(t){return t?.pinned?t.sessionId:null}async readMessages(t,n){return Wk(t.cwd,this.sessionId(t),n)}async readCommands(t,n){return Kk(t.cwd,this.sessionId(t),n)}async updatedAt(t){return Gk(t.cwd,this.sessionId(t))}},N1=new Us("unknown"),ev=new Map;wm(new fm("claude",Tf));wm(new mm("cursor",du));wm(new hm("codex",mi));fu=e=>t=>({...t,box:e.name,agent:e.agent,boxRole:e.role})});function qr(e){let t=e.search(vm);return(t>=0?e.slice(0,t):e).trim()}function P1(e){if(!e)return"";let t=e.replace(/[│┌└├─┘┤┬┴┼─✂].*$/,"").trim();return!t||/hidden|\d+\s+lines?/i.test(t)?"":t}function D1(e){let t=String(e).trim();return!!(!t||Hr.test(e)||vm.test(t)||/hidden|\d+\s+lines?/i.test(t)||/notespress|press n to add/i.test(t)||/^\s*notes?\s*$/i.test(t))}function B1(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=j1(n,t);return n.forEach((a,i)=>{a.current=i===s}),{tabs:n,questionIndex:s,questionTotal:n.length,currentTabLabel:n[s].label}}function j1(e,t){let n=String(t).toLowerCase(),r=e.findIndex(c=>!c.answered),o=r>=0?r:e.length-1;if(!n)return o;let s=e.map(c=>{let l=c.label.toLowerCase(),u=l.split(/\s+/).filter(p=>p.length>3&&n.includes(p)).length;if(u)return u;let d=l.slice(0,8).trim();return d.length>=4&&n.includes(d)?1:0}),a=Math.max(...s);if(a===0||s[o]===a)return o;let i=s.flatMap((c,l)=>c===a?[l]:[]);return i.length===1?i[0]:o}function ov(e){return e.replace(/[←→✔☐☒●▶]/g," ").replace(/\bSubmit\b/g," ").replace(/\s+/g," ").trim()}function L1(e,t=""){let n=String(e);if(!av.test(n))return null;let r=n.replace(/\r/g,"").split(`
161
- `),o=-1;for(let u=r.length-1;u>=0;u--)if(/^\s*Switch model\?\s*$/.test(r[u])){o=u;break}if(o<0)return null;let s=[],a=[];for(let u=o+1;u<r.length;u++){let d=r[u].match(Mo);if(d)s.push({cursor:!!d[1],label:d[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let p=r[u].trim();p&&!Hr.test(r[u])&&a.push(p)}}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 U1(e,t=""){let n=String(e).replace(/\r/g,"").split(`
162
- `),r=n.length-1;for(;r>=0&&n[r].trim()==="";)r--;if(r<0||!iv.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(Mo);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&&!(F1.test(n[c])||Hr.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 H1(e,t=""){let n=String(e);if(!/ready to submit your answers/i.test(n))return null;let r=n.replace(/\r/g,"").split(`
163
- `),o=[];for(let c=0;c<r.length;c++){let l=r[c].match(Mo);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 W1(e,t=""){let n=String(e);if(!bm.test(n))return null;let r=n.replace(/\r/g,"").split(`
164
- `),o=-1;for(let u=r.length-1;u>=0;u--)if(q1.test(r[u])){o=u;break}if(o<0)return null;let s=[],a=[r[o].trim()];for(let u=o+1;u<r.length;u++){let d=r[u].match(Mo);if(d)s.push({cursor:!!d[1],label:d[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let p=r[u].trim();p&&!Hr.test(r[u])&&a.push(p)}}if(s.length<2||!s.some(u=>bm.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 Sm(e){let t=[];for(let r=0;r<e.length;r++){let o=e[r].match(Mo);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 K1(e,t=""){let n=String(e);if(!cv.test(n)||!lv.test(n)||Co.test(n))return null;let r=n.replace(/\r/g,"").split(`
165
- `),o=Sm(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 G1(e,t=""){let n=String(e);if(!uv.test(n)||Co.test(n))return null;let r=n.replace(/\r/g,"").split(`
166
- `),o=Sm(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 V1(e,t){let n=e[t].trim();for(let r=t+1;r<e.length;r++){let o=e[r].trim();if(!o||!z1.test(o)||Tm.test(e[r]))break;n+=o}return n}function J1(e,t=""){let n=String(e);if(!Tm.test(n)||Co.test(n))return null;let r=n.replace(/\r/g,"").split(`
167
- `),o="";for(let s=0;s<r.length;s++)if(/^\s*https:\/\//.test(r[s])){o=V1(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 X1(e,t=""){let n=String(e);if(!km.test(n)||!Y1.test(n)||Co.test(n))return null;let s=([...n.replace(/\r/g,"").split(`
168
- `)].reverse().find(a=>km.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 Z1(e,t=""){let n=String(e);if(!dv.test(n)||Co.test(n))return null;let r=n.replace(/\r/g,"").split(`
169
- `),o=Sm(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 Q1(e,t=""){let n=String(e);if(Co.test(n))return null;let r=n.replace(/\r/g,"").split(`
170
- `),o=-1;for(let l=r.length-1;l>=0;l--)if(r[l].trim()!==""){o=l;break}if(o<0)return null;let s=r[o].match(pv);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(Hr.test(r[l])||vm.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 eB(e){let t=-1;for(let r=e.length-1;r>=0;r--)if(xm.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 tB(e,t){let n=e.find(s=>/^type something\b/i.test(s.label));if(n)return n;if(e.length<2)return null;let r=e[e.length-1];if(mu.test(r.label))return null;let o=null;for(let s=r.line+1;s<Math.min(t.length,r.line+3);s++){let a=t[s].replace(/^\s*❯/,"").trim();if(a){o=a;break}}return o&&(Hr.test(o)||/^submit\b/i.test(o))?r:null}function nB(e,t=""){let n=String(e);if(!sv.test(n)||!xm.test(n))return null;let r=n.replace(/\r/g,"").split(`
171
- `),o=eB(r);if(!o)return null;let{headerLine:s,chatLine:a,optStart:i,optEnd:c}=o,l=[],u=-1;for(let _=i;_<c;_++){let F=r[_].match(Mo);F&&(u<0&&(u=_),l.push({line:_,cursor:!!F[1],checked:F[3]!=null&&F[3]!==" ",hasCheckbox:F[3]!=null,label:F[4].trim(),desc:""}))}if(!l.length)return null;for(let _ of l)for(let F=_.line+1;F<Math.min(r.length,_.line+4)&&!(Mo.test(r[F])||Hr.test(r[F]));F++){let V=r[F].trim();if(!(!V||D1(r[F])||mu.test(V))){_.desc=P1(V);break}}let d=tB(l,r),p=l.filter(_=>_!==d&&!mu.test(_.label));if(!p.length)return null;let f=p.some(_=>_.hasCheckbox),w=d?.cursor?p.length:Math.max(0,p.findIndex(_=>_.cursor)),m=d&&!mu.test(d.label)?qr(d.label):"",g=s>=0?s+1:0,y=[];for(let _=g;_<u;_++){let F=r[_].trim();F&&!Hr.test(r[_])&&!/[☐☒]/.test(r[_])&&y.push(F)}let x=y.join(" ")||(s>=0?ov(r[s]):"")||"The agent is asking a question",b=s>=0?B1(r[s],x):null,O=b?.currentTabLabel||(s>=0?ov(r[s]):""),$=p.map(_=>({label:qr(_.label),description:_.desc})),C=$.map(_=>_.label).join("|"),q=`claude:${b?`q${b.questionIndex+1}/${b.questionTotal}`:"q1/1"}:${O}:${x}:${C}`.slice(0,240),I=b?`claude:ask:${b.tabs.map(_=>_.label).join("|")}`.slice(0,240):q;return{provider:"claude",box:t,multiSelect:f,cursorIndex:w,promptId:q,groupId:I,...d?{custom:!0,customIndex:p.length,customText:m}:{},dismissable:!0,...b?{questionIndex:b.questionIndex,questionTotal:b.questionTotal,currentTabLabel:b.currentTabLabel,tabs:b.tabs}:{},questions:[{question:x,header:O,multiSelect:f,options:$}]}}function Wr(e,t){let n=String(t||"");return n?e==="claude"?sv.test(n)&&xm.test(n)||av.test(n)||bm.test(n)||iv.test(n.trimEnd().split(`
172
- `).pop()||"")?!0:Co.test(n)?!1:cv.test(n)&&lv.test(n)||uv.test(n)||Tm.test(n)||km.test(n)||dv.test(n)||pv.test(n.trimEnd().split(`
173
- `).pop()||""):e==="codex"&&/Sign in with ChatGPT|one-time code|Paste or type your API key|link to authenticate|Successfully logged in\.[\s\S]*Press Enter to continue\./i.test(n)?!0:e==="cursor"||e==="codex"?/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i.test(n):!1:!1}function $n(e,t){return!e||!t?null:e.agent==="claude"?H1(t,e.name)||nB(t,e.name)||L1(t,e.name)||W1(t,e.name)||X1(t,e.name)||J1(t,e.name)||G1(t,e.name)||K1(t,e.name)||Z1(t,e.name)||Q1(t,e.name)||U1(t,e.name):e.agent==="cursor"||e.agent==="codex"?i0(e.agent,t,e.name):null}async function Am(e){if(!e)return null;let t=await on(e.name).catch(()=>"");return $n(e,t)}function Em(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 fv(e,t,n=""){let r=typeof n=="string"?n.trim():"";if(!r||!e?.custom)return{pre:Em(e,t).map(d=>({key:d})),text:"",post:[]};let o=Array.isArray(t?.[0])?t[0].filter(d=>Number.isInteger(d)&&d>=0):[],s=Number.isInteger(e.customIndex)?e.customIndex:e.questions?.[0]?.options?.length??0,a=Number.isInteger(e.cursorIndex)?e.cursorIndex:0,i=(d,p)=>{let f=p-d;return Array.from({length:Math.abs(f)},()=>({key:f>0?"Down":"Up"}))},c=[],l=a,u=typeof e.customText=="string"?e.customText.length:0;if(u>0&&a===s&&c.push(...Array.from({length:u+2},()=>({key:"BSpace"}))),e.multiSelect){for(let d of[...o].sort((p,f)=>p-f))c.push(...i(l,d),{key:"Enter"}),l=d;return c.push(...i(l,s)),{pre:c,text:r,post:[{key:"Down"},{key:"Enter"}]}}return c.push(...i(l,s)),{pre:c,text:r,post:[{key:"Enter"}]}}function mv(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 sv,xm,Mo,mu,Hr,vm,av,iv,F1,bm,q1,Co,cv,lv,uv,Tm,z1,km,Y1,dv,pv,_m=G(()=>{ct();Vl();sv=/to navigate\b.*\bEsc to cancel|Enter to select\b/,xm=/Chat about this/i,Mo=/^\s*(❯)?\s*(\d+)\.\s+(?:\[([ xX✔])\]\s+)?(.+?)\s*$/,mu=/^(type something|chat about this|submit)\b/i,Hr=/^[─—-]{6,}\s*$/,vm=/[\u2500-\u257F\u2550-\u256F┌┐└┘├┤│┬┴┼─✂]/;av=/^\s*Switch model\?\s*$/m;iv=/^\s*Enter to confirm\s*·\s*Esc to cancel\s*$/,F1=/^\s*[─—▔-]{6,}\s*$/;bm=/Resume from summary/i,q1=/^\s*This session is\b/;Co=/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/;cv=/Choose the text style that looks best with your terminal/,lv=/Let's get started\./;uv=/Select login method:/;Tm=/Paste code here if prompted/,z1=/^[A-Za-z0-9%&=+._~#?/:\-]+$/;km=/OAuth error:/,Y1=/Press Enter to retry\./;dv=/Quick safety check: Is this a project you created or one you trust/;pv=/^(.{0,60}?)Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/});function hu(e,t,n){if(!e||!t)return null;for(let r of rB)if(r.provider===e.agent)try{if(r.match(t,n))return r}catch{}return null}function sB(e){let t=Im.get(e);return t||(t={sentAt:[],last:0,emitted:new Set},Im.set(e,t)),t}function gv(e,t,n=Date.now()){let r=sB(e);if(r.sentAt=r.sentAt.filter(s=>n-s<wv),r.sentAt.length>=hv)return{action:"give-up"};if(n-r.last<oB)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 yv(e,t=Date.now()){let n=Im.get(e);return n?n.sentAt.filter(r=>t-r<wv).length>=hv:!1}var rB,oB,hv,wv,Im,$m=G(()=>{rB=[{provider:"claude",id:"fullscreen-upsell",match(e,t){let n=e?.questions?.[0],r=(n?.options||[]).map(s=>String(s.label||"").trim());if(r.length!==2||!/^Yes, try it$/.test(r[0])||!/^Not now$/.test(r[1]))return!1;let o=`${n?.question||""}
174
- ${String(t||"")}`;return/Try the new fullscreen renderer|Flicker-free output/i.test(o)},keys:["Escape"]}];oB=5e3,hv=5,wv=3600*1e3,Im=new Map});function Hs(e){return typeof e=="string"?e.trim():""}var bv=G(()=>{});import{execFile as aB}from"node:child_process";import{promisify as iB}from"node:util";async function Ve(e,t,{input:n}={}){let r=Om("git",["-C",e,...t],{maxBuffer:kv});return n!==void 0&&r.child.stdin&&(r.child.stdin.on("error",()=>{}),r.child.stdin.end(n)),r}async function qs(e){if(!e)return!1;try{let{stdout:t}=await Ve(e,["rev-parse","--is-inside-work-tree"]);return t.trim()==="true"}catch{return!1}}async function xv(e){let{stdout:t}=await Ve(e,["rev-parse","--show-toplevel"]);return t.trim()}async function cB(e){try{return await Ve(e,["rev-parse","--verify","HEAD"]),!0}catch{return!1}}async function Ws(e,t="bostrat: subtask snapshot"){let{stdout:n}=await Ve(e,["rev-parse","--absolute-git-dir"]),r=`${n.trim()}/bostrat-snapshot-index`,o={...process.env,GIT_INDEX_FILE:r},s=(a,i)=>Om("git",["-C",e,...a],{maxBuffer:kv,env:o,...i});try{let a=await cB(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 Om("rm",["-f",r])}catch{}}}async function Mm(e,t,{trailers:n=[]}={}){let{stdout:r}=await Ve(e,["status","--porcelain"]);return r.trim()?(await Ve(e,["add","-A"]),await Ve(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","-m",t,...n.flatMap(o=>["--trailer",o])]),!0):!1}async function Oi(e,{ignorePlumbing:t=!1}={}){let{stdout:n}=await Ve(e,["status","--porcelain"]),r=n.split(`
175
- `).filter(Boolean);return t&&(r=r.filter(o=>{let s=o.slice(3);return!(s===".bostrat"||s===".bostrat/"||s.startsWith(".bostrat/")||o.startsWith("??")&&(s==="AGENTS.md"||s==="CLAUDE.md"))})),r.length>0}async function Mi(e,t){if(!t)return 0;try{let{stdout:n}=await Ve(e,["rev-list","--count",`${t}..HEAD`]);return Number(n.trim())||0}catch{return 0}}async function Ks(e,t,n,r){return await Ve(e,["worktree","add","--no-track","-b",n,t,r]),t}async function vv(e,t){try{return await Ve(e,["rev-parse","--verify","--quiet",`refs/heads/${t}`]),!0}catch{return!1}}async function wu(e,t,n){return await Ve(e,["worktree","add","--end-of-options",t,n]),t}async function Gs(e){if(process.env.BOSTRAT_TRACK_BASE_REF)return process.env.BOSTRAT_TRACK_BASE_REF;try{let{stdout:t}=await Ve(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 Ve(e,["rev-parse","--verify","--quiet",t]),n}catch{}return"HEAD"}async function Cm(e){await Ve(e,["init","-q"]),await Ve(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","--allow-empty","-qm","bostrat: track workspace"])}async function Ot(e,t){try{await Ve(e,["worktree","remove","--force",t])}catch{try{await Ve(e,["worktree","prune"])}catch{}}}function lB(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 Nm(e,t){return!t||!t.length?e:[...e,"--",".",...t.map(n=>`:(exclude)${n}`)]}async function Pm(e,t,n,r){let{stdout:o}=await Ve(e,Nm(["diff","--shortstat",t,n],r));return lB(o)}async function Dm(e,t,n,r){let{stdout:o}=await Ve(e,Nm(["diff","--name-only",t,n],r));return o.split(`
176
- `).map(s=>s.trim()).filter(Boolean)}async function Bm(e,t,n,r){let{stdout:o}=await Ve(e,Nm(["diff","--binary",t,n],r));if(!o.trim())return{applied:!0,empty:!0,conflicts:[]};if((await Rm(e,o,["--whitespace=nowarn"])).ok)return{applied:!0,empty:!1,conflicts:[]};let s=await Rm(e,o,["--3way","--whitespace=nowarn"]),a=await uB(e);return a.length>0?{applied:!1,empty:!1,conflicts:a}:s.ok?{applied:!0,empty:!1,conflicts:[]}:(await Rm(e,o,["--reject","--whitespace=nowarn"]),{applied:!1,empty:!1,conflicts:[`patch did not apply cleanly: ${s.err}`]})}async function Rm(e,t,n){try{return await Ve(e,["apply",...n,"-"],{input:t}),{ok:!0}}catch(r){return{ok:!1,err:r?.stderr?.trim()||r?.message||String(r)}}}async function uB(e){try{let{stdout:t}=await Ve(e,["diff","--name-only","--diff-filter=U"]);return t.split(`
177
- `).map(n=>n.trim()).filter(Boolean)}catch{return[]}}var Om,kv,gu=G(()=>{Om=iB(aB),kv=64*1024*1024});function yu(e,{at:t=Date.now(),reason:n="node-transfer"}={}){let r=!1;for(let o of e?.boxes||[]){if(!o||typeof o!="object")continue;!dB.has(o.state)&&o.state!=="stopped"&&(o.state="stopped",r=!0);let s=Array.isArray(o.epochs)?o.epochs:[],a=s[s.length-1];a&&typeof a=="object"&&a.endedAt==null&&(a.endedAt=t,a.endReason==null&&(a.endReason=n),r=!0)}return r}var De,dB,Gt=G(()=>{De=e=>!!(e&&(e.archivedAt||e.transferredTo)),dB=new Set(["merged","conflict","canceled","failed","handed-off"])});import jm from"node:fs/promises";import Tv from"node:path";import pB from"node:os";function Iv(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(t.getDate()-(t.getDay()+6)%7),t.getTime()}function $v(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(1),t.getTime()}function Rv(e){let t=new Date(Iv(e));return t.setDate(t.getDate()+7),t.getTime()}function Ov(e){let t=new Date($v(e));return t.setMonth(t.getMonth()+1),t.getTime()}function ku(e=Date.now()){for(let[t,n]of Object.entries(zs)){let r=n.startOf(e);if(r!==er[t]){er[t]=r;for(let o of No.values())o[t]=0;for(let o of Vs)o.includes(`:${t}:`)&&!o.endsWith(`:${r}`)&&Vs.delete(o)}}}function Mv(e,t){let n=ln?.caps?.[e]?.[zs[t].capKey];return Number.isFinite(n)&&n>0?n:null}function Po(e,t=Date.now()){if(!e||!Fm||!ln?.caps)return null;ku(t);let n=No.get(e);for(let r of Object.keys(zs)){let o=Mv(e,r);if(o==null)continue;let s=n?.[r]||0;if(s>=o)return{provider:e,window:r,limitUsd:o,spentUsd:bu(s),resetsAt:zs[r].nextStart(t)}}return null}function Cv(e,t){let n=`hit:${e}:${t.provider}:${t.window}:${er[t.window]}`;return Vs.has(n)?!1:(Vs.add(n),!0)}function Sv(e,t,n,r=Date.now()){if(!e||!t)return;ku(r);let o=fB(e);for(let[s,a]of Object.entries(zs))n>=er[s]&&n<a.nextStart(r)&&(o[s]+=t)}async function mB(e,t,n=Date.now()){if(!ln?.caps||!Lm)return;let r=No.get(e);if(r)for(let[o,s]of Object.entries(zs)){let a=Mv(e,o);if(a==null)continue;let i=r[o]||0;if(i<a*_v||i>=a)continue;let c=`warn:${e}:${o}:${er[o]}`;if(!Vs.has(c)){Vs.add(c);try{let l=await Lm(t);if(!l)continue;await M(l,{type:"usage.cap.warning",actor:"system",provider:e,payload:{provider:e,window:o,limitUsd:a,spentUsd:bu(i),pct:Math.round(i/a*100),resetsAt:s.nextStart(n)}})}catch{}}}}function Nv(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 xu(e,{source:t="local",updatedAt:n=Date.now()}={}){ln={caps:Nv(e),updatedAt:n,source:t};try{await jm.mkdir(Av,{recursive:!0}),await jm.writeFile(Ev(),JSON.stringify(ln,null,2))}catch{}return Ci()}function Ci(e=Date.now()){ku(e);let t=new Set([...No.keys(),...Object.keys(ln?.caps||{})]),n={};for(let r of t){let o=No.get(r);n[r]={weeklyUsd:bu(o?.weekly||0),monthlyUsd:bu(o?.monthly||0)}}return{caps:ln?.caps||{},configured:!!ln,seeded:Fm,updatedAt:ln?.updatedAt??null,spent:n,windows:{weekly:{start:er.weekly,resetsAt:Rv(e)},monthly:{start:er.monthly,resetsAt:Ov(e)}},warnPct:_v}}async function Pv({listTracks:e,getTrack:t}={}){Lm=t||null,ku();try{let o=JSON.parse(await jm.readFile(Ev(),"utf8"));ln={caps:Nv(o?.caps),updatedAt:o?.updatedAt??null,source:o?.source??"file"}}catch{ln=null}let n=Date.now();Je.on("event",o=>{if(o?.type!=="cost.recorded")return;let{usd:s}=Kt(o);Sv(o.provider||"unknown",s,o.ts??Date.now()),mB(o.provider||"unknown",o.trackId).catch(()=>{})});let r=Math.min(er.weekly,er.monthly);for(let o of await e?.()||[]){let s;try{s=await K(o)}catch{continue}for(let a of s){if(a.type!=="cost.recorded")continue;let i=a.ts??0;i<r||i>=n||Sv(a.provider||"unknown",Kt(a).usd,i,n)}}return Fm=!0,Ci()}var Av,Ev,_v,zs,ln,Fm,er,No,Vs,Lm,fB,bu,vu=G(()=>{de();Lr();Av=process.env.BOSTRAT_STATE_DIR||Tv.join(process.env.HOME||pB.tmpdir(),".bostrat"),Ev=()=>Tv.join(Av,"usage-caps.json"),_v=.8;zs={weekly:{startOf:Iv,nextStart:Rv,capKey:"weeklyUsd"},monthly:{startOf:$v,nextStart:Ov,capKey:"monthlyUsd"}},ln=null,Fm=!1,er={weekly:0,monthly:0},No=new Map,Vs=new Set,Lm=null,fB=e=>{let t=No.get(e);return t||(t={weekly:0,monthly:0},No.set(e,t)),t};bu=e=>Math.round(e*1e4)/1e4});import hB from"node:fs/promises";import wB from"node:os";import Dv from"node:path";function qv(e){return e==="codex"?kB:e==="cursor"?Hv:Fv}function Bv(e){let t=String(e||"").split(`
178
- `),n=t.findIndex(o=>/Select Model and Effort/i.test(o));if(n<0)return null;let r=[];for(let o=n+1;o<t.length;o++){let s=t[o].match(/^\s*(›\s*)?(\d+)\.\s+(\S+?)(?:\s+\((current|default)\))?(?:\s{2,}|\s*$)/);if(s)r.push({n:Number(s[2]),id:s[3],current:s[4]==="current",active:!!s[1]});else if(r.length&&/Press enter|esc to go back/i.test(t[o]))break}return r.length?r:null}function jv(e){let t=String(e||"").split(`
179
- `),n=t.findIndex(o=>/Select Reasoning Level/i.test(o));if(n<0)return null;let r=[];for(let o=n+1;o<t.length;o++){let s=t[o].match(/^\s*(›\s*)?(\d+)\.\s+([A-Za-z ]+?)(?:\s+\((default|current)\))?(?:\s{2,}|\s*$)/);if(s)r.push({n:Number(s[2]),label:s[3].trim(),isDefault:!!s[4],active:!!s[1]});else if(r.length&&/Press enter|esc to go back/i.test(t[o]))break}return r.length?r:null}function xB(e){let t=String(e||"").split(`
180
- `);for(let n=t.length-1;n>=0;n--){let r=t[n].match(/Model changed to\s+(\S+)(?:\s+(\S+))?\s*$/i);if(r)return{model:r[1],effort:r[2]||null}}return null}function Lv(e){let t=String(e||"").split(`
181
- `),n=t.findIndex(s=>/Available models|Models matching/i.test(s));if(n<0)return null;let r=/Models matching/i.test(t[n]),o=[];for(let s=n+1;s<t.length;s++){let a=t[s];if(/^\s*Filter:/i.test(a)||!a.trim())continue;if(/to filter|Enter to select|^\s*\d+-\d+ of \d+/i.test(a))break;let i=a.match(/^\s*(→\s+)?(.+?)\s*$/);if(!i)continue;let c=i[2].replace(/\s*\(Tab to modify\)\s*$/i,""),l=null,u=c.split(/\s{2,}/);u.length>1&&(c=u[0],l=u.slice(1).join(" ").trim()||null),c&&o.push({label:c.trim(),params:l,active:!!i[1]})}return o.length?{filtered:r,rows:o}:null}function Wv(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&&!Uv.has(o))throw new Error(`unknown codex effort "${o}" (low | medium | high | xhigh)`);return{model:r,effort:o||null}}if(e==="cursor"){let r=Hv.find(o=>o.alias===n);return{model:n,filter:r?r.label:n}}if(!bB.has(n))throw new Error(`unknown model "${n}"`);return{model:n}}async function Ni(e,t,{timeoutMs:n=gB}={}){let r=Date.now()+n;for(;;){let o=await Be(e,{lines:80}).catch(()=>""),s=t(o);if(s)return s;if(Date.now()>r)return null;await Su(yB)}}async function vB(e,t){return await ot(e,`/model ${t.model}`,En("claude")),{verified:!1,note:"confirmed when the next turn's transcript model flips"}}async function SB(e,t){await Ul(e),await ot(e,"/model",{enter:!1}),await Su(250),await We(e,["Enter"],{kind:"model-switch"});let n=await Ni(e,Bv);if(!n)throw new Error("codex model picker didn't open");let r=n.find(i=>i.id===t.model);if(!r)throw await We(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=xB(i);return!c||c.model!==t.model||t.effort&&c.effort&&c.effort.toLowerCase()!==t.effort.toLowerCase()?null:c};await ot(e,String(r.n),{enter:!1,kind:"model-switch"});let s=await Ni(e,i=>jv(i)||!Bv(i)&&o(i)&&{done:o(i)});if(!s)throw await We(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error("codex reasoning-level picker didn't open");if(!s.done){let i=t.effort?Uv.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 We(e,["Escape","Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`codex doesn't offer effort "${t.effort}" for ${t.model}`);await ot(e,String(c.n),{enter:!1,kind:"model-switch"})}let a=s.done||await Ni(e,i=>!jv(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 TB(){let e=Dv.join(process.env.CURSOR_CONFIG_DIR||Dv.join(wB.homedir(),".cursor"),"cli-config.json");try{return JSON.parse(await hB.readFile(e,"utf8"))?.model||null}catch{return null}}async function AB(e,t){await Ul(e),await ql(e,`/model ${t.filter}`,{kind:"model-switch"});let n=await Ni(e,Lv),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 Ni(e,Lv,{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 We(e,["Down"],{kind:"model-switch"}),await Su(250)}if(!n||!s||!o(s)){await We(e,["Escape"],{kind:"model-switch"}).catch(()=>{});let c=Array(`/model ${t.filter}`.length).fill("BSpace");throw await We(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 We(e,["Enter"],{kind:"model-switch"}),await Su(800);let a=await TB();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 Kv(e,t,n){return e==="codex"?SB(t,n):e==="cursor"?AB(t,n):vB(t,n)}var Su,gB,yB,Fv,bB,kB,Uv,Hv,Gv=G(()=>{ct();ki();Su=e=>new Promise(t=>setTimeout(t,e)),gB=Number(process.env.BOSTRAT_MODEL_PICKER_TIMEOUT_MS)||8e3,yB=300,Fv=[{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"}],bB=new Set([...Fv.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"]),kB=[{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"}],Uv=new Map([["low","Low"],["medium","Medium"],["high","High"],["xhigh","Extra high"]]),Hv=[{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 Eu(e){let t=e||{},n=EB(t);return n&&(n.payload={ts:t.at,...n.payload}),n}function EB(e){switch(e.type){case"said":return{type:"turn.user",actor:"user",source:"orchestrator",boxId:e.box,provider:mt(e.agent),payload:{text:e.text,boxRole:e.boxRole,...e.kind?{kind:e.kind}:{},...e.attachments?.length?{attachments:e.attachments}:{},...e.deliveryId?{deliveryId:e.deliveryId}:{}}};case"unsaid":return{type:"turn.retracted",actor:"user",source:"orchestrator",boxId:e.box,provider:mt(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:mt(e.agent),payload:{text:e.prompt,kind:e.kind,boxRole:e.boxRole,...e.deliveryId?{deliveryId:e.deliveryId}:{}}};case"lead-handoff":return{type:"handoff.done",actor:"orchestrator",source:"orchestrator",boxId:e.to,provider:mt(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:mt(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:mt(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:mt(e.agent),payload:{...Kr(e)}};case"subtask-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box||e.to,provider:mt(e.agent||e.toAgent),payload:{kind:"subtask-failed",...Kr(e)}};case"subtask-resumed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:mt(e.agent),payload:{change:"subtask-resumed",...Kr(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",...Kr(e)}};case"opened":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:e.box,payload:{change:"opened",...Kr(e)}};case"archived":case"unarchived":case"track-deleted":case"renamed":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:e.type,...Kr(e)}};case"rehydrated":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:mt(e.agent),payload:{change:"rehydrated",...e.fresh?{fresh:!0}:{}}};case"lead-refreshed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:mt(e.agent),payload:{change:"lead-refreshed",box:e.box,agent:e.agent,fromSessionId:e.fromSessionId,toSessionId:e.toSessionId,epoch:e.epoch,reason:e.reason}};case"transferred-in":return{type:e.mode==="recover"?"track.recovered":"track.transferred",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:mt(e.agent),payload:{...Kr(e)}};case"transferred-out":return null;case"retagged":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:"retagged",...Kr(e)}};case"rehydrate-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:mt(e.agent),payload:{kind:"rehydrate-failed",reason:e.reason}};default:return null}}function Jv(e,t){let n=Eu(t);if(!n)return;let r=t?.type==="track-deleted"?{id:e.id}:e;_u(()=>M(r,n))}async function Yv(e){if(!(!e?.id||zv.has(e.id))){zv.add(e.id);try{let t=await K(e),n=new Set(t.filter(r=>r.source==="orchestrator").map(r=>`${r.type}|${r.payload?.ts??"?"}`));for(let r of e.events||[]){let o=Eu(r);!o||n.has(`${o.type}|${o.payload?.ts??"?"}`)||await M(e,o)}}catch{}}}function Kr(e){let{type:t,at:n,...r}=e;return r}function Xv(e,t,n){!n?.promptId||Au.get(e.id)===n.promptId||(Au.set(e.id,n.promptId),_u(()=>M(e,{type:"prompt.raised",actor:"agent",source:"pane",boxId:t?.name,provider:mt(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 Zv(e,t,n,r={}){Au.delete(e.id),_u(()=>M(e,{type:"prompt.dismissed",actor:"user",source:"orchestrator",boxId:t?.name,provider:mt(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}function Um(e,t,n,r={}){Au.delete(e.id),_u(()=>M(e,{type:"prompt.answered",actor:"user",source:"orchestrator",boxId:t?.name,provider:mt(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}var mt,Tu,_u,Vv,zv,Au,Hm=G(()=>{de();mt=e=>e||null;Tu=Promise.resolve(),_u=e=>(Tu=Tu.then(e).catch(()=>{}),Tu),Vv=()=>Tu;zv=new Set;Au=new Map});function OB(e){return String(e).split(/(?<=[.?!])\s+|\n+/).map(t=>t.trim()).filter(Boolean)}function oS(e){let t=String(e||"").trim();if(!t)return null;let n=t.slice(-600);for(let r of OB(n).reverse()){if(!_B.test(r))continue;let o=r.endsWith("?")&&r.length<=RB&&$B.test(r);if(IB.test(r)||o)return r.length>200?r.slice(0,197)+"\u2026":r}return null}function aS(e){let t=String(e||""),n=[];MB.test(t)&&n.push("commit"),sS.test(t)&&n.push("rebase"),CB.test(t)&&n.push("push");let r=PB.test(t);!r&&NB.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 iS(e){return sS.test(String(e||""))}function Js(e,{branch:t=null,base:n=null,toPr:r=null,repos:o=null,offeredRebase:s=!1}={}){Array.isArray(e)||(e=e==="push"?["commit","push"]:["commit","push","pr"]);let a=new Set(e),i=Array.isArray(o)&&o.length>0,c=i?o.map(f=>`${f.name}/`).join(", "):null,l=t?` on this branch (${t})`:"",u=[];if(a.has("commit")&&u.push(i?`commit the work in each changed checkout (${c})${l} with a clear commit message per repo`:`commit the work${l} with a clear commit message`),a.has("rebase")){let f=a.has("commit")?"the branch":`this branch${t?` (${t})`:""}`;u.push(i?`rebase ${f} in each changed checkout (${c}) onto its own base branch (fetch origin first), resolving any conflicts so both sides' intent is preserved`:`rebase ${f} onto ${n?`the latest ${n}`:"its base branch"} (fetch origin first), resolving any conflicts so both sides' intent is preserved`)}if(a.has("push")||a.has("pr")){let f=r&&!a.has("pr")?` (the open PR${r.number?` #${r.number}`:""} picks it up)`:"",w=a.has("rebase")?" with `--force-with-lease` (the rebase rewrote history)":"";i?u.push(a.has("commit")||a.has("rebase")?`push each one to its remote${w}${f}`:`push this branch${t?` (${t})`:""} from each changed checkout (${c}) to its remote${f}`):u.push(a.has("commit")||a.has("rebase")?`push it to the remote${w}${f}`:`push this branch${l} to the remote${f}`)}a.has("pr")&&u.push(i?"open a pull request in each changed repo with a concise title and a description of what changed and why (run `gh pr create` inside each checkout)":`open a pull request${n?` against ${n}`:""} with a concise title and a description of what changed and why (use \`gh pr create\`)`);let d=[];a.has("commit")||d.push("don't create any new commits \u2014 ship what's already committed"),s&&!a.has("rebase")&&d.push("don't rebase \u2014 leave the branch's history as it is"),!a.has("push")&&!a.has("pr")&&d.push("don't push"),a.has("pr")||d.push("don't open a pull request");let p=`Yes \u2014 go ahead: ${u.join(", then ")}.`;return d.length&&(p+=` ${d.join(", and ").replace(/^./,f=>f.toUpperCase())}.`),a.has("pr")&&(p+=i?" If a repo's PR for this branch is already open, just push that repo's update instead.":" If a PR for this branch is already open, just push the update instead."),p}function cS(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 lS(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<=DB&&n.push({box:r.box,from:r.from,to:t+1e12}),n}function uS(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+BB||(!o||s.ts>=o.ts)&&(o=s);o&&n.add(o)}return n}function dS(e){let t=(Array.isArray(e)?e:[]).filter(r=>Qv[r]).map(r=>Qv[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 eS,tS,nS,rS,_B,IB,$B,RB,Gr,MB,sS,CB,NB,PB,DB,BB,Qv,Do=G(()=>{eS=/(?<!\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,tS=/(?<!\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,nS=/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,rS=/(?<!\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,_B=new RegExp(`\\b(?:${eS}|${tS}|${nS}|${rS})\\b`,"i"),IB=/\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,$B=/^(?:commit|push|open|create|raise|rebase|ready|ok(?:ay)?\s+to|good\s+to)\b/i,RB=90;Gr=["commit","rebase","push","pr"],MB=new RegExp(`\\b(?:${eS})\\b`,"i"),sS=new RegExp(`\\b(?:${rS})\\b`,"i"),CB=new RegExp(`\\b(?:${tS})\\b`,"i"),NB=new RegExp(`\\b(?:${nS})\\b`,"i"),PB=/\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;DB=3e4;BB=2500;Qv={commit:"commit",rebase:"rebase",push:"push",pr:"open a PR"}});import jB from"node:crypto";import Iu from"node:fs/promises";import pS from"node:path";import LB from"node:os";async function Ke(){return zr||(qm??=Iu.readFile(Km,"utf8").then(e=>({links:JSON.parse(e)?.links??{},existed:!0})).catch(()=>({links:{},existed:!1})).then(async({links:e,existed:t})=>{if(zr=e,!t&&He()){let{records:n,source:r}=await st("prlinks").catch(()=>({records:[],source:"error"}));if(r==="plane"){for(let o of n){if(o.deletedAt||!o.data?.repo||o.data?.number==null)continue;let{id:s,updatedAt:a,...i}=o.data;zr[ae(i.repo,i.number)]=i}Object.keys(zr).length&&await Gm().catch(()=>{})}}return zr}).finally(()=>qm=null),qm)}async function Gm(){let e=JSON.stringify({links:zr},null,2),t=`${Km}.${process.pid}.tmp`;await Iu.mkdir(fS,{recursive:!0}),await Iu.writeFile(t,e),await Iu.rename(t,Km)}async function Qe(e){Wm=Wm.then(Gm,Gm),await Wm.catch(()=>{});let t=zr?.[e];t&&bt("prlinks",{id:mS(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 Ke(),c=ae(e,t);return i[c]?{link:i[c],created:!1}:(i[c]={repo:e,number:Number(t),trackId:n,url:r,headRef:o,title:s,source:a,announced:FB.has(a),firstSeen:Date.now()},await Qe(ae(e,t)),{link:i[c],created:!0})}async function tr(e,t){if(!e||t==null)return null;let n=(await Ke())[ae(e,t)];return!n||n.announced?null:(n.announced=!0,await Qe(ae(e,t)),n)}async function hS(e,t){if(!e||t==null)return!1;let n=(await Ke())[ae(e,t)];return n?.notifyOnMerge?(delete n.notifyOnMerge,await Qe(ae(e,t)),!0):!1}async function at(e,t){return!e||t==null?null:(await Ke())[ae(e,t)]??null}async function Vr(e,t,n){if(!e||t==null)return null;let r=(await Ke())[ae(e,t)];return r?(r.state=n,r.resolvedAt=Date.now(),delete r.armedAt,delete r.autoMerge,delete r.archiveOnMerge,delete r.notifyOnMerge,delete r.notifyPending,delete r.followupPending,await Qe(ae(e,t)),r):null}async function wS(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await Ke())[ae(e,t)];return o?(o.ciFix={delegatedAt:Date.now(),headSha:n,trackId:r},await Qe(ae(e,t)),o):null}async function gS(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await Ke())[ae(e,t)];return o?(o.reconcile={delegatedAt:Date.now(),headSha:n,trackId:r},await Qe(ae(e,t)),o):null}async function $u(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await Ke())[ae(e,t)];return!r||!r.ciFix?null:(r.ciFixAwait={since:Date.now(),trackId:r.ciFix.trackId??null,headSha:n},delete r.ciFix,await Qe(ae(e,t)),r)}async function Ru(e,t){if(!e||t==null)return null;let n=(await Ke())[ae(e,t)];return!n||!n.ciFixAwait?null:(delete n.ciFixAwait,await Qe(ae(e,t)),n)}async function Ou(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await Ke())[ae(e,t)];return!r||!r.reconcile?null:(r.reconcileAwait={since:Date.now(),trackId:r.reconcile.trackId??null,headSha:n},delete r.reconcile,await Qe(ae(e,t)),r)}async function Mu(e,t){if(!e||t==null)return null;let n=(await Ke())[ae(e,t)];return!n||!n.reconcileAwait?null:(delete n.reconcileAwait,await Qe(ae(e,t)),n)}async function yS(e,t,{at:n=Date.now()}={}){if(!e||t==null)return null;let r=(await Ke())[ae(e,t)];return r?(r.baseFoldAt=n,await Qe(ae(e,t)),r):null}async function bS(e,t){if(!e||t==null)return null;let n=(await Ke())[ae(e,t)];return!n||!n.baseFoldAt?null:(delete n.baseFoldAt,await Qe(ae(e,t)),n)}async function kS(e,t,n){if(!e||t==null||!n)return null;let r=(await Ke())[ae(e,t)];return r?(r.lastHeadSha=n,await Qe(ae(e,t)),r):null}async function xS(e,t,n){if(!e||t==null||!n)return{prev:null,link:null};let r=(await Ke())[ae(e,t)];if(!r)return{prev:null,link:null};let o=r.verdict??null;return o&&o.blocked===(n.blocked??null)&&(o.sha??null)===(n.sha??null)||(r.verdict={blocked:n.blocked??null,sha:n.sha??null,at:n.at??Date.now()},await Qe(ae(e,t))),{prev:o,link:r}}async function Pi(e,t,{merge:n=null}={}){if(!e||t==null)return null;let r=(await Ke())[ae(e,t)];return r?(r.armedAt=Date.now(),n&&(r.autoMerge={method:n.method||"merge",armedAt:r.armedAt}),await Qe(ae(e,t)),r):null}async function Bo(e,t,n=!0){if(!e||t==null)return null;let r=(await Ke())[ae(e,t)];return r?(n?r.archiveOnMerge=!0:delete r.archiveOnMerge,await Qe(ae(e,t)),r):null}async function jo(e,t,n=!0){if(!e||t==null)return null;let r=(await Ke())[ae(e,t)];return r?(n?r.notifyOnMerge=!0:delete r.notifyOnMerge,await Qe(ae(e,t)),r):null}async function vS(e,t,n){if(!e||t==null)return null;let r=(await Ke())[ae(e,t)];if(!r)return null;r.notifyOnMerge=!0;let o=new Map((r.notifyPending||[]).map(s=>[`${s.repo}#${s.number}`,s]));for(let s of n||[])s&&s.number!=null&&o.set(`${s.repo}#${s.number}`,s);return r.notifyPending=[...o.values()],await Qe(ae(e,t)),r}async function SS(e,t,n){if(!e||t==null)return null;let r=(await Ke())[ae(e,t)];if(!r)return null;let o=new Map((r.followupPending||[]).map(s=>[`${s.repo}#${s.number}`,s]));for(let s of n||[])s&&s.number!=null&&o.set(`${s.repo}#${s.number}`,s);return r.followupPending=[...o.values()],await Qe(ae(e,t)),r}async function Di(e,t){if(!e||t==null)return null;let n=(await Ke())[ae(e,t)];return!n||!n.armedAt&&!n.autoMerge?null:(delete n.armedAt,delete n.autoMerge,delete n.archiveOnMerge,delete n.notifyOnMerge,delete n.notifyPending,await Qe(ae(e,t)),n)}async function TS(){return Object.values(await Ke()).filter(e=>!UB.has(e.state))}async function un(){return Object.values(await Ke()).sort((e,t)=>t.firstSeen-e.firstSeen)}async function AS(){if(!He())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("prlinks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Ke(),r=0;for(let[o,s]of Object.entries(n))await bt("prlinks",{id:mS(o),updatedAt:Date.now(),...s},{trackId:s.trackId??null}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}var fS,Km,ae,mS,zr,qm,Wm,FB,UB,Rn=G(()=>{Ir();fS=process.env.BOSTRAT_STATE_DIR||pS.join(process.env.HOME||LB.tmpdir(),".bostrat"),Km=pS.join(fS,"pr-links.json"),ae=(e,t)=>`${e}#${Number(t)}`,mS=e=>{let t=e.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^[^A-Za-z0-9]+/,"").slice(0,55),n=jB.createHash("sha256").update(e).digest("hex").slice(0,8);return`${t||"pr"}-${n}`},zr=null,qm=null,Wm=Promise.resolve();FB=new Set(["api","observed","reconciled"]);UB=new Set(["merged","closed","lost"])});import HB from"node:fs";import zm from"node:fs/promises";import $S from"node:path";import qB from"node:os";function MS(e,t=!1){if(!t&&e-_S<WB)return;_S=e;let n=JSON.stringify({windowStart:Ys,byCaller:Object.fromEntries(nr),lastHour:Jr});IS=IS.then(()=>zm.mkdir(RS,{recursive:!0})).then(()=>zm.writeFile(`${Cu}.tmp`,n)).then(()=>zm.rename(`${Cu}.tmp`,Cu)).catch(()=>{})}function CS(e){e-Ys<OS||(Jr={start:Ys,total:Nu(nr),byCaller:Object.fromEntries(nr)},Jr.total&&console.log(`[github] ${Jr.total} calls last hour`,Jr.byCaller),Ys=e,nr=new Map,MS(e,!0))}function rr(e="other",t=Date.now()){CS(t),nr.set(e,(nr.get(e)||0)+1),MS(t)}function NS(e=Date.now()){return CS(e),{windowStart:Ys,total:Nu(nr),byCaller:Object.fromEntries(nr),lastHour:Jr,backoffUntil:Lo>e?Lo:null}}function Yr(e){return KB.test(String(e?.message||e||""))}function Xr(e,t=Date.now()){return Lo<=t&&console.warn(`[github] rate limited \u2014 backing off ${ES/6e4} min:`,String(e?.message||e||"").slice(0,200)),Lo=Math.max(Lo,t+ES),Lo}function Pu(e=Date.now()){return Math.max(0,Lo-e)}var RS,Cu,OS,ES,WB,Ys,nr,Jr,Lo,_S,Nu,IS,KB,Bi=G(()=>{RS=process.env.BOSTRAT_STATE_DIR||$S.join(process.env.HOME||qB.tmpdir(),".bostrat"),Cu=$S.join(RS,"github-metrics.json"),OS=60*6e4,ES=5*6e4,WB=6e4,Ys=Date.now(),nr=new Map,Jr=null,Lo=0,_S=0,Nu=e=>[...e.values()].reduce((t,n)=>t+n,0);try{let e=JSON.parse(HB.readFileSync(Cu,"utf8"));e?.windowStart&&(Date.now()-e.windowStart<OS?(Ys=e.windowStart,nr=new Map(Object.entries(e.byCaller||{})),Jr=e.lastHour||null):Nu(new Map(Object.entries(e.byCaller||{})))&&(Jr={start:e.windowStart,total:Nu(new Map(Object.entries(e.byCaller||{}))),byCaller:e.byCaller||{}}))}catch{}IS=Promise.resolve();KB=/rate limit|too quickly|abuse detection|HTTP 429/i});import PS from"node:fs/promises";import DS from"node:path";import GB from"node:os";function Bu({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};Du.push(l),Du.length>VB&&Du.shift();let u=Vm.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)),Vm.set(e,u),JB(l),l}async function JB(e){try{await PS.mkdir(BS,{recursive:!0}),await PS.appendFile(zB,JSON.stringify(e)+`
182
- `)}catch{}}function jS(){let e={};for(let[t,n]of Vm)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:Du.slice(-20)}}var BS,zB,VB,Du,Vm,ju=G(()=>{BS=process.env.BOSTRAT_STATE_DIR||DS.join(process.env.HOME||GB.tmpdir(),".bostrat"),zB=DS.join(BS,"github-latency.ndjson"),VB=100,Du=[],Vm=new Map});import{execFile as YB}from"node:child_process";import{promisify as XB}from"node:util";async function ZB(e){let t=/workspaces[/\\]([0-9a-f]{8})(?:[/\\]|$)/.exec(e||"")?.[1];if(t)try{let[{stdout:n},{stdout:r}]=await Promise.all([Zs("git",["-C",e,"rev-parse","HEAD"]),Zs("git",["-C",e,"rev-parse","--abbrev-ref","HEAD"])]);await M({id:t,cwd:e},{type:"code.pushed",actor:"orchestrator",payload:{ref:r.trim(),sha:n.trim(),wip:!1,ts:Date.now()}})}catch{}}async function zt(e,t,n={}){let{caller:r="prs",...o}=n,s=await vn({cwd:e});rr(r);try{let{stdout:a}=await Zs("gh",t,{cwd:e,...QB,...o,env:{...process.env,...s,...o.env||{}}});return String(a||"")}catch(a){throw Yr(a)&&Xr(a),a}}async function Xm(){if(Lu&&Date.now()-Lu.at<6e4)return Lu.data;let e;try{rr("auth");let t=await Zs("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 za();t.configured&&(e={installed:!0,authenticated:!0,login:t.username,via:"broker"})}catch{}return Lu={at:Date.now(),data:e},e}async function ej(e){try{let{stdout:t}=await Zs("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});return/github\.com/.test(t)}catch{return!1}}function FS(e){let t=e.name||e.context||"check",n=e.detailsUrl||e.targetUrl||null,r=e.completedAt||e.createdAt||null,o;return e.__typename==="StatusContext"?o=e.state==="SUCCESS"?"pass":e.state==="PENDING"||e.state==="EXPECTED"?"pending":"fail":e.status&&e.status!=="COMPLETED"?o="pending":["SUCCESS","NEUTRAL","SKIPPED"].includes(e.conclusion)?o="pass":o="fail",{name:t,state:o,url:n,completedAt:r}}function Jm(e){let t=(e||[]).map(FS),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 Qm(e){return/Resource not accessible by personal access token/.test(String(e?.stderr||e?.message||""))}async function HS(e,t){if(!t)return null;let n=await _e(e);if(!n)return null;try{let r=await zt(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 qS(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 WS(e,t){let n=await HS(e,t);return n===null?{...Jm([]),unavailable:!0}:Jm(qS(n))}function Fu(e,t=Jm(e.statusCheckRollup)){return{number:e.number,title:e.title,url:e.url,author:e.author?.login??null,headRefName:e.headRefName,headSha:e.headRefOid??null,baseRefName:e.baseRefName,isDraft:!!e.isDraft,reviewDecision:e.reviewDecision||null,mergeable:e.mergeable||"UNKNOWN",mergeStateStatus:e.mergeStateStatus||"UNKNOWN",state:e.state??null,mergedAt:e.mergedAt??null,closedAt:e.closedAt??null,additions:e.additions??0,deletions:e.deletions??0,createdAt:e.createdAt,updatedAt:e.updatedAt,checks:t,green:t.failed===0&&t.pending===0&&e.mergeStateStatus==="CLEAN",autoMergeArmed:!!e.autoMergeRequest,mergeabilityPending:!1}}function nj(e,t,n){let r=new Set;for(let o of t){let s=`${e}#${o.number}`;if(o.mergeable!=="UNKNOWN"&&o.mergeStateStatus!=="UNKNOWN"){Xs.delete(s);continue}r.add(s),Xs.has(s)||Xs.set(s,n),o.mergeabilityPending=n-Xs.get(s)<tj}for(let o of Xs.keys())o.startsWith(`${e}#`)&&!r.has(o)&&Xs.delete(o);return t}async function Qs(e,t){let n=await or(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{let o=await zt(n.path,["pr","view",String(r),"--json",Zm]);return Fu(JSON.parse(o))}catch(o){if(!Qm(o))throw o;let s=await zt(n.path,["pr","view",String(r),"--json",US]),a=JSON.parse(s);return Fu(a,await WS(n.path,a.headRefOid))}}async function On(e,{caller:t="prs"}={}){try{let n=await zt(e,["pr","list","--json",Zm,"--limit","50"],{caller:t});return JSON.parse(n||"[]").map(r=>Fu(r)).sort(LS)}catch(n){if(!Qm(n))throw n;let r=await zt(e,["pr","list","--json",US,"--limit","50"],{caller:t});return(await Promise.all(JSON.parse(r||"[]").map(async o=>Fu(o,await WS(e,o.headRefOid))))).sort(LS)}}function Vt(){ji.clear()}async function sj(e,t){if(!e)return t;for(let n of t){let r=await at(e,n.number).catch(()=>null);if(!r)continue;r.trackId&&(n.trackId=r.trackId),r.autoMerge&&(n.autoMergeArmed=!0),r.archiveOnMerge&&(n.archiveOnMerge=!0),r.notifyOnMerge&&(n.notifyOnMerge=!0);let o=s=>n.headSha&&s.headSha&&n.headSha!==s.headSha;r.ciFix&&(o(r.ciFix)?await $u(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.ciFix={delegatedAt:r.ciFix.delegatedAt,trackId:r.ciFix.trackId??null}),r.reconcile&&(o(r.reconcile)?await Ou(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.reconcile={delegatedAt:r.reconcile.delegatedAt,trackId:r.reconcile.trackId??null})}return t}async function KS(){let e=await Xm();if(!e.authenticated)return{auth:e,repos:[]};let t=[];for(let a of await Jn())await ej(a.path)&&t.push(a);let n=Date.now(),r=Pu(n)>0,o=await Promise.all(t.map(async a=>{let i=ji.get(a.path),c=i?.pending?oj:rj;if(i&&(r||n-i.at<c))return i.entry;try{let l=await _e(a.path).catch(()=>null),u=nj(a.path,await On(a.path,{caller:"tab"}),n);if(await sj(l,u),i?.entry?.prs)for(let f of u)i.entry.prs.find(m=>m.number===f.number)?.checks?.pending>0&&f.checks.total>0&&f.checks.pending===0&&Bu({change:f.checks.failed>0?"checks-failed":"checks-green",repo:l||a.name,number:f.number,githubAt:f.checks.settledAt,source:"tab"});let d={name:a.name,path:a.path,prs:u},p=u.some(f=>f.mergeabilityPending||f.checks.pending>0||f.autoMergeArmed);return ji.set(a.path,{at:Date.now(),entry:d,pending:p}),d}catch(l){return i?i.entry:{name:a.name,path:a.path,prs:[],error:Mn(l)}}})),s=new Set(t.map(a=>a.path));for(let a of ji.keys())s.has(a)||ji.delete(a);return{auth:e,repos:o}}async function or(e){let t=(await Jn()).find(n=>n.path===e);if(!t)throw new Error(`unknown repo: ${e}`);return t}async function Fo(e){return ws(e)}async function ea(e,t,{method:n="squash"}={}){let r=await or(e);if(!Li.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 vn({cwd:r.path})).GH_TOKEN){let a=await qp().catch(()=>null);a&&s.push("--body",`Merged by bostrat on behalf of @${a}`)}try{await zt(r.path,s)}catch(a){throw new Error(Mn(a))}finally{Vt()}return{ok:!0,number:o}}async function Fi(e,t){let n=await or(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await zt(n.path,["api","-X","PUT",`repos/{owner}/{repo}/pulls/${r}/update-branch`])}catch(s){throw new Error(Mn(s))}finally{Vt()}let o=await _e(n.path).catch(()=>null);return o&&await yS(o,r).catch(()=>{}),{ok:!0,number:r}}async function eh(e,t){let n=await or(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await zt(n.path,["pr","merge",String(r),"--disable-auto"])}catch(o){throw new Error(Mn(o))}finally{Vt()}return{ok:!0,number:r}}function th(e){return e.green&&!e.isDraft}function lj(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 GS(e,{update:t=!0}={}){return e.isDraft?{action:"skip",reason:"draft"}:th(e)?{action:"merge"}:t&&e.mergeStateStatus==="BEHIND"&&e.mergeable!=="CONFLICTING"&&e.checks.failed===0?{action:"update-arm"}:{action:"arm"}}function zS(e){return[...e.filter(t=>t.plan.action!=="merge"),...e.filter(t=>t.plan.action==="merge")]}function Ui(e,t){let n=a=>a?.firstSeen!=null&&Number.isFinite(Number(a.firstSeen))?Number(a.firstSeen):Number.MAX_SAFE_INTEGER,r=n(e),o=n(t);if(r!==o)return r-o;let s=String(e?.repo||"").localeCompare(String(t?.repo||""));return s||Number(e?.number||0)-Number(t?.number||0)}function VS(e){let t=new Map;for(let n of[...e].filter(r=>r?.autoMerge&&r?.trackId).sort(Ui))t.has(n.trackId)||t.set(n.trackId,`${n.repo}#${n.number}`);return t}function JS(){let e={};for(let[t,n]of Ym)e[t]={...n};return e}async function YS(e,{method:t="merge",onMerged:n=null}={}){let r=await or(e);if(!Li.has(t))throw new Error(`invalid merge method: ${t}`);if(Ym.get(r.path)?.running)throw new Error("a merge-all is already running for this repo");let o=(await On(r.path)).filter(th).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 Ym.set(r.path,s),dj(s,o,{listPrs:()=>On(r.path),merge:a=>ea(r.path,a,{method:t}),sleep:cj,onMerged:n}).catch(()=>{}),{ok:!0,repo:r.path,total:s.total,queue:o.map(a=>a.number)}}async function uj(e,t){let n=Date.now()+(t.settleMaxMs??ij),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(aj)}}async function dj(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 uj(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: ${Mn(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(!th(a)){e.skipped.push({number:a.number,title:a.title,reason:lj(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:Mn(i)})}}}finally{e.current=null,e.running=!1,e.finishedAt=Date.now(),Vt()}}async function nh(e,{title:t,body:n="",base:r=null}={}){if(typeof t!="string"||!t.trim())throw new Error("title required");try{await Zs("git",["-C",e,"push","-u","origin","HEAD"],{timeout:12e4,maxBuffer:4*1024*1024})}catch(l){throw new Error(`push failed: ${Mn(l)}`)}await ZB(e);let o=n||"";if((await vn({cwd:e})).GH_TOKEN){let l=await qp().catch(()=>null);l&&(o=`${o?`${o}
183
-
184
- `:""}Opened by bostrat on behalf of @${l}`)}let s=["pr","create","--title",t.trim(),"--body",o];r&&s.push("--base",r);let a;try{a=await zt(e,s)}catch(l){throw new Error(Mn(l))}finally{Vt()}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 XS(e,t){let n=await or(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");let o;try{let i;try{i=await zt(n.path,["pr","checks",String(r),"--json","name,state,link,bucket"])}catch(c){if(i=String(c?.stdout||""),!i.trim())throw new Error(Mn(c))}o=JSON.parse(i||"[]").filter(c=>c.bucket==="fail")}catch(i){if(!Qm(i))throw i;let c=await zt(n.path,["pr","view",String(r),"--json","headRefOid"]),l=await HS(n.path,JSON.parse(c).headRefOid);if(l===null)throw new Error(Mn(i));o=qS(l).map(FS).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=pj(i.link),l=null;c&&!s.has(c)&&(s.add(c),l=await zt(n.path,["run","view",c,"--log-failed"]).then(u=>fj(u)).catch(()=>null)),a.push({name:i.name,link:i.link||null,log:l})}return a}function pj(e){return String(e||"").match(/\/actions\/runs\/(\d+)/)?.[1]??null}function fj(e,{maxLines:t=400,maxBytes:n=64*1024}={}){let r=String(e||""),o=r.split(`
153
+ `});function jD(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 cx(e,t,n){let r=fm(n),o=e.has(r)?r:null;if(!o&&n.number!=null)for(let[i,c]of e){if(Number(c.number)!==Number(n.number))continue;let l=!!(n.url&&c.url&&n.url===c.url),u=!c.repo&&!!n.repo||!!c.repo&&!n.repo;if(l||u&&(!c.url||!n.url||c.url===n.url)){o=i;break}}let s=n.repo||!o?r:o,a=o?e.get(o):e.get(s);if(o&&o!==s){e.delete(o);let i=t.get(o);if(t.delete(o),i?.length){let c=t.get(s)??[];t.set(s,c.concat(i))}}return e.set(s,{number:n.number,url:n.url??a?.url??null,title:n.title??a?.title??null,repo:n.repo??a?.repo??null,branch:n.branch??a?.branch??null}),s}function Rn(e){let t=[],n=new Set,r=new Set,o=new Map,s=new Map,a=new Set,i=new Map,c=new Map,l=new Set,u=new Map,d=new Map,p=(k,h)=>{d.set(k,h),t.push(h)},f=k=>{let h=d.get(k);h&&(h.retired=!0)},w=/^Agent "([\s\S]+)" finished$/,m=new Map;for(let k of e||[]){if(k.type!=="tool.called"||k.source!=="transcript")continue;let h=String(k.payload?.command||"");if(/\bbostrat-mock\s+(?:add|update)\b/.test(h))for(let v of h.matchAll(/[\w./~-]+\.(?:png|jpe?g|gif|webp|bmp|svg)\b/gi)){let P=v[0].split("/").pop().toLowerCase();m.has(P)||m.set(P,[]),m.get(P).push(k.payload?.ts??k.ts)}}let g=3*6e4,y=20*6e4,x=(k,h)=>!!(k?.name&&m.get(String(k.name).toLowerCase()))?.some(P=>P>=h-g&&P<=h+y);for(let k of e||[])if(k.type==="turn.retracted"){r.add(`${k.boxId}|${k.payload?.saidTs}`);let h=Fe(k.payload?.text);h&&(o.has(k.boxId)||o.set(k.boxId,[]),o.get(k.boxId).push(h))}else if(k.type==="turn.user"&&k.source==="orchestrator"){let h=Fe(k.payload?.text);h&&(s.has(k.boxId)||s.set(k.boxId,new Set),s.get(k.boxId).add(h))}else if(k.type==="job.stalled"&&k.payload?.id)i.set(k.payload.id,{ts:me(k),quietMs:Number(k.payload.quietMs)||null});else if(k.type==="job.started"&&k.payload?.id)a.add(k.payload.id),(k.payload.kind||"agent")==="agent"&&k.payload.name&&l.add(k.payload.name);else if(k.type==="turn.user"&&k.payload?.note?.kind==="task"){let h=k.payload.note,v={status:h.status||null,summary:h.summary||null,resultHead:h.resultHead??null,ts:me(k)};h.toolUseId&&c.set(h.toolUseId,v);let P=String(h.summary||"").match(w);P&&u.set(P[1],v)}let b=new Map,R=new Map,_=null,C=new Map,U=new Map,B=new Map,T=new Map,$=new Map,L=new Map,J=new Map,A=new Map,S=new Map,N=new Map,H=new Map,q=new Map,re=new Map,we=new Map,Re=new Map,Ee=[],Z=k=>Ee.push(k),ye=k=>{if(!Ee.length)return;let h=me(k);for(let v of Ee){if(v.status!=="open"||v.box&&v.box!==k.boxId||(v.ts??0)>h)continue;let P=t.indexOf(v);P>=0&&t.splice(P,1),v.ts=h,t.push(v)}},X=new Map,Y=new Map,ie=new Map,ve=new Map,Ne=new Map,O=new Map,D=new Map,pe=new Map,Le=()=>{for(let k of pe.values())k.questions.length&&t.push(k);pe.clear()},Ce=null,Kt=new Map,Tt=6e4,Jn=new Map,Sn=(k,h)=>{let v=o.get(k);if(!v?.length)return!1;let P=Fe(h),oe=s.get(k);return v.some(ge=>{if(!P.startsWith(ge))return!1;let Me=Fe(P.slice(ge.length));return!!Me&&!!oe?.has(Me)})};for(let k of e||[]){let h=k.payload||{};switch(k.type){case"turn.user":{if(k.source==="hook"||(Ee.length=0,!String(h.text||"").trim()&&!h.images?.length&&!h.attachments?.length))break;{let v=ex(h.text);if(v){if(v.kind==="shell-input"){let P={id:k.id,kind:"shell",command:v.command,stdout:null,stderr:null,done:!1,ts:me(k),box:k.boxId,agent:k.provider};t.push(P),Kt.set(k.boxId,P)}else{let P=Kt.get(k.boxId);P?(P.stdout=v.stdout||null,P.stderr=v.stderr||null,P.done=!0,Kt.delete(k.boxId)):t.push({id:k.id,kind:"shell",command:null,stdout:v.stdout||null,stderr:v.stderr||null,done:!0,ts:me(k),box:k.boxId,agent:k.provider})}break}}{let v=h.note||Pi(h.text);if(v){if(v.kind==="task"){if(v.toolUseId&&a.has(v.toolUseId))break;let P=String(v.summary||"").match(w);if(!v.toolUseId&&P&&l.has(P[1]))break}if(v.kind==="command"&&Z0(v.command))break;if(v.kind==="resume-summary"){t.push({id:k.id,kind:"resume-summary",title:v.title||"Context resumed from summary",bullets:v.bullets||[],sections:v.sections||[],rawChars:v.rawChars??null,ts:me(k),box:k.boxId,agent:k.provider});break}v.kind!=="suppress"&&t.push({id:k.id,kind:"event",type:nx(v),name:v.name??null,command:v.command??null,summary:v.summary??null,status:v.status??null,ts:me(k),box:k.boxId,agent:k.provider});break}}if(r.has(`${k.boxId}|${me(k)}`)||k.source==="transcript"&&Sn(k.boxId,h.text))break;if(h.kind==="merge-notify"||h.kind==="ship-notify"){t.push({id:k.id,kind:"event",type:h.kind==="ship-notify"?"ship-notified":"merge-notified",text:h.text,ts:me(k),box:k.boxId,agent:k.provider});break}if(h.kind==="mock-picked"||h.kind==="ci-fix"||h.kind==="reconcile"||h.kind==="pr-go"||h.kind==="push-go"||h.kind==="spin-up-view"||h.kind==="prompt-answer"||h.kind==="followup-go"){h.kind==="prompt-answer"&&(Ce=null);break}for(let v of C.values())v.status="stale";C.clear();for(let v of B.values())v.status="stale";B.clear();for(let v of re.values())v.status="stale";re.clear(),Ce&&Ce.box===k.boxId&&(t.push(jD(Ce)),Ce=null),t.push({id:k.id,kind:"message",role:"user",text:h.text,ts:me(k),box:k.boxId,agent:k.provider,boxRole:h.boxRole,...k.actor==="orchestrator"?{orchestration:h.kind||!0}:{},...h.sourceId?{sourceId:h.sourceId}:{},...h.attachments?.length?{attachments:h.attachments}:{},...h.images?.length?{images:h.images}:{}});break}case"peer.message":{let v=h.from||{};t.push({id:k.id,kind:"event",type:"peer-message",text:h.text,from:v.trackName||v.boxId||v.name||null,fromTrackId:v.trackId||null,ts:me(k),box:k.boxId,agent:k.provider});break}case"turn.agent":{if(h.model==="<synthetic>"&&/^No response requested\.$/.test(String(h.text||"").trim()))break;let v=d0(h,{codexFailedText:Co});if(v){t.push({id:k.id,kind:"event",type:"provider-error",cls:v.cls,status:v.status??void 0,text:v.text,provider:k.provider,legacy:!0,at:me(k),ts:me(k),box:k.boxId,agent:k.provider});break}Le();let P=(h.images||[]).filter(Ge=>!x(Ge,me(k)));if(!String(h.text||"").trim()&&!P.length)break;if(k.provider==="cursor"){let Ge=`${k.boxId}|${h.text}`;if(n.has(Ge))break;n.add(Ge)}(!Ce||Ce.box===k.boxId)&&(Ce=null);let oe=k.provider==="codex"?(h.tools||[]).filter(Ge=>!Hf.has(Ge)&&!vi.has(Ge)):h.tools||[],ge=h.text,Me=null,tt=lm(String(h.text||""));tt&&(ge=tt.text,Me={questions:tt.questions}),t.push({id:k.id,kind:"message",role:"assistant",text:ge,ts:me(k),box:k.boxId,agent:k.provider,boxRole:h.boxRole,...Me?{ask:Me}:{},...oe.length?{tools:oe}:{},...h.model?{model:h.model}:{},...h.sourceId?{sourceId:h.sourceId}:{},...P.length?{images:P}:{}}),ye(k),Me&&(Ce={id:k.id,groupId:um(k.provider,h.sourceId||k.id,Me.questions),provider:k.provider,box:k.boxId,questions:Me.questions,ts:me(k)});break}case"job.started":{if(!h.id)break;let v=me(k),P=c.get(h.id);if(!P&&(h.kind||"agent")==="agent"&&h.name){let Gt=u.get(h.name);Gt&&Gt.ts>=v&&(P=Gt)}let oe=P?null:i.get(h.id)||null,ge={jobId:h.id,jobKind:h.kind||"agent",name:h.name||null,detail:h.detail||null,status:P?P.status==="killed"?"stopped":P.status&&P.status!=="completed"?"failed":"done":oe?"stalled":"running",startedTs:v,finishedTs:P?.ts??oe?.ts??null,quietMs:oe?.quietMs??null,summary:P?.summary??null,resultHead:P?.resultHead??null},Me=Jn.get(k.boxId),tt=Me?.jobs[Me.jobs.length-1]?.startedTs;if(Me&&tt!=null&&v-tt<=Tt)Me.jobs.push(ge);else{let Gt={id:k.id,kind:"job-dock",dockId:h.id,ts:v,box:k.boxId,agent:k.provider,jobs:[ge]};Jn.set(k.boxId,Gt),t.push(Gt)}break}case"handoff.done":t.push(lt(k,"lead-handoff"));break;case"subtask.delegated":t.push({...lt(k,"subtask-delegated"),to:k.boxId,toAgent:k.provider});break;case"subtask.merged":t.push(lt(k,"subtask-merged"));break;case"pr.state.changed":{if(!h.change)break;if(h.change==="opened"){for(let P of C.values())P.status="stale";C.clear();for(let P of B.values())P.status="stale";B.clear()}let v=lt(k,`pr-${h.change}`);if(v.box=k.boxId??null,ix.has(h.change)&&h.number!=null){let P=cx(b,R,h);if(b.size>=2){for(let ge of R.values())for(let Me of ge)Me.grouped=!0;v.groupPrs=[...b.values()];let oe=[v];for(let ge of b.keys())R.set(ge,oe)}else{let oe=R.get(P)??[];oe.push(v),R.set(P,oe)}}else if(h.change==="merged"||h.change==="closed"||h.change==="lost"){let P=fm(h),oe=_&&!_.complete||b.size>=2;if(b.has(P))b.delete(P),R.delete(P);else if(h.number!=null)for(let ge of[...b.keys()])ge.endsWith(`#${h.number}`)&&(b.delete(ge),R.delete(ge));if(oe&&h.number!=null){(!_||_.complete)&&(_={id:k.id,kind:"event",type:"pr-group-settled",prs:[],remaining:[],complete:!1,at:me(k),ts:me(k),box:k.boxId,agent:k.provider},t.push(_)),_.prs.push({number:h.number,url:h.url??null,title:h.title??null,repo:h.repo??null,branch:h.branch??null,change:h.change,ts:me(k)}),_.remaining=[...b.values()],_.complete=b.size===0;break}}t.push(v);break}case"pr.offered":{if(!h.offerId)break;for(let P of C.values())P.status="stale";C.clear();for(let P of B.values())P.status="stale";B.clear();let v={id:k.id,kind:"pr-offer",offerId:h.offerId,excerpt:h.excerpt||null,branch:h.branch||null,base:h.base||null,offered:Array.isArray(h.offered)&&h.offered.length?h.offered:null,toPr:h.toPr&&typeof h.toPr=="object"?{number:h.toPr.number??null}:null,available:Array.isArray(h.available)?h.available:null,defaults:Array.isArray(h.defaults)?h.defaults:null,prState:h.prState||null,openPr:h.openPr&&typeof h.openPr=="object"?h.openPr:null,repos:Array.isArray(h.repos)&&h.repos.length?h.repos:null,status:"open",source:k.source==="cli"||h.via==="cli"?"cli":"transcript",ts:me(k),box:k.boxId,agent:k.provider};C.set(h.offerId,v),U.set(h.offerId,v),t.push(v),v.source==="cli"&&Z(v);break}case"pr.offer.answered":{let v=U.get(h.offerId);v&&(v.status=h.action||"dismiss",v.actions=Array.isArray(h.actions)?h.actions:null,v.notify=h.notify===!0,h.existingPr&&typeof h.existingPr=="object"&&(v.existingPr={number:h.existingPr.number??null}),C.delete(h.offerId));break}case"pr.exists.offered":{if(!h.offerId)break;for(let P of B.values())P.status="stale";B.clear();let v={id:k.id,kind:"pr-exists-offer",offerId:h.offerId,srcOfferId:h.srcOfferId??null,branch:h.branch||null,base:h.base||null,pr:h.pr&&typeof h.pr=="object"?{number:h.pr.number??null,url:h.pr.url??null,title:h.pr.title??null}:null,actions:Array.isArray(h.actions)&&h.actions.length?h.actions:null,notify:h.notify===!0,status:"open",ts:me(k),box:k.boxId,agent:k.provider};B.set(h.offerId,v),T.set(h.offerId,v),t.push(v);break}case"pr.exists.answered":{let v=T.get(h.offerId);v&&(v.status=h.choice||"dismiss",B.delete(h.offerId));break}case"box.state.changed":{let v=h.change==="model"?"model-change":h.change;if(!v)break;let P=lt(k,v);if(v==="model-change"&&(P.to=h.model),v==="node-update"&&P.latest){let oe=t.findIndex(ge=>ge.kind==="event"&&ge.type==="node-update"&&ge.latest===P.latest);if(oe>=0){let ge=t[oe];t[oe]={...P,ts:ge.ts,at:ge.at,firstAt:ge.firstAt??ge.ts,updatedAt:P.ts};break}}t.push(P);break}case"track.transferred":case"track.recovered":t.push(lt(k,"track-moved"));break;case"view.state.changed":{if(h.change==="deleted"){f(`view:${h.viewId}`);break}if(h.change!=="created"||h.restarted)break;p(`view:${h.viewId}`,{id:k.id,kind:"view-card",viewId:h.viewId,name:h.name,slug:h.slug,port:h.port,origin:h.origin,ts:me(k),box:k.boxId,agent:k.provider});break}case"view.spinup.failed":{t.push({id:k.id,kind:"view-spinup-failed",name:h.name||null,reason:h.reason||"no-view",ts:me(k),box:k.boxId,agent:k.provider});break}case"mock.state.changed":{if(h.change==="picked"){t.push({id:k.id,kind:"mock-picked",mockId:h.mockId,name:h.name,group:h.group??null,version:h.version??null,siblings:h.siblings??[],ts:me(k),box:k.boxId,agent:k.provider});break}if(h.change==="deleted"){f(`mock:${h.mockId}`);break}if(h.change!=="created")break;p(`mock:${h.mockId}`,{id:k.id,kind:"mock-card",mockId:h.mockId,name:h.name,group:h.group??null,ts:me(k),box:k.boxId,agent:k.provider});break}case"flow.state.changed":{if(h.change==="deleted"){f(`flow:${h.flowId}`);break}if(h.change!=="created")break;p(`flow:${h.flowId}`,{id:k.id,kind:"flow-card",flowId:h.flowId,name:h.name,stepCount:h.stepCount??null,mockIds:h.mockIds??[],ts:me(k),box:k.boxId,agent:k.provider});break}case"runbook.state.changed":{if(h.change==="deleted"){f(`runbook:${h.runbookId}`);break}if(h.change!=="created")break;p(`runbook:${h.runbookId}`,{id:k.id,kind:"runbook-card",runbookId:h.runbookId,name:h.name,ts:me(k),box:k.boxId,agent:k.provider});break}case"ticket.linked":{t.push({id:k.id,kind:"ticket-card",provider:h.provider||"linear",key:h.key,url:h.url,title:h.title??null,linkSource:h.linkSource??null,ts:me(k),box:k.boxId,agent:k.provider});break}case"box.fullscreen.detected":{if(!h.offerId)break;for(let P of J.values())P.box===(h.box||k.boxId)&&(P.status="stale",J.delete(P.offerId));let v={id:k.id,kind:"fullscreen-offer",offerId:h.offerId,status:"open",ts:me(k),box:h.box||k.boxId,agent:h.agent||k.provider};J.set(h.offerId,v),A.set(h.offerId,v),t.push(v);break}case"box.fullscreen.answered":{let v=A.get(h.offerId);v&&(v.status=h.action==="restarted"?"restarted":h.action==="cleared"?"cleared":"dismiss",J.delete(h.offerId));break}case"ticket.move.offered":{if(!h.offerId)break;for(let P of $.values())P.key===h.key&&(P.status="stale",$.delete(P.offerId));let v={id:k.id,kind:"ticket-offer",offerId:h.offerId,provider:h.provider||"linear",key:h.key,url:h.url??null,phase:h.phase??null,from:h.from??null,to:h.to?.name??null,prNumber:h.prNumber??null,status:"open",ts:me(k),box:k.boxId,agent:k.provider};$.set(h.offerId,v),L.set(h.offerId,v),t.push(v);break}case"ticket.move.answered":{let v=L.get(h.offerId);v&&(v.status=h.action==="moved"?"moved":"dismiss",$.delete(h.offerId));break}case"ticket.state.changed":{for(let v of $.values())v.key===h.key&&v.to===h.to&&(v.status="stale",$.delete(v.offerId));if(h.mode==="offer")break;t.push(lt(k,"ticket-state"));break}case"ticket.commented":{t.push({id:k.id,kind:"ticket-comment",key:h.key,url:h.url??null,excerpt:h.excerpt??null,ts:me(k),box:k.boxId,agent:k.provider});break}case"ticket.flow.changed":t.push(lt(k,"ticket-flow"));break;case"ticket.create.offered":{if(!h.proposalId)break;for(let P of S.values())P.status="stale";S.clear();let v={id:k.id,kind:"ticket-create-offer",proposalId:h.proposalId,provider:h.provider||"linear",epic:h.epic??null,issues:Array.isArray(h.issues)?h.issues:[],team:h.team??null,needsTeam:!!h.needsTeam,linkCurrentTrack:!!h.linkCurrentTrack,status:"open",ts:me(k),box:k.boxId,agent:k.provider};S.set(h.proposalId,v),N.set(h.proposalId,v),t.push(v),Z(v);break}case"ticket.create.answered":{let v=N.get(h.proposalId);v&&(v.status=h.action==="created"?"created":"dismiss",v.createdCount=h.createdCount??null,v.failedCount=h.failedCount??null,S.delete(h.proposalId));break}case"loop.create.offered":{if(!h.proposalId)break;for(let P of H.values())P.status="stale";H.clear();let v={id:k.id,kind:"loop-create-offer",proposalId:h.proposalId,name:h.name??"",schedule:h.schedule??"",prompt:h.prompt??"",expectation:h.expectation??null,notify:h.notify??"off",assignment:h.assignment??{provider:"claude"},repo:h.repo??null,nodeId:h.nodeId??null,nodeName:h.nodeName??null,status:"open",ts:me(k),box:k.boxId,agent:k.provider};H.set(h.proposalId,v),q.set(h.proposalId,v),t.push(v),Z(v);break}case"loop.create.answered":{let v=q.get(h.proposalId);v&&(v.status=h.action==="created"?"created":"dismiss",H.delete(h.proposalId));break}case"followup.armed":{if(!h.armId)break;let v=h.replaces?Re.get(h.replaces):null;v&&v.status==="armed"&&(v.status="replaced");let P={id:k.id,kind:"followup-armed",armId:h.armId,trigger:h.trigger??"now",label:h.label??"",prompt:h.prompt??"",why:h.why??null,status:"armed",ts:me(k),box:k.boxId,agent:k.provider};Re.set(h.armId,P),P.trigger!=="now"&&t.push(P);break}case"followup.armed.cancelled":{let v=Re.get(h.armId);v&&v.status==="armed"&&(v.status="cancelled");break}case"followup.offered":{if(!h.offerId)break;for(let oe of re.values())oe.trigger===h.trigger&&(oe.status="stale",re.delete(oe.offerId));let v=Array.isArray(h.rows)?h.rows:[];for(let oe of v){let ge=oe.armId?Re.get(oe.armId):null;ge&&ge.status==="armed"&&(ge.status="offered")}let P={id:k.id,kind:"followup-offer",offerId:h.offerId,trigger:h.trigger??"now",repo:h.repo??null,context:h.context&&typeof h.context=="object"?h.context:{},rows:v.map(oe=>({followupId:oe.followupId??null,armId:oe.armId??null,label:oe.label??"",prompt:oe.prompt??null,promptPreview:oe.promptPreview??null,promptHash:oe.promptHash??null,origin:oe.origin??"operator",why:oe.why??null})),status:"open",answer:null,ts:me(k),box:k.boxId,agent:k.provider};re.set(h.offerId,P),we.set(h.offerId,P),t.push(P),P.trigger==="now"&&Z(P);break}case"followup.answered":{let v=we.get(h.offerId);v&&(v.status=h.action==="sent"?"sent":h.action==="removed"?"removed":"dismiss",v.answer={followupId:h.followupId??null,armId:h.armId??null,label:h.label??null,promoted:h.promoted??null,revived:h.revived===!0},re.delete(h.offerId));break}case"followup.create.offered":{if(!h.proposalId)break;for(let P of X.values())P.status="stale";X.clear();let v={id:k.id,kind:"followup-create-offer",proposalId:h.proposalId,label:h.label??"",prompt:h.prompt??"",trigger:h.trigger??"pr.merged",repo:h.repo??null,why:h.why??null,status:"open",created:null,ts:me(k),box:k.boxId,agent:k.provider};X.set(h.proposalId,v),Y.set(h.proposalId,v),t.push(v),Z(v);break}case"followup.create.answered":{let v=Y.get(h.proposalId);v&&(v.status=h.action==="created"?"created":"dismiss",X.delete(h.proposalId));break}case"followup.created":{let v=h.proposalId?Y.get(h.proposalId):null;v&&(v.created={followupId:h.followupId??null});break}case"loop.created":{let v=h.proposalId?q.get(h.proposalId):null;v&&(v.created={loopId:h.loopId??null,nextFireAt:Number.isFinite(Number(h.nextFireAt))?Number(h.nextFireAt):null}),t.push(lt(k,"loop-created"));break}case"loop.update.offered":case"loop.delete.offered":{if(!h.proposalId||!h.loopId)break;for(let oe of ie.values())oe.loopId===h.loopId&&(oe.status="stale",oe.staleReason="superseded",ie.delete(oe.proposalId));let v=k.type==="loop.update.offered",P={id:k.id,kind:v?"loop-update-offer":"loop-delete-offer",proposalId:h.proposalId,loopId:String(h.loopId),name:h.name??h.base?.name??"",base:h.base??null,...v?{patch:h.patch??{},changed:Array.isArray(h.changed)?h.changed:Object.keys(h.patch||{})}:{reason:h.reason??""},selfEdit:!!h.selfEdit,status:"open",staleReason:null,ts:me(k),box:k.boxId,agent:k.provider};ie.set(h.proposalId,P),ve.set(h.proposalId,P),t.push(P),Z(P);break}case"loop.update.answered":{let v=ve.get(h.proposalId);v&&(h.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=h.action==="applied"?"applied":"dismiss",ie.delete(h.proposalId));break}case"loop.delete.answered":{let v=ve.get(h.proposalId);v&&(h.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=h.action==="delete"?"deleted":h.action==="pause"?"paused":"keep",ie.delete(h.proposalId));break}case"loop.updated":{let v=h.proposalId?ve.get(h.proposalId):null;v&&(v.applied={changed:Array.isArray(h.changed)?h.changed:[],nextFireAt:Number.isFinite(Number(h.nextFireAt))?Number(h.nextFireAt):null}),t.push(lt(k,"loop-updated"));break}case"loop.deleted":t.push(lt(k,"loop-deleted"));break;case"loop.paused":t.push(lt(k,"loop-paused"));break;case"planning.change.offered":{if(!h.proposalId||!Array.isArray(h.ops)||!h.ops.length)break;for(let P of Ne.values())P.status="stale",P.staleReason="superseded",Ne.delete(P.proposalId);let v={id:k.id,kind:"planning-offer",proposalId:h.proposalId,why:h.why??"",ops:h.ops,base:h.base??{},resolved:h.resolved??{},snapped:!!h.snapped,createsMeRow:!!h.createsMeRow,status:"open",staleReason:null,applied:null,ts:me(k),box:k.boxId,agent:k.provider};Ne.set(h.proposalId,v),O.set(h.proposalId,v),t.push(v),Z(v);break}case"planning.change.answered":{let v=O.get(h.proposalId);v&&(h.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=h.action==="applied"?"applied":"dismiss",Ne.delete(h.proposalId));break}case"planning.changed":{let v=h.proposalId?O.get(h.proposalId):null;v&&(v.applied={results:Array.isArray(h.results)?h.results:[]}),t.push(lt(k,"planning-changed"));break}case"rework.cause.offered":{if(!h.sha||D.has(h.sha))break;let v={id:k.id,kind:"rework-cause-offer",sha:h.sha,subject:h.subject??"",linesReworked:Number(h.linesReworked)||0,origins:Array.isArray(h.origins)?h.origins:[],heuristic:h.heuristic??null,intent:h.intent??null,shas:Array.isArray(h.shas)?h.shas:null,pr:h.pr??null,retracts:0,status:"open",cause:null,ts:me(k),box:k.boxId,agent:k.provider};D.set(h.sha,v),t.push(v);break}case"rework.cause.answered":{let v=h.sha?D.get(h.sha):null;v&&(v.status="answered",v.cause=h.cause??null);break}case"rework.cause.retracted":{let v=h.sha?D.get(h.sha):null;v&&(v.status="open",v.cause=null,v.retracts=(v.retracts??0)+1);break}case"ticket.created":{let v={items:Array.isArray(h.items)?h.items:[],failed:Array.isArray(h.failed)?h.failed:[],team:h.team??null},P=h.proposalId?N.get(h.proposalId):null;if(P){P.created=v;break}t.push({id:k.id,kind:"ticket-created",...v,ts:me(k),box:k.boxId,agent:k.provider});break}case"error":{if(!h.kind)break;t.push(lt(k,h.kind));break}case"provider.error":t.push({...lt(k,"provider-error"),provider:k.provider,box:k.boxId,agent:k.provider});break;case"usage.cap.hit":t.push(lt(k,"usage-cap-hit"));break;case"usage.cap.warning":t.push(lt(k,"usage-cap-warning"));break;case"provider.connected":{t.push({id:k.id,kind:"event",type:"provider-connected",provider:h.provider||k.provider,ts:me(k),at:me(k),box:k.boxId,agent:k.provider});break}case"prompt.answered":{if(Ce=null,h.control||!h.question)break;let v=h.groupId||h.promptId;if(!v)break;let P=pe.get(v);P||(P={id:k.id,kind:"prompt",groupId:v,provider:k.provider,box:k.boxId,agent:k.provider,questionTotal:h.questionTotal??1,questions:[],ts:me(k)},pe.set(v,P));let oe=h.questionIndex??0,ge={index:oe,header:h.header||"",question:h.question,multiSelect:!!h.multiSelect,chosen:Array.isArray(h.chosen)?h.chosen:[]},Me=P.questions.findIndex(Ge=>Ge.index===oe&&Fe(Ge.question)===Fe(ge.question));Me>=0?P.questions[Me]=ge:P.questions.push(ge),P.questions.sort((Ge,Gt)=>Ge.index-Gt.index),P.questionTotal=Math.max(P.questionTotal,h.questionTotal??1),P.questions.length>=P.questionTotal&&(t.push(P),pe.delete(v));break}case"prompt.dismissed":{Ce=null;let v=h.groupId||h.promptId;if(!v||!h.question)break;let oe=pe.get(v)||{id:k.id,kind:"prompt",groupId:v,provider:k.provider,box:k.boxId,agent:k.provider,questionTotal:h.questionTotal??1,questions:[],ts:me(k)},ge=h.questionIndex??0;oe.questions.some(Me=>Me.index===ge&&Fe(Me.question)===Fe(h.question))||(oe.questions.push({index:ge,header:h.header||"",question:h.question,multiSelect:!!h.multiSelect,chosen:[]}),oe.questions.sort((Me,tt)=>Me.index-tt.index)),oe.answeredVia="chat",t.push(oe),pe.delete(v);break}default:break}}let bt=d.size?t.filter(k=>!k.retired):t;return FD(bt.sort((k,h)=>(k.ts??0)-(h.ts??0)))}function FD(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<=LD){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 mm(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:UD(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??Rn(e)).filter(o=>o.kind==="message");return r0(n,r)}function UD(e){let t=String(e.summary||"").trim();return t&&t!==e.command&&t!==Hs(e.command)?t:Dr(e.command,e.description||"")}function lt(e,t){let{ts:n,change:r,...o}=e.payload||{};return{id:e.id,kind:"event",type:t,...o,at:me(e),ts:me(e)}}function lx(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)+HD,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||a?.kind==="event"&&WD.has(a.type))break;s++}s>n&&t.splice(s,0,...t.splice(n,1)),n=s}return t}function ux(e){let t=[...e];for(let n=0;n<t.length;n++){let r=t[n];if(r?.kind!=="event"||!KD.has(r.type)||!r.box)continue;let o=(r.ts??0)+qD,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 lu(e){return(e||[]).filter(t=>GD.has(t?.kind)&&t.status==="open")}function dx(e){let t=new Map,n=new Map;for(let r of e||[]){if(r.type!=="pr.state.changed")continue;let o=r.payload||{};if(ix.has(o.change)&&o.number!=null)cx(t,n,o);else if(o.change==="merged"||o.change==="closed"||o.change==="lost"){let s=fm(o);if(t.has(s))t.delete(s);else if(o.number!=null)for(let a of[...t.keys()])a.endsWith(`#${o.number}`)&&t.delete(a)}}return[...t.values()]}var me,ix,fm,LD,HD,WD,qD,KD,GD,uu=G(()=>{Ws();No();Yl();$i();cu();pm();me=e=>e.payload?.ts??e.ts;ix=new Set(["opened","ci-fixed","reconciled","pushed"]),fm=e=>`${e.repo??""}#${e.number}`;LD=2*6e4;HD=12e4,WD=new Set(["archived","unarchived","opened"]);qD=2500,KD=new Set(["pr-opened","pr-merged","pr-auto-armed"]);GD=new Set(["pr-offer","pr-exists-offer","ticket-offer","ticket-create-offer","loop-create-offer","loop-update-offer","loop-delete-offer","planning-offer","fullscreen-offer","followup-create-offer"])});function XD(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 QD(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 e1(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<JD&&(o.add(c.path),n.push(c.path)),c.head&&!s.has(c.head)&&r.length<YD&&(s.add(c.head),r.push(c.head))}return{files:n,heads:r}}function hx(e,{trackName:t="this Track",now:n=null,mode:r="failover"}={}){let o=XD(e),s=QD(e),a=s?.payload?.content??null,i=s?s.payload?.ts??s.ts??null:null,c=Rn(e??[]).filter(p=>p?.kind==="message"&&typeof p.text=="string"&&p.text.trim()).slice(-zD);if(!a&&!c.length)return null;let l=[];if(l.push(`# Reconstructed resume brief \u2014 ${t}`),l.push(""),l.push(mx[r]??mx.failover),l.push(""),o.lastPush?.sha){let p=fx(n,o.lastPush.ts),f=p?` (~${p} min before the loss)`:"";l.push(`**Code state:** last pushed ref \`${o.lastPush.ref}\` @ \`${o.lastPush.sha.slice(0,12)}\`${f}`+(o.lastPush.wip?" \u2014 a bostrat WIP snapshot (full working tree incl. uncommitted edits at push time).":"."))}else r==="in-place"?l.push("**Code state:** no push recorded \u2014 the working tree in this workspace is the only copy; commit early."):l.push("**Code state:** no push was ever recorded for this Track \u2014 work since the branch's last known state stayed on the offline node.");if(l.push(""),a){let p=fx(n,i);l.push(`## Last real checkpoint (written by the previous agent${p?`, ~${p} min before this reconstruction`:""})`),l.push(""),l.push(a.trim()),l.push("")}let u=e1(e??[],i);if((u.files.length||u.heads.length)&&(l.push(`## Work since ${a?"that checkpoint":"the start of the log"} (from the event log)`),l.push(""),u.files.length&&l.push(`Files touched (most recent first): ${u.files.map(p=>`\`${p}\``).join(", ")}`),u.heads.length&&(u.files.length&&l.push(""),l.push(`Commands run (most recent first): ${u.heads.map(p=>`\`${p}\``).join(" \xB7 ")}`)),l.push("")),c.length){l.push(`## Recent conversation (last ${c.length} message${c.length===1?"":"s"})`),l.push("");for(let p of c)l.push(`**${p.role==="user"?"operator":"agent"}:** ${ZD(p.text,VD)}`),l.push("")}l.push("---"),l.push("Resume: continue the objective above from the verified repository state; ask the operator before redoing anything the log says was already done.");let d=l.join(`
154
+ `);return d.length<=px?d:`${d.slice(0,px)}
155
+
156
+ [\u2026 brief truncated]`}var zD,VD,px,JD,YD,ZD,fx,mx,wx=G(()=>{uu();zD=12,VD=2e3,px=48e3,JD=30,YD=10;ZD=(e,t)=>{let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1)}\u2026`},fx=(e,t)=>e&&t?Math.max(1,Math.round((e-t)/6e4)):null;mx={failover:"**This is a reconstruction, not a checkpoint.** The node this Track lived on went offline without a clean handoff; bostrat assembled this brief from the durable event log. Treat every claim below as a lead, not a fact \u2014 **verify the repository state first** (git status, git log, the diff against the last pushed ref) before continuing work.","in-place":"**This is a reconstruction, not a checkpoint.** The previous lead ended without writing one (out of credits, capped, or unresponsive); bostrat assembled this status from the Track's event log. You are in the SAME live workspace \u2014 uncommitted work is present locally. **Run git status and git log first** and treat every claim below as a lead, not a fact.",get recover(){return this.failover},transfer:"**This Track was MOVED to a new machine while it was alive.** The previous node checkpointed and pushed its work as part of the move; this workspace was re-created from that push (uncommitted work re-applied when possible). **Run git status and git log to confirm what carried over**, then continue the objective below."}});import t1 from"node:fs";import jr from"node:fs/promises";import Lr from"node:path";function Ax(e){let t=Io(String(e??"")),n=Buffer.byteLength(t,"utf8");return n<=gx?{content:t,bytes:n,truncated:!1}:{content:`${Buffer.from(t,"utf8").subarray(0,gx).toString("utf8").replace(/�+$/,"")}
157
+
158
+ [\u2026 truncated by bostrat at 32 KiB \u2014 full artifact in the workspace]`,bytes:n,truncated:!0}}function u1(e){let t=String(e||"").split(/\r?\n/).map(s=>s.trim()).filter(Boolean),n=[],r=[];for(let s of t)if(bx.test(s)){if(r.length>=Rx)continue;let a=l1(s.replace(bx,"").replace(/[.;,:]+$/,""),Ox,i1);a&&r.push(a)}else r.length||n.push(s);let o=n.join(" ").replace(/\s+/g," ").replace(/[:\-–—]+$/,"").trim();if(!o)throw new Error("beat file has no summary line");return o.length>yx&&(o=`${o.slice(0,yx-1).trimEnd()}\u2026`),{text:o,items:r.length>1?r:[]}}async function Mx(e,t,{timeoutMs:n=9e4}={}){let r=Lr.join(t,s1),o=Lr.join(r,a1);await jr.mkdir(r,{recursive:!0});let s=await du(o),a=await be(e);if(!a)throw new Error(`session "${e}" not found`);return await pu(e,a,c1(o)),await Lx(o,s,n),u1(await jr.readFile(o,"utf8"))}function Cx(e,t){let n=(t||"").trim();if(!n)return!1;if(e==="assistant")return n===Ex||n===$x;let r=n.replace(/^\/[a-z0-9:_-]+\s+/i,"");return r.startsWith(Tx)||n===n1||r.startsWith(_x)||r.startsWith(Ix)}function Nx(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-d1;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 Px(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 Dx(e,{windows:t=[]}={}){if(Cx(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 fu(e){return hm.get(e)||null}async function Bx(e){let t=hm.get(e);if(t&&!t.finishedAt)throw new Error("a handoff is already running for this session");let n=await be(e);if(!n)throw new Error(`session "${e}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${e}"`);let r={name:e,step:"summarize",startedAt:Date.now(),finishedAt:null,error:null,file:Lr.join(n.cwd,vx,Sx)};return hm.set(e,r),m1(r,n.cwd).catch(o=>{r.error=o?.message||String(o),r.finishedAt=Date.now()}),r}async function m1(e,t){e.step="summarize",await jx(e.name,t),e.step="clear";let n=await be(e.name);await pu(e.name,n,"/clear"),await wm(p1),e.step="resume",await pu(e.name,n,o1),e.step="done",e.finishedAt=Date.now()}async function jx(e,t,{timeoutMs:n=f1}={}){let r=Lr.join(t,vx),o=Lr.join(r,Sx);await jr.mkdir(r,{recursive:!0});let s=await du(o),a=await be(e);await ue({flow:"checkpoint",phase:"summarize-start",sessionName:e,cwd:t,file:o,beforeMtime:s}),await pu(e,a,r1(o)),await Lx(o,s,n),await ue({flow:"checkpoint",phase:"summarize-done",sessionName:e,file:o,afterMtime:await du(o)});let i=await q0(t,o,{exclude:u=>Cx(u.role,u.text)});await ue({flow:"checkpoint",phase:"seed-enriched",sessionName:e,file:o,...i});let c=/workspaces[/\\]([0-9a-f]{8})$/.exec(t||"")?.[1];if(c){await M({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 jr.readFile(o,"utf8");await M({id:c,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...Ax(u),ts:Date.now()}})}catch{}}await wf(t);let l=await h1(r,o);return c&&await Sk(c,l||o,{box:e,agent:a?.agent??null}),o}async function mu(e,{timeoutMs:t}={}){let n=await be(e);if(!n)throw new Error(`session "${e}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${e}"`);return jx(e,n.cwd,t?{timeoutMs:t}:void 0)}async function hu(e,t,{trackName:n="this Track"}={}){let r=await K({id:e,cwd:t}),o=hx(r,{trackName:n,now:Date.now(),mode:"in-place"});if(!o)return null;let s=Lr.join(t,kx);return await jr.mkdir(Lr.dirname(s),{recursive:!0}),await jr.writeFile(s,o,"utf8"),await M({id:e,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...Ax(o),reconstructed:!0,ts:Date.now()}}).catch(()=>{}),kx}async function du(e){try{return(await jr.stat(e)).mtimeMs}catch{return 0}}async function Lx(e,t,n){let r=Date.now()+n;for(;;){if(await du(e)>t)return;if(Date.now()>r)throw new Error(`timed out waiting for the handoff file to be written (${e})`);await wm(2e3)}}async function h1(e,t){try{if(!t1.existsSync(t))return null;let n=new Date().toISOString().replace(/[:.]/g,"-"),r=Lr.join(e,`${n}.md`);return await jr.copyFile(t,r),r}catch{return null}}function wm(e){return new Promise(t=>setTimeout(t,e))}function xx(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 pu(e,t,n){if(t){let o=xx(t.agent);await tr({cwd:t.cwd,sessionId:t.sessionId,sessionName:e,agent:t.agent,agentCmd:o})}let r=await be(e);if(!r)throw new Error(`session "${e}" disappeared before the orchestration prompt could be sent`);await qe(e,["Escape"],{kind:"drive-wipe"}),await wm(150),await js(e,zl,{kind:"drive-wipe"}),await ot(e,n,{kind:"orchestration-drive",...$n(r.agent,n)}),await Oi({sessionName:e,agent:r.agent,agentCmd:xx(r.agent),text:n,flow:"orchestration-drive"})}var vx,Sx,gx,Tx,Ex,_x,n1,r1,o1,Ix,$x,s1,a1,yx,Rx,Ox,i1,c1,bx,l1,d1,p1,f1,hm,kx,gm=G(()=>{ct();Ei();En();_i();rm();K0();si();fe();jl();wx();vx=".bostrat/handoff",Sx="latest.md",gx=32*1024;Tx="Checkpoint: write a work-in-progress handoff",Ex="HANDOFF WRITTEN",_x="Resume from .bostrat/handoff/latest.md",n1="/clear",r1=e=>`${Tx} 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 ${Ex} and take no further action.`,o1=`${_x}: read it, restate the Objective and the single next step in one line, then continue the work from 'Next steps'.`,Ix="Beat: write a",$x="BEAT WRITTEN",s1=".bostrat/arc",a1="beat.txt",yx=200,Rx=4,Ox=5,i1=36,c1=e=>`${Ix} 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 ${Rx} further lines, each starting with "- " and naming ONE piece in at most ${Ox} 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 ${$x} and take no further action.`,bx=/^(?:[-–—*•·]|\d+[.)])\s+/,l1=(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};d1=6e5;p1=3500,f1=3e5,hm=new Map;kx=".bostrat/handoff/status-latest.md"});function Ur(e,t,n){if(e==null)return t==="from"?-1/0:1/0;if(!wu.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 Hx(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:Ur(o.from,"from",n),toMs:Ur(o.to,"to",n)}))}return t}function bm(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 g1(e){if(!e)return null;let t=String(e).trim();return Fr[t]?t:Fx[t]?Fx[t]:Object.keys(Fr).find(r=>t.startsWith(r))||null}function y1(e){if(!e||e===Fr)return w1;let t=Ux.get(e);return t||(t=Hx(e),Ux.set(e,t)),t}function Wx(e,t,n={}){let{table:r,speed:o}=n,s=y1(r),a=r&&r!==Fr?s[e]?e:null:g1(e);if(!a)return null;let i=bm(t);if(i===null)return null;let c=s[a].find(l=>i>=l.fromMs&&i<=l.toMs)||null;return c?o==null||o==="standard"?c:o==="fast"&&c.fast?{...c.fast,fromMs:c.fromMs,toMs:c.toMs,verifiedAt:c.verifiedAt,note:c.note,speed:"fast"}:null:null}function On(e,t={},n,r){let o=Wx(e,n,r);return o?((t.input||0)*o.input+(t.output||0)*o.output+(t.cacheWrite||0)*o.cacheWrite+(t.cacheRead||0)*o.cacheRead)/1e6:0}function b1(e=Fr){let t=[];for(let[n,r]of Object.entries(e)){if(!Array.isArray(r)||r.length===0){t.push(`${n}: must be a non-empty array of windows`);continue}let o;try{o=r.map(a=>({fromMs:Ur(a.from,"from",n),toMs:Ur(a.to,"to",n)}))}catch(a){t.push(String(a.message));continue}let s=r.filter(a=>a.to==null);s.length!==1?t.push(`${n}: expected exactly 1 open-ended window (to: null), found ${s.length}`):r[r.length-1].to!=null&&t.push(`${n}: the open-ended window must be last`),r[0].from!=null&&t.push(`${n}: the first window must be open at the start (from: null)`);for(let a=0;a<o.length;a++){if(o[a].fromMs>o[a].toMs&&t.push(`${n}: window ${a} ends before it begins (${r[a].from} \u2192 ${r[a].to})`),a===0)continue;let i=o[a-1],c=o[a];c.fromMs<=i.toMs?t.push(`${n}: windows ${a-1} and ${a} overlap (${r[a-1].to} / ${r[a].from})`):c.fromMs-i.toMs>2&&t.push(`${n}: gap between windows ${a-1} and ${a} (${r[a-1].to} \u2192 ${r[a].from})`),r[a].from||t.push(`${n}: window ${a} must declare a from bound`)}for(let a of r){a.note||t.push(`${n}: every window needs a note recording what was verified and when`),wu.test(String(a.verifiedAt??""))||t.push(`${n}: every window needs a verifiedAt (YYYY-MM-DD) \u2014 the date its rates were checked against the vendor's published page`);for(let i of["input","output","cacheWrite","cacheRead"])(typeof a[i]!="number"||!Number.isFinite(a[i])||a[i]<0)&&t.push(`${n}: window ${i} must be a non-negative number, got ${JSON.stringify(a[i])}`),a.fast&&(typeof a.fast[i]!="number"||!Number.isFinite(a.fast[i])||a.fast[i]<0)&&t.push(`${n}: fast variant ${i} must be a non-negative number, got ${JSON.stringify(a.fast?.[i])}`)}}return t}function x1({now:e=Date.now(),table:t=Fr,...n}={}){let{staleDays:r,leadDays:o,confirmDays:s}={...k1,...n},a=[],i=bm(e);if(i===null)return[`pricingFreshness: unparseable now ${JSON.stringify(e)}`];for(let[c,l]of Object.entries(t)){if(!Array.isArray(l))continue;let u;try{u=l.map(d=>({...d,fromMs:Ur(d.from,"from",c),toMs:Ur(d.to,"to",c),verifiedMs:wu.test(String(d.verifiedAt??""))?Date.parse(`${d.verifiedAt}T00:00:00.000Z`):NaN}))}catch(d){a.push(String(d.message));continue}for(let d of u){if(!Number.isFinite(d.verifiedMs)){a.push(`${c}: window ${d.from??"\u2026"} \u2192 ${d.to??"now"} has no verifiedAt`);continue}let p=i>=d.fromMs&&i<=d.toMs,f=d.fromMs>i&&d.fromMs-i<=o*ym;p&&i-d.verifiedMs>r*ym&&a.push(`${c}: current rate last verified ${d.verifiedAt} (>${r}d) \u2014 re-check the vendor page and bump verifiedAt`),f&&d.fromMs-d.verifiedMs>s*ym&&a.push(`${c}: scheduled rate change on ${d.from} was last verified ${d.verifiedAt} \u2014 confirm it is still happening (vendors cancel; sonnet-5 did) and bump verifiedAt`)}}return a}function Vs({now:e=Date.now(),table:t=Fr,...n}={}){let r=bm(e)??Date.now(),o=null,s=[];for(let[i,c]of Object.entries(t))for(let l of c){let u=Ur(l.from,"from",i),d=Ur(l.to,"to",i);r>=u&&r<=d&&wu.test(String(l.verifiedAt??""))&&(!o||l.verifiedAt<o)&&(o=l.verifiedAt),u>r&&s.push({model:i,from:l.from,verifiedAt:l.verifiedAt??null})}s.sort((i,c)=>i.from<c.from?-1:1);let a=[...b1(t),...x1({now:r,table:t,...n})];return{tableVerifiedAt:o,upcomingChanges:s,problems:a,ok:a.length===0}}var Fr,Fx,wu,w1,Ux,qx,k1,ym,rr=G(()=>{Fr={"claude-opus-5":[{from:null,to:null,input:5,output:25,cacheWrite:10,cacheRead:.5,fast:{input:10,output:50,cacheWrite:20,cacheRead:1},verifiedAt:"2026-08-20",note:"GA rates; verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); fast-mode variant added 2026-08-20."}],"claude-opus-4-8":[{from:null,to:null,input:5,output:25,cacheWrite:10,cacheRead:.5,fast:{input:10,output:50,cacheWrite:20,cacheRead:1},verifiedAt:"2026-08-20",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); fast-mode variant added 2026-08-20."}],"claude-sonnet-5":[{from:null,to:null,input:2,output:10,cacheWrite:4,cacheRead:.2,verifiedAt:"2026-08-17",note:"$2/$10 is the standard price (intro pricing made permanent; the 2026-09-01 $3/$15 increase was cancelled) \u2014 verified 2026-08-17 against platform.claude.com/docs/en/about-claude/pricing."}],"claude-sonnet-4-6":[{from:null,to:null,input:3,output:15,cacheWrite:6,cacheRead:.3,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page)."}],"claude-haiku-4-5":[{from:null,to:null,input:1,output:5,cacheWrite:2,cacheRead:.1,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page)."}],"claude-fable-5":[{from:null,to:null,input:10,output:50,cacheWrite:20,cacheRead:1,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); 83% of fleet spend."}],"gpt-5.5":[{from:null,to:null,input:5,output:30,cacheWrite:5,cacheRead:.5,verifiedAt:"2026-08-17",note:"verified 2026-07-03, re-verified 2026-08-17 (developers.openai.com pricing); no cache-write premium on 5.5-and-earlier."}],"gpt-5.6-sol":[{from:null,to:"2026-08-23",input:5,output:30,cacheWrite:6.25,cacheRead:.5,verifiedAt:"2026-08-17",note:"verified 2026-07-18, re-verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL). Superseded 2026-08-24 by the vendor's promotional cut (window below)."},{from:"2026-08-24",to:null,input:4,output:20,cacheWrite:5,cacheRead:.4,verifiedAt:"2026-08-24",note:"promotional pricing verified 2026-08-24 (developers.openai.com pricing), 'at least through November 21, 2026'; cacheWrite = 1.25\xD7 input (30-min TTL)."}],"gpt-5.6-terra":[{from:null,to:"2026-08-16",input:2.5,output:15,cacheWrite:3.125,cacheRead:.25,verifiedAt:"2026-07-18",note:"as verified 2026-07-18; superseded by the 2026-08-17 sweep (0 corpus rows in this window)."},{from:"2026-08-17",to:null,input:2,output:12,cacheWrite:2.5,cacheRead:.2,verifiedAt:"2026-08-17",note:"verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL)."}],"gpt-5.6-luna":[{from:null,to:"2026-08-16",input:1,output:6,cacheWrite:1.25,cacheRead:.1,verifiedAt:"2026-07-18",note:"as verified 2026-07-18; superseded by the 2026-08-17 sweep (0 corpus rows in this window)."},{from:"2026-08-17",to:null,input:.2,output:1.2,cacheWrite:.25,cacheRead:.02,verifiedAt:"2026-08-17",note:"verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL)."}]},Fx={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"},wu=/^\d{4}-\d{2}-\d{2}$/;w1=Hx(Fr);Ux=new WeakMap;qx=(e,t,n)=>Wx(e,t,n)!==null;k1=Object.freeze({staleDays:90,leadDays:14,confirmDays:30}),ym=864e5});function v1(e){return e?{input:e.input||0,output:e.output||0,cacheRead:e.cacheRead||0,cacheWrite:e.cacheWrite??e.cacheCreation??0}:null}function Gx(e,t){t&&(e.input+=t.input,e.output+=t.output,e.cacheRead+=t.cacheRead,e.cacheCreation+=t.cacheWrite)}function Vt(e){let t=e.payload?.model||"unknown",n=v1(e.payload?.tokens),r=Number(e.payload?.usd)||0,o=e.payload?.speed||void 0,s=e.source==="vendor",a=r,i=!1;if(n&&!s){let u=On(t,n,e.ts,o?{speed:o}:void 0);u>0&&(a=u,i=Math.abs(u-r)>1e-9)}let c=n?n.input+n.output+n.cacheRead+n.cacheWrite:0,l=!a&&c>0&&!qx(t,e.ts,o?{speed:o}:void 0);return{usd:a,model:t,tokens:n,repriced:i,unpriced:l,asRecorded:r}}function Hr(e,{boxLabels:t={}}={}){let n=(e||[]).filter(p=>p.type==="cost.recorded"),r={},o={},s={},a=0,i=0,c=0,l=0,u=new Set,d=Kx();for(let p of n){let{usd:f,model:w,tokens:m,repriced:g,unpriced:y,asRecorded:x}=Vt(p);i+=x;let b=p.provider||"unknown",R=p.boxId||"unattributed";if(g&&c++,y&&(l++,u.add(w)),a+=f,Gx(d,m),r[w]||={usd:0,tokens:Kx(),events:0},r[w].usd+=f,r[w].events+=1,Gx(r[w].tokens,m),o[b]||={usd:0,events:0},o[b].usd+=f,o[b].events+=1,s[R]||={usd:0,events:0,provider:b,models:new Set,label:t[R]||R},s[R].usd+=f,s[R].events+=1,w!=="unknown"&&s[R].models.add(w),p.epoch!=null){let _=(s[R].epochs||={})[p.epoch]||={usd:0,events:0,provider:b,models:new Set};_.usd+=f,_.events+=1,_.provider=b,w!=="unknown"&&_.models.add(w)}}return{totalUsd:Js(a),asRecordedUsd:Js(i),totalTokens:d,turns:n.length,repricedTurns:c,unpricedTurns:l,unpricedModels:[...u],byModel:gu(r,p=>({...p,usd:Js(p.usd)})),byProvider:gu(o,p=>({...p,usd:Js(p.usd)})),byBox:gu(s,p=>({usd:Js(p.usd),events:p.events,provider:p.provider,label:p.label,models:[...p.models],...p.epochs?{epochs:gu(p.epochs,f=>({usd:Js(f.usd),events:f.events,provider:f.provider,models:[...f.models]}))}:{}}))}}var Kx,Js,gu,Wr=G(()=>{rr();Kx=()=>({input:0,output:0,cacheRead:0,cacheCreation:0});Js=e=>Math.round(e*1e4)/1e4,gu=(e,t)=>Object.fromEntries(Object.entries(e).map(([n,r])=>[n,t(r)]))});function S1(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 zx(e,t=[]){let n=[],r=e?.events||[],o=new Map,s=0;for(let u of t){if(u.type!=="pr.state.changed")continue;let d=u.payload||{};!d.repo||d.number==null||(d.change==="merged"?o.set(`${d.repo}#${d.number}`,d):d.change==="opened"&&s++)}if(o.size){let u=[...o.keys()].map(d=>{let[p,f]=d.split("#");return`${p.split("/").pop()}#${f}`});n.push(`Merged ${u.slice(0,4).join(", ")}${u.length>4?` +${u.length-4}`:""}`)}else s&&n.push(km(s,"PR")+" opened");let a=Object.keys(e?.subtasks||{}).length||r.filter(u=>u.type==="subtask-delegated").length;a&&n.push(km(a,"subtask"));let i=r.filter(u=>u.type==="lead-handoff"&&u.fromAgent&&u.toAgent);if(i.length){let u=i.slice(0,3).map(d=>`${d.fromAgent}\u2192${d.toAgent}`).join(", ");n.push(`${km(i.length,"handoff")} ${u}${i.length>3?"\u2026":""}`)}let c=Hr(t);c.totalUsd>=.01&&n.push(`$${c.totalUsd.toFixed(2)}`);let l=Number.isFinite(e?.archivedAt)&&Number.isFinite(e?.createdAt)?S1(e.archivedAt-e.createdAt):null;return n.length&&l&&n.push(l),n.length?n.join(" \xB7 "):null}var km,Vx=G(()=>{Wr();km=(e,t)=>`${e} ${t}${e===1?"":"s"}`});import{execFile as A1}from"node:child_process";import{promisify as T1}from"node:util";import{randomUUID as E1}from"node:crypto";async function xm(e,t){let n=Date.now()+t;for(;;){if(await er(e))return!0;if(Date.now()>n)return!1;await Di(_1)}}async function $1(e,t){let n=Jx[t]||Jx.default;n.escape&&(await qe(e,["Escape"],{kind:"swap-exit"}),await Di(150)),n.wipe&&await js(e,zl,{kind:"swap-exit"}),await Vl(e,n.text,{perCharDelayMs:90,kind:"swap-exit"});let r=$n(t).submitDelayMs||0;await Di(Math.max(r,250)),await qe(e,["Enter"],{kind:"swap-exit"})}async function Yx(e,t){try{let{stdout:n}=await Bo(ee,ne("show-environment","-t",e,t));return!String(n||"").trimStart().startsWith("-")}catch{return!1}}async function Qx(e){await Bo(ee,ne("respawn-pane","-k","-t",e))}async function vm(e,{exitTimeoutMs:t=Xx,fromAgent:n=null}={}){if(!De(e))throw new Error("invalid session name");let r=!1;if(await er(e))return{forced:r};let o=n||(await be(e))?.agent||"agent";if(await $1(e,o),!await xm(e,t)&&(r=!0,await ue({flow:"swap",phase:"respawn-forced",sessionName:e,from:o}),await Qx(e),!await xm(e,Zx)))throw new Error(`pane shell did not come back after respawn-pane in "${e}"`);return{forced:r}}async function Sm(e,t={}){if(!De(e))throw new Error("invalid session name");let n=String(t.agentCmd||"").trim();if(!n)throw new Error("agentCmd is required");let r=await be(e);if(!r)throw new Error(`session "${e}" not found`);if(!r.cwd)throw new Error(`can't resolve cwd for "${e}"`);let o=r.agent||"agent",s=t.agent||Nr(n),a=Number(t.exitTimeoutMs)||Xx;await ue({flow:"swap",phase:"start",sessionName:e,from:o,to:s,cwd:r.cwd});let{forced:i}=await vm(e,{exitTimeoutMs:a,fromAgent:o}),c=s==="claude"&&Ro(n),l=c?gl():null,u=await Yx(e,"ANTHROPIC_API_KEY"),d=!1;try{l?(await Bo(ee,ne("set-environment","-t",e,"ANTHROPIC_API_KEY",l)),d=!0):u&&(await Bo(ee,ne("set-environment","-u","-t",e,"ANTHROPIC_API_KEY")),d=!0)}catch(g){throw l?Ul(g,l):g}if(d&&!i&&(await Qx(e),!await xm(e,Zx)))throw new Error(`pane shell did not come back after env respawn in "${e}"`);let p=!!t.resumeSessionId,f=t.resumeSessionId||E1(),w=p?n:hi(n,f,e),m=p?t.pinned===!0:/(^|\s)--session-id(\s|=)/.test(w);return c&&await _r(r.cwd),s==="codex"&&await Es(r.cwd),s==="cursor"&&await _s(r.cwd),await Oo(e),await Bo(ee,ne("set-option","-t",e,"@bostrat-sid",f)),await Bo(ee,ne("set-option","-t",e,"@bostrat-agent",s)),await Di(I1),c&&mi().length&&(await Yx(e,fi)||await Bo(ee,ne("set-environment","-t",e,fi,"1")).catch(()=>{}),await ot(e,`export ${fi}=1`,{kind:"swap-env"}),await Di(150)),await ot(e,w,{kind:"swap-launch"}),await ue({flow:"swap",phase:"done",sessionName:e,from:o,to:s,sid:f,forced:i,envRespawned:d}),{name:e,cwd:r.cwd,sessionId:f,agent:s,pinned:m,forced:i,envRespawned:d,launchCmd:w}}var Bo,Di,Xx,Zx,_1,I1,Jx,ev=G(()=>{ct();Za();bl();kl();_i();En();Bo=T1(A1),Di=e=>new Promise(t=>setTimeout(t,e)),Xx=Number(process.env.BOSTRAT_SWAP_EXIT_TIMEOUT_MS)||15e3,Zx=Number(process.env.BOSTRAT_SWAP_SHELL_TIMEOUT_MS)||8e3,_1=250,I1=400,Jx={claude:{escape:!0,wipe:!0,text:"/exit"},codex:{escape:!0,wipe:!0,text:"/quit"},cursor:{escape:!0,wipe:!0,text:"/quit"},default:{escape:!1,wipe:!1,text:"exit"}}});function N1(e){if(e.type==="queue-operation"&&e.operation==="enqueue")return tv.test(String(e.content||""))?String(e.content):null;if(e.type==="attachment"){let n=e.attachment;return n?.type==="queued_command"&&n.commandMode==="task-notification"&&typeof n.prompt=="string"?n.prompt:null}let t=e.message?.content;return typeof t=="string"&&tv.test(t)?t:null}async function nv(e,t={}){return(await ov(e,t)).launches}async function rv(e,t={}){let{launches:n,done:r}=await ov(e,t);return n.filter(o=>!r.has(o.id))}async function ov(e,{maxBytes:t=2097152,limit:n=100}={}){let r;try{r=await Rt(e,t)}catch{return{launches:[],done:new Set}}let o=new Map,s=new Set,a=new Set,i=new Map;for(let l of r.split(`
159
+ `)){let u=l.trim();if(!u||u[0]!=="{")continue;let d;try{d=JSON.parse(u)}catch{continue}if(d.isSidechain)continue;let p=N1(d);if(p){let m=p.match(C1)?.[1]?.trim();m&&a.add(m);continue}let f=d.message?.content;if(!Array.isArray(f))continue;let w=d.timestamp?Date.parse(d.timestamp):null;for(let m of f)if(!(!m||typeof m!="object")){if(m.type==="tool_use"&&m.id){if(m.name==="Agent"){let g=m.input||{};o.set(m.id,{id:m.id,kind:"agent",name:String(g.description||"").trim()||null,detail:String(g.subagent_type||"").trim()||null,ts:w,proven:!1})}else if(m.name==="Bash"){let g=String(m.input?.command||"").trim(),y={id:m.id,kind:"command",name:String(m.input?.description||"").trim()||(g?Hs(g):null),detail:g?Hs(g):null,ts:w,proven:m.input?.run_in_background===!0};y.proven?o.set(m.id,y):i.set(m.id,y)}}else if(m.type==="tool_result"&&m.tool_use_id){let g=P1(m.content);if(R1.test(g)&&s.add(m.tool_use_id),g.match(O1)){let x=i.get(m.tool_use_id);x&&(i.delete(m.tool_use_id),x.proven=!0,x.outputFile=g.match(M1)?.[1]?.replace(/\.$/,"")||null,o.set(x.id,x))}}}}let c=[];for(let l of o.values()){if(!l.proven&&!s.has(l.id))continue;let{proven:u,...d}=l;c.push(d)}return{launches:c.slice(-n),done:a}}var R1,O1,M1,tv,C1,P1,sv=G(()=>{cn();Ws();R1=/^Async (?:agent|task) launched/i,O1=/^Command did not complete within its [^\n]*?moved to the background \(ID: ([^)]+)\)/i,M1=/Output is being written to:\s*(\S+)/i,tv=/^\s*<task-notification>/i,C1=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i;P1=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 qr(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 D1(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 av(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:ln(`read ${qr(r,n)}${o?` (lines ${o}\u2013${s??"end"})`:""}`,140),description:o?`Read lines ${o}\u2013${s??"end"} of ${Ys(r)}`:`Read ${Ys(r)}`}}case"Grep":{let r=t?.pattern;if(!r)return null;let o=t?.path?qr(t.path,n):null,s=t?.glob?` --glob ${Am(t.glob)}`:"",a=ln(String(r),40);return{command:ln(`grep ${Am(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?qr(t.target_directory,n):null;return{command:ln(`glob ${Am(r)}${o&&o!=="."?` ${o}`:""}`,140),description:`Find files matching \u201C${ln(String(r),40)}\u201D`}}case"StrReplace":return t?.path?{command:ln(`edit ${qr(t.path,n)}`,140),description:`Edit ${Ys(t.path)}`}:null;case"Write":return t?.path?{command:ln(`write ${qr(t.path,n)}`,140),description:`Write ${Ys(t.path)}`}:null;case"Delete":return t?.path?{command:ln(`delete ${qr(t.path,n)}`,140),description:`Delete ${Ys(t.path)}`}:null;case"ReadLints":{let o=(Array.isArray(t?.paths)?t.paths:[]).map(s=>qr(s,n)).filter(Boolean);return{command:ln(o.length?`lints ${o.join(" ")}`:"lints",140),description:"Check lints"}}case"ApplyPatch":{let r=D1(t);if(!r.length)return null;let o=r.length>1?` (+${r.length-1} more)`:"";return{command:ln(`apply_patch ${qr(r[0],n)}${o}`,140),description:r.length>1?`Patch ${r.length} files`:`Patch ${Ys(r[0])}`}}case"Await":{let r=t?.shell_id??t?.task_id;return{command:ln(`await ${r??"background output"}`,140),description:"Wait for a background command"}}default:return null}}var yu,ln,Ys,Am,iv=G(()=>{yu=new Set(["Shell","Read","Grep","Glob","StrReplace","Write","ReadLints","Delete","ApplyPatch","Await"]),ln=(e,t=88)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,Ys=e=>String(e).replace(/\/+$/,"").split("/").pop()||String(e);Am=e=>`"${String(e).replace(/"/g,'\\"')}"`});import Bi from"node:fs";import B1 from"node:fs/promises";import jo from"node:path";import j1 from"node:os";import L1 from"node:crypto";import F1 from"node:zlib";function uv(e){let t=L1.createHash("md5").update(String(e)).digest("hex");return jo.join(U1,t)}function dv(e){try{let t=JSON.parse(Bi.readFileSync(jo.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 H1(e){let t=uv(e),n;try{n=Bi.readdirSync(t,{withFileTypes:!0}).filter(o=>o.isDirectory())}catch{return null}let r=null;for(let o of n){let s=jo.join(t,o.name),a=jo.join(s,"store.db");if(!Bi.existsSync(a))continue;let i=dv(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 bu(e,t){if(!e)return null;if(t){let n=jo.join(uv(e),t),r=jo.join(n,"store.db");if(Bi.existsSync(r))return{id:t,dir:n,store:r,...dv(n)||{createdAtMs:null,updatedAtMs:null}}}return H1(e)}function cv(e,t){let n=e.prepare("SELECT data FROM blobs WHERE id = ?").get(t);return n?Buffer.from(n.data):null}function W1(e){if(!e)return null;let t=e;if(t.length>1&&t[0]===31&&t[1]===139)try{t=F1.gunzipSync(t)}catch{}try{return JSON.parse(t.toString("utf8"))}catch{return null}}function q1(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 K1(e,t){if(!Array.isArray(e))return[];let n=[];for(let r of e){if(!r||r.type!=="tool-call"||!yu.has(r.toolName))continue;let o=av(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 Tm(e,t){if(!lv)return Xs;let{DatabaseSync:n}=lv,r;try{r=new n(e,{readOnly:!0})}catch{return Xs}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 Xs;let s;try{s=JSON.parse(Buffer.from(String(o.value),"hex").toString("utf8"))}catch{return Xs}let a=s.lastUsedModel||null,i=s.latestRootBlobId?cv(r,s.latestRootBlobId):null;if(!i)return{...Xs,model:a};let c=[],l=[],u=[],d=null,p=[];for(let f of q1(i)){let w=W1(cv(r,f));if(!w)continue;let m=w.providerOptions?.cursor;if(m?.requestId&&p.push(m.requestId),m?.modelProviderMessageId&&p.push(m.modelProviderMessageId),w.role!=="assistant")continue;if(Array.isArray(w.content))for(let x of w.content){let b=x?.providerOptions?.cursor?.modelName;b&&(d=b)}l.push(...K1(w.content,t).map((x,b)=>({...x,id:x.id||`${f}:${b}`}))),u.push(...z1(w.content));let g=G1(w.content);if(!g)continue;let y=[...new Set(u)];u=[],c.push({id:f,text:g,tools:y.length?y:void 0,commands:l,model:d}),l=[]}return{turns:c,trailingCommands:l,model:a,requestIds:p}}catch{return Xs}finally{try{r.close()}catch{}}}function pv(e,t){let n=e.updatedAtMs;if(!n)try{n=Math.round(Bi.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 fv(e,t,{limit:n=80}={}){let r=bu(e,t);if(!r)return[];let{turns:o,model:s}=await Tm(r.store,e);if(!o.length)return[];let a=o.slice(-n),{tsAt:i}=pv(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 mv(e,t){let n=bu(e,t);if(!n)return null;let{turns:r,requestIds:o,model:s}=await Tm(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 hv(e,t,{limit:n=80}={}){let r=bu(e,t);if(!r)return[];let{turns:o,trailingCommands:s}=await Tm(r.store,e);if(!o.length&&!s.length)return[];let a=o.slice(-n),{end:i,tsAt:c}=pv(r,a.length||1),l=[];a.forEach((u,d)=>{for(let p of u.commands)l.push({...p,summary:Dr(p.command,p.description),ts:c(d)})});for(let u of s)l.push({...u,summary:Dr(u.command,u.description),ts:i+1});return l}async function wv(e,t){let n=bu(e,t);if(!n)return null;if(n.updatedAtMs)return n.updatedAtMs;try{return Math.round((await B1.stat(n.store)).mtimeMs)}catch{return null}}var U1,G1,z1,lv,Xs,Em=G(()=>{Ws();iv();U1=process.env.BOSTRAT_CURSOR_CHATS||jo.join(j1.homedir(),".cursor","chats");G1=e=>typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&t.type==="text"&&typeof t.text=="string").map(t=>t.text).join(`
160
+ `).trim():"",z1=e=>Array.isArray(e)?e.filter(t=>t&&t.type==="tool-call"&&t.toolName).map(t=>t.toolName):[],lv=process.getBuiltinModule?.("node:sqlite"),Xs={turns:[],trailingCommands:[],model:null,requestIds:[]}});import V1 from"node:fs/promises";function Rm(e){return gv.set(e.agent,e),e}function Kr(e){return gv.get(e)||J1}async function Om(e,t={}){return(await Kr(e.agent).readMessages(e,t)).map(ku(e))}async function yv(e,t={}){return(await Kr(e.agent).readCommands(e,t)).map(ku(e))}async function bv(e,t={}){return(await Kr(e.agent).readJobs(e,t)).map(ku(e))}async function kv(e,t={}){return(await Kr(e.agent).readOpenJobs(e,t)).map(ku(e))}var Zs,_m,Im,$m,J1,gv,ku,Mm=G(()=>{cn();Xl();Ws();sv();Em();No();Zs=class{constructor(t,n=new Set){this.agent=t,this.cliTools=n}async readMessages(){return[]}async readCommands(){return[]}async readJobs(){return[]}async readOpenJobs(){return[]}async updatedAt(){return null}},_m=class extends Zs{transcript(t){return!t?.cwd||!t?.sessionId?null:an(t.cwd,t.sessionId)}async readMessages(t,n){let r=this.transcript(t);return r?qf(r,n):[]}async readCommands(t,n){let r=this.transcript(t);return r?n0(r,n):[]}async readJobs(t,n){let r=this.transcript(t);return r?nv(r,n):[]}async readOpenJobs(t,n){let r=this.transcript(t);return r?rv(r,n):[]}async updatedAt(t){let n=this.transcript(t);if(!n)return null;try{return Math.round((await V1.stat(n)).mtimeMs)}catch{return null}}},Im=class extends Zs{async readMessages(t,n){return fv(t.cwd,t.sessionId,n)}async readCommands(t,n){return hv(t.cwd,t.sessionId,n)}async updatedAt(t){return wv(t.cwd,t.sessionId)}},$m=class extends Zs{sessionId(t){return t?.pinned?t.sessionId:null}async readMessages(t,n){return a0(t.cwd,this.sessionId(t),n)}async readCommands(t,n){return i0(t.cwd,this.sessionId(t),n)}async updatedAt(t){return c0(t.cwd,this.sessionId(t))}},J1=new Zs("unknown"),gv=new Map;Rm(new _m("claude",Lf));Rm(new Im("cursor",yu));Rm(new $m("codex",vi));ku=e=>t=>({...t,box:e.name,agent:e.agent,boxRole:e.role})});function zr(e){let t=e.search(Dm);return(t>=0?e.slice(0,t):e).trim()}function Y1(e){if(!e)return"";let t=e.replace(/[│┌└├─┘┤┬┴┼─✂].*$/,"").trim();return!t||/hidden|\d+\s+lines?/i.test(t)?"":t}function X1(e){let t=String(e).trim();return!!(!t||Gr.test(e)||Dm.test(t)||/hidden|\d+\s+lines?/i.test(t)||/notespress|press n to add/i.test(t)||/^\s*notes?\s*$/i.test(t))}function Z1(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=Q1(n,t);return n.forEach((a,i)=>{a.current=i===s}),{tabs:n,questionIndex:s,questionTotal:n.length,currentTabLabel:n[s].label}}function Q1(e,t){let n=String(t).toLowerCase(),r=e.findIndex(c=>!c.answered),o=r>=0?r:e.length-1;if(!n)return o;let s=e.map(c=>{let l=c.label.toLowerCase(),u=l.split(/\s+/).filter(p=>p.length>3&&n.includes(p)).length;if(u)return u;let d=l.slice(0,8).trim();return d.length>=4&&n.includes(d)?1:0}),a=Math.max(...s);if(a===0||s[o]===a)return o;let i=s.flatMap((c,l)=>c===a?[l]:[]);return i.length===1?i[0]:o}function xv(e){return e.replace(/[←→✔☐☒●▶]/g," ").replace(/\bSubmit\b/g," ").replace(/\s+/g," ").trim()}function eB(e,t=""){let n=String(e);if(!Sv.test(n))return null;let r=n.replace(/\r/g,"").split(`
161
+ `),o=-1;for(let u=r.length-1;u>=0;u--)if(/^\s*Switch model\?\s*$/.test(r[u])){o=u;break}if(o<0)return null;let s=[],a=[];for(let u=o+1;u<r.length;u++){let d=r[u].match(Lo);if(d)s.push({cursor:!!d[1],label:d[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let p=r[u].trim();p&&!Gr.test(r[u])&&a.push(p)}}if(s.length<2)return null;let i=s.map(u=>({label:zr(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 nB(e,t=""){let n=String(e).replace(/\r/g,"").split(`
162
+ `),r=n.length-1;for(;r>=0&&n[r].trim()==="";)r--;if(r<0||!Av.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(Lo);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&&!(tB.test(n[c])||Gr.test(n[c]));c--){let l=n[c].trim();l&&a.unshift(l)}let i=s.map(c=>({label:zr(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 rB(e,t=""){let n=String(e);if(!/ready to submit your answers/i.test(n))return null;let r=n.replace(/\r/g,"").split(`
163
+ `),o=[];for(let c=0;c<r.length;c++){let l=r[c].match(Lo);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 sB(e,t=""){let n=String(e);if(!Cm.test(n))return null;let r=n.replace(/\r/g,"").split(`
164
+ `),o=-1;for(let u=r.length-1;u>=0;u--)if(oB.test(r[u])){o=u;break}if(o<0)return null;let s=[],a=[r[o].trim()];for(let u=o+1;u<r.length;u++){let d=r[u].match(Lo);if(d)s.push({cursor:!!d[1],label:d[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let p=r[u].trim();p&&!Gr.test(r[u])&&a.push(p)}}if(s.length<2||!s.some(u=>Cm.test(u.label)))return null;let i=s.map(u=>({label:zr(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 Bm(e){let t=[];for(let r=0;r<e.length;r++){let o=e[r].match(Lo);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 aB(e,t=""){let n=String(e);if(!Tv.test(n)||!Ev.test(n)||Fo.test(n))return null;let r=n.replace(/\r/g,"").split(`
165
+ `),o=Bm(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:zr(s.label),description:""}))}]}:null}function iB(e,t=""){let n=String(e);if(!_v.test(n)||Fo.test(n))return null;let r=n.replace(/\r/g,"").split(`
166
+ `),o=Bm(r);if(!o)return null;let s=o.map(a=>{let[i,...c]=a.label.split("\xB7");return{label:zr(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 lB(e,t){let n=e[t].trim();for(let r=t+1;r<e.length;r++){let o=e[r].trim();if(!o||!cB.test(o)||jm.test(e[r]))break;n+=o}return n}function uB(e,t=""){let n=String(e);if(!jm.test(n)||Fo.test(n))return null;let r=n.replace(/\r/g,"").split(`
167
+ `),o="";for(let s=0;s<r.length;s++)if(/^\s*https:\/\//.test(r[s])){o=lB(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 pB(e,t=""){let n=String(e);if(!Nm.test(n)||!dB.test(n)||Fo.test(n))return null;let s=([...n.replace(/\r/g,"").split(`
168
+ `)].reverse().find(a=>Nm.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 fB(e,t=""){let n=String(e);if(!Iv.test(n)||Fo.test(n))return null;let r=n.replace(/\r/g,"").split(`
169
+ `),o=Bm(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:zr(s.label),description:""}))}]}:null}function mB(e,t=""){let n=String(e);if(Fo.test(n))return null;let r=n.replace(/\r/g,"").split(`
170
+ `),o=-1;for(let l=r.length-1;l>=0;l--)if(r[l].trim()!==""){o=l;break}if(o<0)return null;let s=r[o].match($v);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(Gr.test(r[l])||Dm.test(u))break;a.unshift(u)}let i=s[1].trim();i&&a.push(i);let c=a.join(" ")||"Claude Code is waiting for you to continue.";return{provider:"claude",box:t,multiSelect:!1,cursorIndex:0,setup:"continue",promptId:`claude:setup:continue:${c}`.slice(0,200),questions:[{question:c,header:"Continue",multiSelect:!1,options:[{label:"Continue",description:""}]}]}}function hB(e){let t=-1;for(let r=e.length-1;r>=0;r--)if(Pm.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 wB(e,t){let n=e.find(s=>/^type something\b/i.test(s.label));if(n)return n;if(e.length<2)return null;let r=e[e.length-1];if(xu.test(r.label))return null;let o=null;for(let s=r.line+1;s<Math.min(t.length,r.line+3);s++){let a=t[s].replace(/^\s*❯/,"").trim();if(a){o=a;break}}return o&&(Gr.test(o)||/^submit\b/i.test(o))?r:null}function gB(e,t=""){let n=String(e);if(!vv.test(n)||!Pm.test(n))return null;let r=n.replace(/\r/g,"").split(`
171
+ `),o=hB(r);if(!o)return null;let{headerLine:s,chatLine:a,optStart:i,optEnd:c}=o,l=[],u=-1;for(let $=i;$<c;$++){let L=r[$].match(Lo);L&&(u<0&&(u=$),l.push({line:$,cursor:!!L[1],checked:L[3]!=null&&L[3]!==" ",hasCheckbox:L[3]!=null,label:L[4].trim(),desc:""}))}if(!l.length)return null;for(let $ of l)for(let L=$.line+1;L<Math.min(r.length,$.line+4)&&!(Lo.test(r[L])||Gr.test(r[L]));L++){let J=r[L].trim();if(!(!J||X1(r[L])||xu.test(J))){$.desc=Y1(J);break}}let d=wB(l,r),p=l.filter($=>$!==d&&!xu.test($.label));if(!p.length)return null;let f=p.some($=>$.hasCheckbox),w=d?.cursor?p.length:Math.max(0,p.findIndex($=>$.cursor)),m=d&&!xu.test(d.label)?zr(d.label):"",g=s>=0?s+1:0,y=[];for(let $=g;$<u;$++){let L=r[$].trim();L&&!Gr.test(r[$])&&!/[☐☒]/.test(r[$])&&y.push(L)}let x=y.join(" ")||(s>=0?xv(r[s]):"")||"The agent is asking a question",b=s>=0?Z1(r[s],x):null,R=b?.currentTabLabel||(s>=0?xv(r[s]):""),_=p.map($=>({label:zr($.label),description:$.desc})),C=_.map($=>$.label).join("|"),B=`claude:${b?`q${b.questionIndex+1}/${b.questionTotal}`:"q1/1"}:${R}:${x}:${C}`.slice(0,240),T=b?`claude:ask:${b.tabs.map($=>$.label).join("|")}`.slice(0,240):B;return{provider:"claude",box:t,multiSelect:f,cursorIndex:w,promptId:B,groupId:T,...d?{custom:!0,customIndex:p.length,customText:m}:{},dismissable:!0,...b?{questionIndex:b.questionIndex,questionTotal:b.questionTotal,currentTabLabel:b.currentTabLabel,tabs:b.tabs}:{},questions:[{question:x,header:R,multiSelect:f,options:_}]}}function Vr(e,t){let n=String(t||"");return n?e==="claude"?vv.test(n)&&Pm.test(n)||Sv.test(n)||Cm.test(n)||Av.test(n.trimEnd().split(`
172
+ `).pop()||"")?!0:Fo.test(n)?!1:Tv.test(n)&&Ev.test(n)||_v.test(n)||jm.test(n)||Nm.test(n)||Iv.test(n)||$v.test(n.trimEnd().split(`
173
+ `).pop()||""):e==="codex"&&/Sign in with ChatGPT|one-time code|Paste or type your API key|link to authenticate|Successfully logged in\.[\s\S]*Press Enter to continue\./i.test(n)?!0:e==="cursor"||e==="codex"?/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i.test(n):!1:!1}function Mn(e,t){return!e||!t?null:e.agent==="claude"?rB(t,e.name)||gB(t,e.name)||eB(t,e.name)||sB(t,e.name)||pB(t,e.name)||uB(t,e.name)||iB(t,e.name)||aB(t,e.name)||fB(t,e.name)||mB(t,e.name)||nB(t,e.name):e.agent==="cursor"||e.agent==="codex"?S0(e.agent,t,e.name):null}async function Lm(e){if(!e)return null;let t=await sn(e.name).catch(()=>"");return Mn(e,t)}function Fm(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 Rv(e,t,n=""){let r=typeof n=="string"?n.trim():"";if(!r||!e?.custom)return{pre:Fm(e,t).map(d=>({key:d})),text:"",post:[]};let o=Array.isArray(t?.[0])?t[0].filter(d=>Number.isInteger(d)&&d>=0):[],s=Number.isInteger(e.customIndex)?e.customIndex:e.questions?.[0]?.options?.length??0,a=Number.isInteger(e.cursorIndex)?e.cursorIndex:0,i=(d,p)=>{let f=p-d;return Array.from({length:Math.abs(f)},()=>({key:f>0?"Down":"Up"}))},c=[],l=a,u=typeof e.customText=="string"?e.customText.length:0;if(u>0&&a===s&&c.push(...Array.from({length:u+2},()=>({key:"BSpace"}))),e.multiSelect){for(let d of[...o].sort((p,f)=>p-f))c.push(...i(l,d),{key:"Enter"}),l=d;return c.push(...i(l,s)),{pre:c,text:r,post:[{key:"Down"},{key:"Enter"}]}}return c.push(...i(l,s)),{pre:c,text:r,post:[{key:"Enter"}]}}function Ov(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 vv,Pm,Lo,xu,Gr,Dm,Sv,Av,tB,Cm,oB,Fo,Tv,Ev,_v,jm,cB,Nm,dB,Iv,$v,Um=G(()=>{ct();Ql();vv=/to navigate\b.*\bEsc to cancel|Enter to select\b/,Pm=/Chat about this/i,Lo=/^\s*(❯)?\s*(\d+)\.\s+(?:\[([ xX✔])\]\s+)?(.+?)\s*$/,xu=/^(type something|chat about this|submit)\b/i,Gr=/^[─—-]{6,}\s*$/,Dm=/[\u2500-\u257F\u2550-\u256F┌┐└┘├┤│┬┴┼─✂]/;Sv=/^\s*Switch model\?\s*$/m;Av=/^\s*Enter to confirm\s*·\s*Esc to cancel\s*$/,tB=/^\s*[─—▔-]{6,}\s*$/;Cm=/Resume from summary/i,oB=/^\s*This session is\b/;Fo=/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/;Tv=/Choose the text style that looks best with your terminal/,Ev=/Let's get started\./;_v=/Select login method:/;jm=/Paste code here if prompted/,cB=/^[A-Za-z0-9%&=+._~#?/:\-]+$/;Nm=/OAuth error:/,dB=/Press Enter to retry\./;Iv=/Quick safety check: Is this a project you created or one you trust/;$v=/^(.{0,60}?)Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/});function vu(e,t,n){if(!e||!t)return null;for(let r of yB)if(r.provider===e.agent)try{if(r.match(t,n))return r}catch{}return null}function kB(e){let t=Hm.get(e);return t||(t={sentAt:[],last:0,emitted:new Set},Hm.set(e,t)),t}function Nv(e,t,n=Date.now()){let r=kB(e);if(r.sentAt=r.sentAt.filter(s=>n-s<Cv),r.sentAt.length>=Mv)return{action:"give-up"};if(n-r.last<bB)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 Pv(e,t=Date.now()){let n=Hm.get(e);return n?n.sentAt.filter(r=>t-r<Cv).length>=Mv:!1}var yB,bB,Mv,Cv,Hm,Wm=G(()=>{yB=[{provider:"claude",id:"fullscreen-upsell",match(e,t){let n=e?.questions?.[0],r=(n?.options||[]).map(s=>String(s.label||"").trim());if(r.length!==2||!/^Yes, try it$/.test(r[0])||!/^Not now$/.test(r[1]))return!1;let o=`${n?.question||""}
174
+ ${String(t||"")}`;return/Try the new fullscreen renderer|Flicker-free output/i.test(o)},keys:["Escape"]}];bB=5e3,Mv=5,Cv=3600*1e3,Hm=new Map});function Qs(e){return typeof e=="string"?e.trim():""}var Dv=G(()=>{});import{execFile as xB}from"node:child_process";import{promisify as vB}from"node:util";async function Ve(e,t,{input:n}={}){let r=Km("git",["-C",e,...t],{maxBuffer:Bv});return n!==void 0&&r.child.stdin&&(r.child.stdin.on("error",()=>{}),r.child.stdin.end(n)),r}async function ea(e){if(!e)return!1;try{let{stdout:t}=await Ve(e,["rev-parse","--is-inside-work-tree"]);return t.trim()==="true"}catch{return!1}}async function jv(e){let{stdout:t}=await Ve(e,["rev-parse","--show-toplevel"]);return t.trim()}async function SB(e){try{return await Ve(e,["rev-parse","--verify","HEAD"]),!0}catch{return!1}}async function ta(e,t="bostrat: subtask snapshot"){let{stdout:n}=await Ve(e,["rev-parse","--absolute-git-dir"]),r=`${n.trim()}/bostrat-snapshot-index`,o={...process.env,GIT_INDEX_FILE:r},s=(a,i)=>Km("git",["-C",e,...a],{maxBuffer:Bv,env:o,...i});try{let a=await SB(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 Km("rm",["-f",r])}catch{}}}async function Gm(e,t,{trailers:n=[]}={}){let{stdout:r}=await Ve(e,["status","--porcelain"]);return r.trim()?(await Ve(e,["add","-A"]),await Ve(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","-m",t,...n.flatMap(o=>["--trailer",o])]),!0):!1}async function Uo(e,{ignorePlumbing:t=!1}={}){let{stdout:n}=await Ve(e,["status","--porcelain"]),r=n.split(`
175
+ `).filter(Boolean);return t&&(r=r.filter(o=>{let s=o.slice(3);return!(s===".bostrat"||s===".bostrat/"||s.startsWith(".bostrat/")||o.startsWith("??")&&(s==="AGENTS.md"||s==="CLAUDE.md"))})),r.length>0}async function Ho(e,t){if(!t)return 0;try{let{stdout:n}=await Ve(e,["rev-list","--count",`${t}..HEAD`]);return Number(n.trim())||0}catch{return 0}}async function Wo(e,t,n,r){return await Ve(e,["worktree","add","--no-track","-b",n,t,r]),t}async function zm(e,t){try{return await Ve(e,["rev-parse","--verify","--quiet",`refs/heads/${t}`]),!0}catch{return!1}}async function ji(e,t,n){return await Ve(e,["worktree","add","--end-of-options",t,n]),t}async function qo(e){if(process.env.BOSTRAT_TRACK_BASE_REF)return process.env.BOSTRAT_TRACK_BASE_REF;try{let{stdout:t}=await Ve(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 Ve(e,["rev-parse","--verify","--quiet",t]),n}catch{}return"HEAD"}async function Vm(e){await Ve(e,["init","-q"]),await Ve(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","--allow-empty","-qm","bostrat: track workspace"])}async function xt(e,t){try{await Ve(e,["worktree","remove","--force",t])}catch{try{await Ve(e,["worktree","prune"])}catch{}}}function AB(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 Jm(e,t){return!t||!t.length?e:[...e,"--",".",...t.map(n=>`:(exclude)${n}`)]}async function Ym(e,t,n,r){let{stdout:o}=await Ve(e,Jm(["diff","--shortstat",t,n],r));return AB(o)}async function Xm(e,t,n,r){let{stdout:o}=await Ve(e,Jm(["diff","--name-only",t,n],r));return o.split(`
176
+ `).map(s=>s.trim()).filter(Boolean)}async function Zm(e,t,n,r){let{stdout:o}=await Ve(e,Jm(["diff","--binary",t,n],r));if(!o.trim())return{applied:!0,empty:!0,conflicts:[]};if((await qm(e,o,["--whitespace=nowarn"])).ok)return{applied:!0,empty:!1,conflicts:[]};let s=await qm(e,o,["--3way","--whitespace=nowarn"]),a=await TB(e);return a.length>0?{applied:!1,empty:!1,conflicts:a}:s.ok?{applied:!0,empty:!1,conflicts:[]}:(await qm(e,o,["--reject","--whitespace=nowarn"]),{applied:!1,empty:!1,conflicts:[`patch did not apply cleanly: ${s.err}`]})}async function qm(e,t,n){try{return await Ve(e,["apply",...n,"-"],{input:t}),{ok:!0}}catch(r){return{ok:!1,err:r?.stderr?.trim()||r?.message||String(r)}}}async function TB(e){try{let{stdout:t}=await Ve(e,["diff","--name-only","--diff-filter=U"]);return t.split(`
177
+ `).map(n=>n.trim()).filter(Boolean)}catch{return[]}}var Km,Bv,Su=G(()=>{Km=vB(xB),Bv=64*1024*1024});function Au(e,{at:t=Date.now(),reason:n="node-transfer"}={}){let r=!1;for(let o of e?.boxes||[]){if(!o||typeof o!="object")continue;!EB.has(o.state)&&o.state!=="stopped"&&(o.state="stopped",r=!0);let s=Array.isArray(o.epochs)?o.epochs:[],a=s[s.length-1];a&&typeof a=="object"&&a.endedAt==null&&(a.endedAt=t,a.endReason==null&&(a.endReason=n),r=!0)}return r}var je,EB,Jt=G(()=>{je=e=>!!(e&&(e.archivedAt||e.transferredTo)),EB=new Set(["merged","conflict","canceled","failed","handed-off"])});import Qm from"node:fs/promises";import Fv from"node:path";import _B from"node:os";function qv(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(t.getDate()-(t.getDay()+6)%7),t.getTime()}function Kv(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(1),t.getTime()}function Gv(e){let t=new Date(qv(e));return t.setDate(t.getDate()+7),t.getTime()}function zv(e){let t=new Date(Kv(e));return t.setMonth(t.getMonth()+1),t.getTime()}function Eu(e=Date.now()){for(let[t,n]of Object.entries(na)){let r=n.startOf(e);if(r!==or[t]){or[t]=r;for(let o of Ko.values())o[t]=0;for(let o of ra)o.includes(`:${t}:`)&&!o.endsWith(`:${r}`)&&ra.delete(o)}}}function Vv(e,t){let n=un?.caps?.[e]?.[na[t].capKey];return Number.isFinite(n)&&n>0?n:null}function Jr(e,t=Date.now()){if(!e||!th||!un?.caps)return null;Eu(t);let n=Ko.get(e);for(let r of Object.keys(na)){let o=Vv(e,r);if(o==null)continue;let s=n?.[r]||0;if(s>=o)return{provider:e,window:r,limitUsd:o,spentUsd:Tu(s),resetsAt:na[r].nextStart(t)}}return null}function Jv(e,t){let n=`hit:${e}:${t.provider}:${t.window}:${or[t.window]}`;return ra.has(n)?!1:(ra.add(n),!0)}function Lv(e,t,n,r=Date.now()){if(!e||!t)return;Eu(r);let o=IB(e);for(let[s,a]of Object.entries(na))n>=or[s]&&n<a.nextStart(r)&&(o[s]+=t)}async function $B(e,t,n=Date.now()){if(!un?.caps||!eh)return;let r=Ko.get(e);if(r)for(let[o,s]of Object.entries(na)){let a=Vv(e,o);if(a==null)continue;let i=r[o]||0;if(i<a*Wv||i>=a)continue;let c=`warn:${e}:${o}:${or[o]}`;if(!ra.has(c)){ra.add(c);try{let l=await eh(t);if(!l)continue;await M(l,{type:"usage.cap.warning",actor:"system",provider:e,payload:{provider:e,window:o,limitUsd:a,spentUsd:Tu(i),pct:Math.round(i/a*100),resetsAt:s.nextStart(n)}})}catch{}}}}function Yv(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 _u(e,{source:t="local",updatedAt:n=Date.now()}={}){un={caps:Yv(e),updatedAt:n,source:t};try{await Qm.mkdir(Uv,{recursive:!0}),await Qm.writeFile(Hv(),JSON.stringify(un,null,2))}catch{}return Li()}function Li(e=Date.now()){Eu(e);let t=new Set([...Ko.keys(),...Object.keys(un?.caps||{})]),n={};for(let r of t){let o=Ko.get(r);n[r]={weeklyUsd:Tu(o?.weekly||0),monthlyUsd:Tu(o?.monthly||0)}}return{caps:un?.caps||{},configured:!!un,seeded:th,updatedAt:un?.updatedAt??null,spent:n,windows:{weekly:{start:or.weekly,resetsAt:Gv(e)},monthly:{start:or.monthly,resetsAt:zv(e)}},warnPct:Wv}}async function Xv({listTracks:e,getTrack:t}={}){eh=t||null,Eu();try{let o=JSON.parse(await Qm.readFile(Hv(),"utf8"));un={caps:Yv(o?.caps),updatedAt:o?.updatedAt??null,source:o?.source??"file"}}catch{un=null}let n=Date.now();Je.on("event",o=>{if(o?.type!=="cost.recorded")return;let{usd:s}=Vt(o);Lv(o.provider||"unknown",s,o.ts??Date.now()),$B(o.provider||"unknown",o.trackId).catch(()=>{})});let r=Math.min(or.weekly,or.monthly);for(let o of await e?.()||[]){let s;try{s=await K(o)}catch{continue}for(let a of s){if(a.type!=="cost.recorded")continue;let i=a.ts??0;i<r||i>=n||Lv(a.provider||"unknown",Vt(a).usd,i,n)}}return th=!0,Li()}var Uv,Hv,Wv,na,un,th,or,Ko,ra,eh,IB,Tu,Iu=G(()=>{fe();Wr();Uv=process.env.BOSTRAT_STATE_DIR||Fv.join(process.env.HOME||_B.tmpdir(),".bostrat"),Hv=()=>Fv.join(Uv,"usage-caps.json"),Wv=.8;na={weekly:{startOf:qv,nextStart:Gv,capKey:"weeklyUsd"},monthly:{startOf:Kv,nextStart:zv,capKey:"monthlyUsd"}},un=null,th=!1,or={weekly:0,monthly:0},Ko=new Map,ra=new Set,eh=null,IB=e=>{let t=Ko.get(e);return t||(t={weekly:0,monthly:0},Ko.set(e,t)),t};Tu=e=>Math.round(e*1e4)/1e4});import RB from"node:fs/promises";import OB from"node:os";import Zv from"node:path";function nh(e){return e==="codex"?PB:e==="cursor"?oS:nS}function Qv(e){let t=String(e||"").split(`
178
+ `),n=t.findIndex(o=>/Select Model and Effort/i.test(o));if(n<0)return null;let r=[];for(let o=n+1;o<t.length;o++){let s=t[o].match(/^\s*(›\s*)?(\d+)\.\s+(\S+?)(?:\s+\((current|default)\))?(?:\s{2,}|\s*$)/);if(s)r.push({n:Number(s[2]),id:s[3],current:s[4]==="current",active:!!s[1]});else if(r.length&&/Press enter|esc to go back/i.test(t[o]))break}return r.length?r:null}function eS(e){let t=String(e||"").split(`
179
+ `),n=t.findIndex(o=>/Select Reasoning Level/i.test(o));if(n<0)return null;let r=[];for(let o=n+1;o<t.length;o++){let s=t[o].match(/^\s*(›\s*)?(\d+)\.\s+([A-Za-z ]+?)(?:\s+\((default|current)\))?(?:\s{2,}|\s*$)/);if(s)r.push({n:Number(s[2]),label:s[3].trim(),isDefault:!!s[4],active:!!s[1]});else if(r.length&&/Press enter|esc to go back/i.test(t[o]))break}return r.length?r:null}function DB(e){let t=String(e||"").split(`
180
+ `);for(let n=t.length-1;n>=0;n--){let r=t[n].match(/Model changed to\s+(\S+)(?:\s+(\S+))?\s*$/i);if(r)return{model:r[1],effort:r[2]||null}}return null}function tS(e){let t=String(e||"").split(`
181
+ `),n=t.findIndex(s=>/Available models|Models matching/i.test(s));if(n<0)return null;let r=/Models matching/i.test(t[n]),o=[];for(let s=n+1;s<t.length;s++){let a=t[s];if(/^\s*Filter:/i.test(a)||!a.trim())continue;if(/to filter|Enter to select|^\s*\d+-\d+ of \d+/i.test(a))break;let i=a.match(/^\s*(→\s+)?(.+?)\s*$/);if(!i)continue;let c=i[2].replace(/\s*\(Tab to modify\)\s*$/i,""),l=null,u=c.split(/\s{2,}/);u.length>1&&(c=u[0],l=u.slice(1).join(" ").trim()||null),c&&o.push({label:c.trim(),params:l,active:!!i[1]})}return o.length?{filtered:r,rows:o}:null}function sS(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&&!rS.has(o))throw new Error(`unknown codex effort "${o}" (low | medium | high | xhigh)`);return{model:r,effort:o||null}}if(e==="cursor"){let r=oS.find(o=>o.alias===n);return{model:n,filter:r?r.label:n}}if(!NB.has(n))throw new Error(`unknown model "${n}"`);return{model:n}}async function Fi(e,t,{timeoutMs:n=MB}={}){let r=Date.now()+n;for(;;){let o=await Pe(e,{lines:80}).catch(()=>""),s=t(o);if(s)return s;if(Date.now()>r)return null;await $u(CB)}}async function BB(e,t){return await ot(e,`/model ${t.model}`,$n("claude")),{verified:!1,note:"confirmed when the next turn's transcript model flips"}}async function jB(e,t){await Gl(e),await ot(e,"/model",{enter:!1}),await $u(250),await qe(e,["Enter"],{kind:"model-switch"});let n=await Fi(e,Qv);if(!n)throw new Error("codex model picker didn't open");let r=n.find(i=>i.id===t.model);if(!r)throw await qe(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=DB(i);return!c||c.model!==t.model||t.effort&&c.effort&&c.effort.toLowerCase()!==t.effort.toLowerCase()?null:c};await ot(e,String(r.n),{enter:!1,kind:"model-switch"});let s=await Fi(e,i=>eS(i)||!Qv(i)&&o(i)&&{done:o(i)});if(!s)throw await qe(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error("codex reasoning-level picker didn't open");if(!s.done){let i=t.effort?rS.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 qe(e,["Escape","Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`codex doesn't offer effort "${t.effort}" for ${t.model}`);await ot(e,String(c.n),{enter:!1,kind:"model-switch"})}let a=s.done||await Fi(e,i=>!eS(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 LB(){let e=Zv.join(process.env.CURSOR_CONFIG_DIR||Zv.join(OB.homedir(),".cursor"),"cli-config.json");try{return JSON.parse(await RB.readFile(e,"utf8"))?.model||null}catch{return null}}async function FB(e,t){await Gl(e),await Vl(e,`/model ${t.filter}`,{kind:"model-switch"});let n=await Fi(e,tS),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 Fi(e,tS,{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 qe(e,["Down"],{kind:"model-switch"}),await $u(250)}if(!n||!s||!o(s)){await qe(e,["Escape"],{kind:"model-switch"}).catch(()=>{});let c=Array(`/model ${t.filter}`.length).fill("BSpace");throw await qe(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 qe(e,["Enter"],{kind:"model-switch"}),await $u(800);let a=await LB();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 aS(e,t,n){return e==="codex"?jB(t,n):e==="cursor"?FB(t,n):BB(t,n)}var $u,MB,CB,nS,NB,PB,rS,oS,iS=G(()=>{ct();_i();$u=e=>new Promise(t=>setTimeout(t,e)),MB=Number(process.env.BOSTRAT_MODEL_PICKER_TIMEOUT_MS)||8e3,CB=300,nS=[{alias:"default",label:"Default"},{alias:"opus",label:"Opus 5"},{alias:"sonnet",label:"Sonnet 5"},{alias:"haiku",label:"Haiku 4.5"},{alias:"fable",label:"Fable 5.1"},{alias:"opusplan",label:"Opus Plan"}],NB=new Set([...nS.map(e=>e.alias),"best","opus[1m]","sonnet[1m]","claude-opus-5","claude-opus-4-8","claude-sonnet-5","claude-sonnet-4-6","claude-haiku-4-5","claude-fable-5","claude-fable-5-1"]),PB=[{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"}],rS=new Map([["low","Low"],["medium","Medium"],["high","High"],["xhigh","Extra high"]]),oS=[{alias:"auto",label:"Auto"},{alias:"composer-2.5",label:"Composer 2.5"},{alias:"claude-opus-5-high",label:"Opus 5"},{alias:"claude-fable-5-1-high",label:"Fable 5.1"},{alias:"claude-sonnet-5-high",label:"Sonnet 5"},{alias:"cursor-grok-4.6-high",label:"Cursor Grok 4.6"},{alias:"gpt-5.6-sol-high",label:"GPT-5.6 Sol High"},{alias:"gpt-5.3-codex",label:"Codex 5.3"}]});function Mu(e){let t=e||{},n=UB(t);return n&&(n.payload={ts:t.at,...n.payload}),n}function UB(e){switch(e.type){case"said":return{type:"turn.user",actor:"user",source:"orchestrator",boxId:e.box,provider:ut(e.agent),payload:{text:e.text,boxRole:e.boxRole,...e.kind?{kind:e.kind}:{},...e.attachments?.length?{attachments:e.attachments}:{},...e.deliveryId?{deliveryId:e.deliveryId}:{}}};case"unsaid":return{type:"turn.retracted",actor:"user",source:"orchestrator",boxId:e.box,provider:ut(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:ut(e.agent),payload:{text:e.prompt,kind:e.kind,boxRole:e.boxRole,...e.deliveryId?{deliveryId:e.deliveryId}:{}}};case"lead-handoff":return{type:"handoff.done",actor:"orchestrator",source:"orchestrator",boxId:e.to,provider:ut(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:ut(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:ut(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:ut(e.agent),payload:{...Yr(e)}};case"subtask-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box||e.to,provider:ut(e.agent||e.toAgent),payload:{kind:"subtask-failed",...Yr(e)}};case"subtask-resumed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:ut(e.agent),payload:{change:"subtask-resumed",...Yr(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",...Yr(e)}};case"opened":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:e.box,payload:{change:"opened",...Yr(e)}};case"archived":case"unarchived":case"track-deleted":case"renamed":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:e.type,...Yr(e)}};case"rehydrated":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:ut(e.agent),payload:{change:"rehydrated",...e.fresh?{fresh:!0}:{}}};case"lead-refreshed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:ut(e.agent),payload:{change:"lead-refreshed",box:e.box,agent:e.agent,fromSessionId:e.fromSessionId,toSessionId:e.toSessionId,epoch:e.epoch,reason:e.reason}};case"transferred-in":return{type:e.mode==="recover"?"track.recovered":"track.transferred",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:ut(e.agent),payload:{...Yr(e)}};case"transferred-out":return null;case"retagged":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:"retagged",...Yr(e)}};case"retag-failed":return{type:"error",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:ut(e.agent),payload:{kind:"retag-failed",action:e.action??"reshape",reason:e.reason,rolledBack:e.rolledBack!==!1,...e.recovered?{recovered:!0}:{}}};case"rehydrate-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:ut(e.agent),payload:{kind:"rehydrate-failed",reason:e.reason}};default:return null}}function uS(e,t){let n=Mu(t);if(!n)return;let r=t?.type==="track-deleted"?{id:e.id}:e;Cu(()=>M(r,n))}async function dS(e){if(!(!e?.id||cS.has(e.id))){cS.add(e.id);try{let t=await K(e),n=new Set(t.filter(r=>r.source==="orchestrator").map(r=>`${r.type}|${r.payload?.ts??"?"}`));for(let r of e.events||[]){let o=Mu(r);!o||n.has(`${o.type}|${o.payload?.ts??"?"}`)||await M(e,o)}}catch{}}}function Yr(e){let{type:t,at:n,...r}=e;return r}function pS(e,t,n){!n?.promptId||Ou.get(e.id)===n.promptId||(Ou.set(e.id,n.promptId),Cu(()=>M(e,{type:"prompt.raised",actor:"agent",source:"pane",boxId:t?.name,provider:ut(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 fS(e,t,n,r={}){Ou.delete(e.id),Cu(()=>M(e,{type:"prompt.dismissed",actor:"user",source:"orchestrator",boxId:t?.name,provider:ut(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}function rh(e,t,n,r={}){Ou.delete(e.id),Cu(()=>M(e,{type:"prompt.answered",actor:"user",source:"orchestrator",boxId:t?.name,provider:ut(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}var ut,Ru,Cu,lS,cS,Ou,oh=G(()=>{fe();ut=e=>e||null;Ru=Promise.resolve(),Cu=e=>(Ru=Ru.then(e).catch(()=>{}),Ru),lS=()=>Ru;cS=new Set;Ou=new Map});function GB(e){return String(e).split(/(?<=[.?!])\s+|\n+/).map(t=>t.trim()).filter(Boolean)}function bS(e){let t=String(e||"").trim();if(!t)return null;let n=t.slice(-600);for(let r of GB(n).reverse()){if(!HB.test(r))continue;let o=r.endsWith("?")&&r.length<=KB&&qB.test(r);if(WB.test(r)||o)return r.length>200?r.slice(0,197)+"\u2026":r}return null}function xS(e){let t=String(e||""),n=[];zB.test(t)&&n.push("commit"),kS.test(t)&&n.push("rebase"),VB.test(t)&&n.push("push");let r=YB.test(t);!r&&JB.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 vS(e){return kS.test(String(e||""))}function oa(e,{branch:t=null,base:n=null,toPr:r=null,repos:o=null,offeredRebase:s=!1}={}){Array.isArray(e)||(e=e==="push"?["commit","push"]:["commit","push","pr"]);let a=new Set(e),i=Array.isArray(o)&&o.length>0,c=i?o.map(f=>`${f.name}/`).join(", "):null,l=t?` on this branch (${t})`:"",u=[];if(a.has("commit")&&u.push(i?`commit the work in each changed checkout (${c})${l} with a clear commit message per repo`:`commit the work${l} with a clear commit message`),a.has("rebase")){let f=a.has("commit")?"the branch":`this branch${t?` (${t})`:""}`;u.push(i?`rebase ${f} in each changed checkout (${c}) onto its own base branch (fetch origin first), resolving any conflicts so both sides' intent is preserved`:`rebase ${f} onto ${n?`the latest ${n}`:"its base branch"} (fetch origin first), resolving any conflicts so both sides' intent is preserved`)}if(a.has("push")||a.has("pr")){let f=r&&!a.has("pr")?` (the open PR${r.number?` #${r.number}`:""} picks it up)`:"",w=a.has("rebase")?" with `--force-with-lease` (the rebase rewrote history)":"";i?u.push(a.has("commit")||a.has("rebase")?`push each one to its remote${w}${f}`:`push this branch${t?` (${t})`:""} from each changed checkout (${c}) to its remote${f}`):u.push(a.has("commit")||a.has("rebase")?`push it to the remote${w}${f}`:`push this branch${l} to the remote${f}`)}a.has("pr")&&u.push(i?"open a pull request in each changed repo with a concise title and a description of what changed and why (run `gh pr create` inside each checkout)":`open a pull request${n?` against ${n}`:""} with a concise title and a description of what changed and why (use \`gh pr create\`)`);let d=[];a.has("commit")||d.push("don't create any new commits \u2014 ship what's already committed"),s&&!a.has("rebase")&&d.push("don't rebase \u2014 leave the branch's history as it is"),!a.has("push")&&!a.has("pr")&&d.push("don't push"),a.has("pr")||d.push("don't open a pull request");let p=`Yes \u2014 go ahead: ${u.join(", then ")}.`;return d.length&&(p+=` ${d.join(", and ").replace(/^./,f=>f.toUpperCase())}.`),a.has("pr")&&(p+=i?" If a repo's PR for this branch is already open, just push that repo's update instead.":" If a PR for this branch is already open, just push the update instead."),p}function SS(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 AS(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<=XB&&n.push({box:r.box,from:r.from,to:t+1e12}),n}function TS(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+ZB||(!o||s.ts>=o.ts)&&(o=s);o&&n.add(o)}return n}function ES(e){let t=(Array.isArray(e)?e:[]).filter(r=>mS[r]).map(r=>mS[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 hS,wS,gS,yS,HB,WB,qB,KB,Xr,zB,kS,VB,JB,YB,XB,ZB,mS,Go=G(()=>{hS=/(?<!\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,wS=/(?<!\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,gS=/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,yS=/(?<!\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,HB=new RegExp(`\\b(?:${hS}|${wS}|${gS}|${yS})\\b`,"i"),WB=/\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,qB=/^(?:commit|push|open|create|raise|rebase|ready|ok(?:ay)?\s+to|good\s+to)\b/i,KB=90;Xr=["commit","rebase","push","pr"],zB=new RegExp(`\\b(?:${hS})\\b`,"i"),kS=new RegExp(`\\b(?:${yS})\\b`,"i"),VB=new RegExp(`\\b(?:${wS})\\b`,"i"),JB=new RegExp(`\\b(?:${gS})\\b`,"i"),YB=/\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;XB=3e4;ZB=2500;mS={commit:"commit",rebase:"rebase",push:"push",pr:"open a PR"}});import QB from"node:crypto";import Nu from"node:fs/promises";import _S from"node:path";import ej from"node:os";async function Ke(){return Zr||(sh??=Nu.readFile(ih,"utf8").then(e=>({links:JSON.parse(e)?.links??{},existed:!0})).catch(()=>({links:{},existed:!1})).then(async({links:e,existed:t})=>{if(Zr=e,!t&&He()){let{records:n,source:r}=await st("prlinks").catch(()=>({records:[],source:"error"}));if(r==="plane"){for(let o of n){if(o.deletedAt||!o.data?.repo||o.data?.number==null)continue;let{id:s,updatedAt:a,...i}=o.data;Zr[le(i.repo,i.number)]=i}Object.keys(Zr).length&&await ch().catch(()=>{})}}return Zr}).finally(()=>sh=null),sh)}async function ch(){let e=JSON.stringify({links:Zr},null,2),t=`${ih}.${process.pid}.tmp`;await Nu.mkdir(IS,{recursive:!0}),await Nu.writeFile(t,e),await Nu.rename(t,ih)}async function Qe(e){ah=ah.then(ch,ch),await ah.catch(()=>{});let t=Zr?.[e];t&&kt("prlinks",{id:$S(e),updatedAt:Date.now(),...t},{trackId:t.trackId??null}).catch(()=>{})}async function Bt({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 Ke(),c=le(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:tj.has(a),firstSeen:Date.now()},await Qe(le(e,t)),{link:i[c],created:!0})}async function sr(e,t){if(!e||t==null)return null;let n=(await Ke())[le(e,t)];return!n||n.announced?null:(n.announced=!0,await Qe(le(e,t)),n)}async function RS(e,t){if(!e||t==null)return!1;let n=(await Ke())[le(e,t)];return n?.notifyOnMerge?(delete n.notifyOnMerge,await Qe(le(e,t)),!0):!1}async function at(e,t){return!e||t==null?null:(await Ke())[le(e,t)]??null}async function Qr(e,t,n){if(!e||t==null)return null;let r=(await Ke())[le(e,t)];return r?(r.state=n,r.resolvedAt=Date.now(),delete r.armedAt,delete r.autoMerge,delete r.archiveOnMerge,delete r.notifyOnMerge,delete r.notifyPending,delete r.followupPending,await Qe(le(e,t)),r):null}async function OS(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await Ke())[le(e,t)];return o?(o.ciFix={delegatedAt:Date.now(),headSha:n,trackId:r},await Qe(le(e,t)),o):null}async function MS(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await Ke())[le(e,t)];return o?(o.reconcile={delegatedAt:Date.now(),headSha:n,trackId:r},await Qe(le(e,t)),o):null}async function Pu(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await Ke())[le(e,t)];return!r||!r.ciFix?null:(r.ciFixAwait={since:Date.now(),trackId:r.ciFix.trackId??null,headSha:n},delete r.ciFix,await Qe(le(e,t)),r)}async function Du(e,t){if(!e||t==null)return null;let n=(await Ke())[le(e,t)];return!n||!n.ciFixAwait?null:(delete n.ciFixAwait,await Qe(le(e,t)),n)}async function Bu(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await Ke())[le(e,t)];return!r||!r.reconcile?null:(r.reconcileAwait={since:Date.now(),trackId:r.reconcile.trackId??null,headSha:n},delete r.reconcile,await Qe(le(e,t)),r)}async function ju(e,t){if(!e||t==null)return null;let n=(await Ke())[le(e,t)];return!n||!n.reconcileAwait?null:(delete n.reconcileAwait,await Qe(le(e,t)),n)}async function CS(e,t,{at:n=Date.now()}={}){if(!e||t==null)return null;let r=(await Ke())[le(e,t)];return r?(r.baseFoldAt=n,await Qe(le(e,t)),r):null}async function NS(e,t){if(!e||t==null)return null;let n=(await Ke())[le(e,t)];return!n||!n.baseFoldAt?null:(delete n.baseFoldAt,await Qe(le(e,t)),n)}async function PS(e,t,n){if(!e||t==null||!n)return null;let r=(await Ke())[le(e,t)];return r?(r.lastHeadSha=n,await Qe(le(e,t)),r):null}async function DS(e,t,n){if(!e||t==null||!n)return{prev:null,link:null};let r=(await Ke())[le(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 Qe(le(e,t))),{prev:o,link:r}}async function Ui(e,t,{merge:n=null}={}){if(!e||t==null)return null;let r=(await Ke())[le(e,t)];return r?(r.armedAt=Date.now(),n&&(r.autoMerge={method:n.method||"merge",armedAt:r.armedAt}),await Qe(le(e,t)),r):null}async function zo(e,t,n=!0){if(!e||t==null)return null;let r=(await Ke())[le(e,t)];return r?(n?r.archiveOnMerge=!0:delete r.archiveOnMerge,await Qe(le(e,t)),r):null}async function Vo(e,t,n=!0){if(!e||t==null)return null;let r=(await Ke())[le(e,t)];return r?(n?r.notifyOnMerge=!0:delete r.notifyOnMerge,await Qe(le(e,t)),r):null}async function BS(e,t,n){if(!e||t==null)return null;let r=(await Ke())[le(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 Qe(le(e,t)),r}async function jS(e,t,n){if(!e||t==null)return null;let r=(await Ke())[le(e,t)];if(!r)return null;let o=new Map((r.followupPending||[]).map(s=>[`${s.repo}#${s.number}`,s]));for(let s of n||[])s&&s.number!=null&&o.set(`${s.repo}#${s.number}`,s);return r.followupPending=[...o.values()],await Qe(le(e,t)),r}async function Hi(e,t){if(!e||t==null)return null;let n=(await Ke())[le(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 Qe(le(e,t)),n)}async function LS(){return Object.values(await Ke()).filter(e=>!nj.has(e.state))}async function dn(){return Object.values(await Ke()).sort((e,t)=>t.firstSeen-e.firstSeen)}async function FS(){if(!He())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("prlinks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Ke(),r=0;for(let[o,s]of Object.entries(n))await kt("prlinks",{id:$S(o),updatedAt:Date.now(),...s},{trackId:s.trackId??null}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}var IS,ih,le,$S,Zr,sh,ah,tj,nj,Cn=G(()=>{Cr();IS=process.env.BOSTRAT_STATE_DIR||_S.join(process.env.HOME||ej.tmpdir(),".bostrat"),ih=_S.join(IS,"pr-links.json"),le=(e,t)=>`${e}#${Number(t)}`,$S=e=>{let t=e.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^[^A-Za-z0-9]+/,"").slice(0,55),n=QB.createHash("sha256").update(e).digest("hex").slice(0,8);return`${t||"pr"}-${n}`},Zr=null,sh=null,ah=Promise.resolve();tj=new Set(["api","observed","reconciled"]);nj=new Set(["merged","closed","lost"])});import rj from"node:fs";import lh from"node:fs/promises";import qS from"node:path";import oj from"node:os";function zS(e,t=!1){if(!t&&e-HS<sj)return;HS=e;let n=JSON.stringify({windowStart:sa,byCaller:Object.fromEntries(ar),lastHour:eo});WS=WS.then(()=>lh.mkdir(KS,{recursive:!0})).then(()=>lh.writeFile(`${Lu}.tmp`,n)).then(()=>lh.rename(`${Lu}.tmp`,Lu)).catch(()=>{})}function VS(e){e-sa<GS||(eo={start:sa,total:Fu(ar),byCaller:Object.fromEntries(ar)},eo.total&&console.log(`[github] ${eo.total} calls last hour`,eo.byCaller),sa=e,ar=new Map,zS(e,!0))}function ir(e="other",t=Date.now()){VS(t),ar.set(e,(ar.get(e)||0)+1),zS(t)}function JS(e=Date.now()){return VS(e),{windowStart:sa,total:Fu(ar),byCaller:Object.fromEntries(ar),lastHour:eo,backoffUntil:Jo>e?Jo:null}}function to(e){return aj.test(String(e?.message||e||""))}function no(e,t=Date.now()){return Jo<=t&&console.warn(`[github] rate limited \u2014 backing off ${US/6e4} min:`,String(e?.message||e||"").slice(0,200)),Jo=Math.max(Jo,t+US),Jo}function Uu(e=Date.now()){return Math.max(0,Jo-e)}var KS,Lu,GS,US,sj,sa,ar,eo,Jo,HS,Fu,WS,aj,Wi=G(()=>{KS=process.env.BOSTRAT_STATE_DIR||qS.join(process.env.HOME||oj.tmpdir(),".bostrat"),Lu=qS.join(KS,"github-metrics.json"),GS=60*6e4,US=5*6e4,sj=6e4,sa=Date.now(),ar=new Map,eo=null,Jo=0,HS=0,Fu=e=>[...e.values()].reduce((t,n)=>t+n,0);try{let e=JSON.parse(rj.readFileSync(Lu,"utf8"));e?.windowStart&&(Date.now()-e.windowStart<GS?(sa=e.windowStart,ar=new Map(Object.entries(e.byCaller||{})),eo=e.lastHour||null):Fu(new Map(Object.entries(e.byCaller||{})))&&(eo={start:e.windowStart,total:Fu(new Map(Object.entries(e.byCaller||{}))),byCaller:e.byCaller||{}}))}catch{}WS=Promise.resolve();aj=/rate limit|too quickly|abuse detection|HTTP 429/i});import YS from"node:fs/promises";import XS from"node:path";import ij from"node:os";function Wu({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};Hu.push(l),Hu.length>lj&&Hu.shift();let u=uh.get(e)||{count:0,measured:0,totalMs:0,maxMs:0};return u.count+=1,c!=null&&(u.measured+=1,u.totalMs+=c,u.maxMs=Math.max(u.maxMs,c)),uh.set(e,u),uj(l),l}async function uj(e){try{await YS.mkdir(ZS,{recursive:!0}),await YS.appendFile(cj,JSON.stringify(e)+`
182
+ `)}catch{}}function QS(){let e={};for(let[t,n]of uh)e[t]={count:n.count,measured:n.measured,avgMs:n.measured?Math.round(n.totalMs/n.measured):null,maxMs:n.measured?n.maxMs:null};return{byChange:e,recent:Hu.slice(-20)}}var ZS,cj,lj,Hu,uh,qu=G(()=>{ZS=process.env.BOSTRAT_STATE_DIR||XS.join(process.env.HOME||ij.tmpdir(),".bostrat"),cj=XS.join(ZS,"github-latency.ndjson"),lj=100,Hu=[],uh=new Map});import{execFile as dj}from"node:child_process";import{promisify as pj}from"node:util";async function fj(e){let t=/workspaces[/\\]([0-9a-f]{8})(?:[/\\]|$)/.exec(e||"")?.[1];if(t)try{let[{stdout:n},{stdout:r}]=await Promise.all([ia("git",["-C",e,"rev-parse","HEAD"]),ia("git",["-C",e,"rev-parse","--abbrev-ref","HEAD"])]);await M({id:t,cwd:e},{type:"code.pushed",actor:"orchestrator",payload:{ref:r.trim(),sha:n.trim(),wip:!1,ts:Date.now()}})}catch{}}async function Yt(e,t,n={}){let{caller:r="prs",...o}=n,s=await An({cwd:e});ir(r);try{let{stdout:a}=await ia("gh",t,{cwd:e,...mj,...o,env:{...process.env,...s,...o.env||{}}});return String(a||"")}catch(a){throw to(a)&&no(a),a}}async function fh(){if(Ku&&Date.now()-Ku.at<6e4)return Ku.data;let e;try{ir("auth");let t=await ia("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 ti();t.configured&&(e={installed:!0,authenticated:!0,login:t.username,via:"broker"})}catch{}return Ku={at:Date.now(),data:e},e}async function hj(e){try{let{stdout:t}=await ia("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});return/github\.com/.test(t)}catch{return!1}}function tA(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 dh(e){let t=(e||[]).map(tA),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 hh(e){return/Resource not accessible by personal access token/.test(String(e?.stderr||e?.message||""))}async function rA(e,t){if(!t)return null;let n=await _e(e);if(!n)return null;try{let r=await Yt(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 oA(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 sA(e,t){let n=await rA(e,t);return n===null?{...dh([]),unavailable:!0}:dh(oA(n))}function Gu(e,t=dh(e.statusCheckRollup)){return{number:e.number,title:e.title,url:e.url,author:e.author?.login??null,headRefName:e.headRefName,headSha:e.headRefOid??null,baseRefName:e.baseRefName,isDraft:!!e.isDraft,reviewDecision:e.reviewDecision||null,mergeable:e.mergeable||"UNKNOWN",mergeStateStatus:e.mergeStateStatus||"UNKNOWN",state:e.state??null,mergedAt:e.mergedAt??null,closedAt:e.closedAt??null,additions:e.additions??0,deletions:e.deletions??0,createdAt:e.createdAt,updatedAt:e.updatedAt,checks:t,green:t.failed===0&&t.pending===0&&e.mergeStateStatus==="CLEAN",autoMergeArmed:!!e.autoMergeRequest,mergeabilityPending:!1}}function gj(e,t,n){let r=new Set;for(let o of t){let s=`${e}#${o.number}`;if(o.mergeable!=="UNKNOWN"&&o.mergeStateStatus!=="UNKNOWN"){aa.delete(s);continue}r.add(s),aa.has(s)||aa.set(s,n),o.mergeabilityPending=n-aa.get(s)<wj}for(let o of aa.keys())o.startsWith(`${e}#`)&&!r.has(o)&&aa.delete(o);return t}async function ca(e,t){let n=await cr(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{let o=await Yt(n.path,["pr","view",String(r),"--json",mh]);return Gu(JSON.parse(o))}catch(o){if(!hh(o))throw o;let s=await Yt(n.path,["pr","view",String(r),"--json",nA]),a=JSON.parse(s);return Gu(a,await sA(n.path,a.headRefOid))}}async function Nn(e,{caller:t="prs"}={}){try{let n=await Yt(e,["pr","list","--json",mh,"--limit","50"],{caller:t});return JSON.parse(n||"[]").map(r=>Gu(r)).sort(eA)}catch(n){if(!hh(n))throw n;let r=await Yt(e,["pr","list","--json",nA,"--limit","50"],{caller:t});return(await Promise.all(JSON.parse(r||"[]").map(async o=>Gu(o,await sA(e,o.headRefOid))))).sort(eA)}}function Xt(){qi.clear()}async function kj(e,t){if(!e)return t;for(let n of t){let r=await at(e,n.number).catch(()=>null);if(!r)continue;r.trackId&&(n.trackId=r.trackId),r.autoMerge&&(n.autoMergeArmed=!0),r.archiveOnMerge&&(n.archiveOnMerge=!0),r.notifyOnMerge&&(n.notifyOnMerge=!0);let o=s=>n.headSha&&s.headSha&&n.headSha!==s.headSha;r.ciFix&&(o(r.ciFix)?await Pu(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.ciFix={delegatedAt:r.ciFix.delegatedAt,trackId:r.ciFix.trackId??null}),r.reconcile&&(o(r.reconcile)?await Bu(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.reconcile={delegatedAt:r.reconcile.delegatedAt,trackId:r.reconcile.trackId??null})}return t}async function aA(){let e=await fh();if(!e.authenticated)return{auth:e,repos:[]};let t=[];for(let a of await Zn())await hj(a.path)&&t.push(a);let n=Date.now(),r=Uu(n)>0,o=await Promise.all(t.map(async a=>{let i=qi.get(a.path),c=i?.pending?bj:yj;if(i&&(r||n-i.at<c))return i.entry;try{let l=await _e(a.path).catch(()=>null),u=gj(a.path,await Nn(a.path,{caller:"tab"}),n);if(await kj(l,u),i?.entry?.prs)for(let f of u)i.entry.prs.find(m=>m.number===f.number)?.checks?.pending>0&&f.checks.total>0&&f.checks.pending===0&&Wu({change:f.checks.failed>0?"checks-failed":"checks-green",repo:l||a.name,number:f.number,githubAt:f.checks.settledAt,source:"tab"});let d={name:a.name,path:a.path,prs:u},p=u.some(f=>f.mergeabilityPending||f.checks.pending>0||f.autoMergeArmed);return qi.set(a.path,{at:Date.now(),entry:d,pending:p}),d}catch(l){return i?i.entry:{name:a.name,path:a.path,prs:[],error:Pn(l)}}})),s=new Set(t.map(a=>a.path));for(let a of qi.keys())s.has(a)||qi.delete(a);return{auth:e,repos:o}}async function cr(e){let t=(await Zn()).find(n=>n.path===e);if(!t)throw new Error(`unknown repo: ${e}`);return t}async function Yo(e){return Is(e)}async function la(e,t,{method:n="squash"}={}){let r=await cr(e);if(!Ki.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 An({cwd:r.path})).GH_TOKEN){let a=await sf().catch(()=>null);a&&s.push("--body",`Merged by bostrat on behalf of @${a}`)}try{await Yt(r.path,s)}catch(a){throw new Error(Pn(a))}finally{Xt()}return{ok:!0,number:o}}async function Gi(e,t){let n=await cr(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await Yt(n.path,["api","-X","PUT",`repos/{owner}/{repo}/pulls/${r}/update-branch`])}catch(s){throw new Error(Pn(s))}finally{Xt()}let o=await _e(n.path).catch(()=>null);return o&&await CS(o,r).catch(()=>{}),{ok:!0,number:r}}async function wh(e,t){let n=await cr(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await Yt(n.path,["pr","merge",String(r),"--disable-auto"])}catch(o){throw new Error(Pn(o))}finally{Xt()}return{ok:!0,number:r}}function gh(e){return e.green&&!e.isDraft}function Aj(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 iA(e,{update:t=!0}={}){return e.isDraft?{action:"skip",reason:"draft"}:gh(e)?{action:"merge"}:t&&e.mergeStateStatus==="BEHIND"&&e.mergeable!=="CONFLICTING"&&e.checks.failed===0?{action:"update-arm"}:{action:"arm"}}function cA(e){return[...e.filter(t=>t.plan.action!=="merge"),...e.filter(t=>t.plan.action==="merge")]}function zi(e,t){let n=a=>a?.firstSeen!=null&&Number.isFinite(Number(a.firstSeen))?Number(a.firstSeen):Number.MAX_SAFE_INTEGER,r=n(e),o=n(t);if(r!==o)return r-o;let s=String(e?.repo||"").localeCompare(String(t?.repo||""));return s||Number(e?.number||0)-Number(t?.number||0)}function lA(e){let t=new Map;for(let n of[...e].filter(r=>r?.autoMerge&&r?.trackId).sort(zi))t.has(n.trackId)||t.set(n.trackId,`${n.repo}#${n.number}`);return t}function uA(){let e={};for(let[t,n]of ph)e[t]={...n};return e}async function dA(e,{method:t="merge",onMerged:n=null}={}){let r=await cr(e);if(!Ki.has(t))throw new Error(`invalid merge method: ${t}`);if(ph.get(r.path)?.running)throw new Error("a merge-all is already running for this repo");let o=(await Nn(r.path)).filter(gh).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 ph.set(r.path,s),Ej(s,o,{listPrs:()=>Nn(r.path),merge:a=>la(r.path,a,{method:t}),sleep:Sj,onMerged:n}).catch(()=>{}),{ok:!0,repo:r.path,total:s.total,queue:o.map(a=>a.number)}}async function Tj(e,t){let n=Date.now()+(t.settleMaxMs??vj),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(xj)}}async function Ej(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 Tj(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: ${Pn(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(!gh(a)){e.skipped.push({number:a.number,title:a.title,reason:Aj(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:Pn(i)})}}}finally{e.current=null,e.running=!1,e.finishedAt=Date.now(),Xt()}}async function yh(e,{title:t,body:n="",base:r=null}={}){if(typeof t!="string"||!t.trim())throw new Error("title required");try{await ia("git",["-C",e,"push","-u","origin","HEAD"],{timeout:12e4,maxBuffer:4*1024*1024})}catch(l){throw new Error(`push failed: ${Pn(l)}`)}await fj(e);let o=n||"";if((await An({cwd:e})).GH_TOKEN){let l=await sf().catch(()=>null);l&&(o=`${o?`${o}
183
+
184
+ `:""}Opened by bostrat on behalf of @${l}`)}let s=["pr","create","--title",t.trim(),"--body",o];r&&s.push("--base",r);let a;try{a=await Yt(e,s)}catch(l){throw new Error(Pn(l))}finally{Xt()}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 pA(e,t){let n=await cr(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");let o;try{let i;try{i=await Yt(n.path,["pr","checks",String(r),"--json","name,state,link,bucket"])}catch(c){if(i=String(c?.stdout||""),!i.trim())throw new Error(Pn(c))}o=JSON.parse(i||"[]").filter(c=>c.bucket==="fail")}catch(i){if(!hh(i))throw i;let c=await Yt(n.path,["pr","view",String(r),"--json","headRefOid"]),l=await rA(n.path,JSON.parse(c).headRefOid);if(l===null)throw new Error(Pn(i));o=oA(l).map(tA).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=_j(i.link),l=null;c&&!s.has(c)&&(s.add(c),l=await Yt(n.path,["run","view",c,"--log-failed"]).then(u=>Ij(u)).catch(()=>null)),a.push({name:i.name,link:i.link||null,log:l})}return a}function _j(e){return String(e||"").match(/\/actions\/runs\/(\d+)/)?.[1]??null}function Ij(e,{maxLines:t=400,maxBytes:n=64*1024}={}){let r=String(e||""),o=r.split(`
185
185
  `);return o.length>t&&(r=`\u2026 (${o.length-t} earlier lines truncated)
186
186
  `+o.slice(-t).join(`
187
187
  `)),Buffer.byteLength(r)>n&&(r=`\u2026 (truncated)
188
- `+r.slice(-n)),r}function Mn(e){return String(e?.stderr||e?.message||e||"").trim().split(`
189
- `).find(n=>n.trim())||"gh failed"}var Zs,QB,Lu,Zm,US,tj,Xs,LS,rj,oj,ji,Li,aj,ij,cj,Ym,Uo=G(()=>{Tr();pt();Rn();Bi();ju();de();Zs=XB(YB),QB={timeout:3e4,maxBuffer:8*1024*1024};Lu=null;Zm="number,title,url,headRefName,headRefOid,baseRefName,isDraft,author,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup,autoMergeRequest,additions,deletions,createdAt,updatedAt,state,mergedAt,closedAt",US=Zm.replace("statusCheckRollup,","");tj=9e4,Xs=new Map;LS=(e,t)=>e.number-t.number;rj=3e4,oj=1500,ji=new Map;Li=new Set(["squash","merge","rebase"]);aj=2500,ij=9e4,cj=e=>new Promise(t=>setTimeout(t,e));Ym=new Map});import{execFile as mj}from"node:child_process";import{promisify as hj}from"node:util";async function gj(e,t){try{let{stdout:n}=await wj("git",["-C",e,"rev-list","--count",t]);return Number(n.trim())||0}catch{return null}}async function yj(e,t,n,{rebase:r=!1,listPrs:o=On}={}){let s=await Oi(e.dir,{ignorePlumbing:!0}).catch(()=>!1),a=await Mi(e.dir,n).catch(()=>0),i=t?await gj(e.dir,`refs/remotes/origin/${t}..HEAD`):null,c=i==null?a>0:i>0,l=null,u="unknown";try{l=(await o(e.dir,{caller:"ship-state"})||[]).find(m=>m.headRefName===t)||null,u=l?"open":"none"}catch{}let d=s||a>0,p=[];s&&p.push("commit"),r&&p.push("rebase"),(s||c)&&p.push("push"),d&&(u!=="open"||s||c)&&p.push("pr");let f=p.filter(w=>!(w==="pr"&&u==="open"));return{name:e.name??null,slug:e.repo??null,dirty:s,unpushed:c,aheadBase:a,prState:u,openPr:l?{number:l.number,url:l.url??null,title:l.title??null}:null,available:Uu.filter(w=>p.includes(w)),defaults:Uu.filter(w=>f.includes(w))}}async function Hu(e,{branch:t,rebase:n=!1,listPrs:r=On}={}){let o=e?.workspace,s=o?.kind==="multi"?(o.repos||[]).filter(p=>p?.dir):o?.base&&(o.dir||e?.cwd)?[{name:o.base?.split("/").pop()??null,dir:o.dir||e.cwd,repo:o.repo??null,baseRef:o.baseRef}]:[];if(!s.length||!await qs(s[0].dir).catch(()=>!1))return null;let a=[];for(let p of s)a.push(await yj(p,t,p.baseRef||o.baseRef,{rebase:n,listPrs:r}));let i=a.filter(p=>p.dirty||p.aheadBase>0||p.openPr),c=i.length?i:a,l=Uu.filter(p=>c.some(f=>f.available.includes(p))),u=Uu.filter(p=>c.some(f=>f.defaults.includes(p))),d=c.filter(p=>p.openPr);return{available:l,defaults:u,prState:d.length?"open":c.every(p=>p.prState==="none")?"none":"unknown",openPr:c.length===1?c[0].openPr:null,repos:c.map(p=>({name:p.name,slug:p.slug,dirty:p.dirty,unpushed:p.unpushed,prState:p.prState,openPr:p.openPr}))}}var wj,Uu,rh=G(()=>{gu();Uo();wj=hj(mj),Uu=["commit","rebase","push","pr"]});function qu(e,t,n){let{state:r,reason:o}=Pf(t,n);if(r!=="unknown"){if(e){let a=Date.now();for(let[i,c]of Hi)a-c.at>=ZS()&&Hi.delete(i);Hi.set(e,{busy:r==="busy",at:a})}return r==="busy"}if(o!=="narrow"||!e)return!1;let s=Hi.get(e);return s?Date.now()-s.at>=ZS()?(Hi.delete(e),!1):s.busy:!1}async function oh(e,t){let n={working:!1,prompted:!1};if(!e)return n;let r=await Be(e,{lines:Ze}).catch(()=>"");if(!qu(e,t,r))return f0(t,r)?{working:!0,prompted:!1}:n;if(Wr(t,r)){let o=await on(e).catch(()=>r),s=$n({name:e,agent:t},o);if(s)return!hu({name:e,agent:t},s,o)||yv(e)?{working:!1,prompted:!0}:{working:!1,prompted:!1}}return{working:!0,prompted:!1}}async function Ho(e,t){return(await oh(e,t)).working}var ZS,Hi,qi=G(()=>{ct();bi();_m();$m();ZS=()=>Number(process.env.BOSTRAT_NARROW_CARRY_MS)||9e4,Hi=new Map});import{execFile as bj}from"node:child_process";import{promisify as kj}from"node:util";async function Zr(e){if(!e)return null;let t=QS.get(e);if(t&&Date.now()-t.at<vj)return t.branch;let n=null;try{let{stdout:r}=await xj("git",["-C",e,"symbolic-ref","--short","-q","HEAD"],{timeout:5e3});n=r.trim()||null}catch{n=null}return QS.set(e,{at:Date.now(),branch:n}),n}function eT(e){return String(e||"").match(Sj)?.[1]??null}function tT(e,t){let n=eT(e);return!!n&&!!t&&n===t}function nT(e,t){let n=eT(e);return!!n&&n!==t}function Tj(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 ta(e){let t=[],n=r=>{r&&!t.includes(r)&&t.push(r)};n(e?.workspace?.branch??null);for(let r of Tj(e))n(await Zr(r));return t}async function Wu(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=>tT(t,a.id));if(s)return s;for(let a of r)if(!De(a)&&(await ta(a)).includes(t))return a;return null}function Aj(e,t,n){let r=e?.workspace;return r?.kind==="multi"?(r.repos??[]).some(o=>t&&o?.base===t||n&&o?.repo===n):!r?.base||!t||r.base===t||n&&r.repo===n}function Ku(e,{branch:t=null,repo:n=null,slug:r=null}={}){return tT(t,e?.id)?!0:Aj(e,n,r)}var xj,vj,QS,Sj,qo=G(()=>{Gt();xj=kj(bj),vj=5e3,QS=new Map;Sj=/^track\/.+-([0-9a-f]{8})$/});import{execFile as Ej}from"node:child_process";import{promisify as _j}from"node:util";function na({trackId:e,boxId:t,epoch:n}){return`${e}/${t}/${Number.isFinite(Number(n))?Number(n):0}`}function zu(e){let t=/^([^/\s]+)\/([^/\s]+)\/(\d+)$/.exec(String(e||"").trim());return t?{trackId:t[1],boxId:t[2],epoch:Number(t[3])}:null}function Ju({trackId:e,boxId:t,epoch:n=0,provider:r=null,model:o=null}){let s=[],a=r?Cj[r]:null;return a&&s.push(a),s.push(`${iT}: ${na({trackId:e,boxId:t,epoch:n})}`),o&&s.push(`${cT}: ${String(o).trim()}`),s}function rT(e){let t={epoch:null,model:null,provider:null,cause:null};for(let n of String(e||"").split(`
190
- `)){let r=n.trim(),o=/^([A-Za-z-]+):\s*(.+)$/.exec(r);if(!o)continue;let s=o[1].toLowerCase(),a=o[2].trim();if(s===iT.toLowerCase()&&!t.epoch)t.epoch=zu(a);else if(s===cT.toLowerCase()&&!t.model)t.model=a;else if(s===lT.toLowerCase()&&!t.cause){let i=a.toLowerCase();Wi.includes(i)&&(t.cause=i)}else if(s==="co-authored-by"||s==="made-with"){let i=a.toLowerCase();t.provider||(i.startsWith("claude")?t.provider="claude":i.startsWith("codex")?t.provider="codex":i.startsWith("cursor")&&(t.provider="cursor"))}}return t}function Nj(e,t=Qr){return e<=t?"rework":"drift"}function Pj(e,{window:t=Qr,end:n=lh}={}){return!Number.isFinite(e)||e<=t?1:e>=n?0:1-(e-t)/(n-t)}function Yu({subject:e="",trailerCause:t=null,wallReason:n=null,fixerCategory:r=null,ciFix:o=!1}={}){let s=String(e||"");return Dj.test(s)?{cause:"defect",level:"A",basis:"revert"}:o?{cause:"defect",level:"A",basis:"ci-fix"}:t?{cause:t,level:"E",basis:`${lT} trailer`}:jj.test(s)&&!oT.test(s)?{cause:"style",level:"C",basis:"subject"}:oT.test(s)?{cause:"defect",level:"C",basis:"subject"}:Bj.test(s)?{cause:"design",level:"C",basis:"subject: refactor"}:n==="wrong-approach"?{cause:"design",level:"C",basis:"wall label: wrong-approach"}:r==="bug-fix"?{cause:"defect",level:"C",basis:"fixer prompt: bug-fix"}:null}function dh({heuristic:e=null,subject:t="",ref:n=null,promptKind:r=null,fixerCategory:o=null,ticketKind:s=null}={}){let a=String(t||""),i=Lj.exec(a),c=i?i[1].toLowerCase():null;return e&&(e.level==="A"||e.level==="E")?{intent:"fix",basis:e.basis}:s&&/^bug/i.test(s)?{intent:"fix",basis:`linked ticket: ${s}`}:c&&Fj.has(c)?{intent:"fix",basis:`subject prefix: ${c}:`}:c&&Uj.has(c)?{intent:"planned",basis:`subject prefix: ${c}:`}:s&&/^(story|feature|task)/i.test(s)?{intent:"planned",basis:`linked ticket: ${s}`}:e?{intent:"likely-fix",basis:e.basis}:r==="followup-go"?{intent:"planned",basis:"operator-tapped follow-up"}:sT.test(String(n||""))||sT.test(a)?{intent:"planned",basis:"blueprint item"}:o&&Hj.has(o)?{intent:"planned",basis:`prompt: ${o}`}:{intent:"unknown",basis:null}}function Gj(e){let t=String(e||"");return qj.some(n=>n.test(t))?"excluded":Wj.some(n=>n.test(t))?"docs":Kj.some(n=>n.test(t))?"config":"code"}function zj(e){let t=[],n=null,r=null;for(let o of String(e||"").split(`
191
- `)){if(o.startsWith("diff --git ")){n={oldPath:null,newPath:null,deleted:[],added:0,binary:!1,hunks:[]},r=null,t.push(n);continue}if(n)if(o.startsWith("--- ")&&!r){let s=o.slice(4).trim();n.oldPath=s==="/dev/null"?null:s.replace(/^a\//,"")}else if(o.startsWith("+++ ")&&!r){let s=o.slice(4).trim();n.newPath=s==="/dev/null"?null:s.replace(/^b\//,"")}else if(o.startsWith("Binary files"))n.binary=!0;else if(o.startsWith("@@")){let s=/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/.exec(o);if(!s)continue;let a=Number(s[1]),i=s[2]==null?1:Number(s[2]),c=Number(s[3]),l=s[4]==null?1:Number(s[4]);i>0&&n.deleted.push([a,i]),n.added+=l,r={oldStart:a,oldCount:i,newStart:c,newCount:l,del:[],add:[]},n.hunks.push(r)}else r&&o.startsWith("-")?r.del.push(o.slice(1)):r&&o.startsWith("+")&&r.add.push(o.slice(1))}return t}function Vj(e,t){let n=ch(e),r=ch(t);if(n===r)return 1;if(!n.length||!r.length)return 0;n.length>Gu&&(n=n.slice(0,Gu)),r.length>Gu&&(r=r.slice(0,Gu));let o=new Array(r.length+1),s=new Array(r.length+1);for(let a=0;a<=r.length;a++)o[a]=a;for(let a=1;a<=n.length;a++){s[0]=a;let i=n.charCodeAt(a-1);for(let c=1;c<=r.length;c++){let l=i===r.charCodeAt(c-1)?0:1;s[c]=Math.min(o[c]+1,s[c-1]+1,o[c-1]+l)}[o,s]=[s,o]}return 1-o[r.length]/Math.max(n.length,r.length)}function Jj(e,t=uT){let n=new Set,r=e?.del||[],o=e?.add||[];for(let s=0;s<r.length;s++){let a=e.oldStart+s;if(!ch(r[s]).length){n.add(a);continue}s<o.length&&Vj(r[s],o[s])>=t&&n.add(a)}return n}function Yj(e){let t=[...e].sort((r,o)=>r-o),n=[];for(let r of t){let o=n[n.length-1];o&&o[0]+o[1]===r?o[1]+=1:n.push([r,1])}return n}function Xj(e){let t=new Map,n=null;for(let r of String(e||"").split(`
192
- `)){let o=/^([0-9a-f]{40}) (\d+) (\d+)(?: (\d+))?$/.exec(r);if(o){n={sha:o[1],line:Number(o[3]),time:null},t.set(n.line,n);continue}n&&r.startsWith("committer-time ")&&(n.time=Number(r.slice(15))*1e3)}return t}async function aT(e,t){let{stdout:n}=await ih(e,["show","-s","--format=%H%n%P%n%ct%n%s%n%B",t]),[r,o,s,a,...i]=n.split(`
188
+ `+r.slice(-n)),r}function Pn(e){return String(e?.stderr||e?.message||e||"").trim().split(`
189
+ `).find(n=>n.trim())||"gh failed"}var ia,mj,Ku,mh,nA,wj,aa,eA,yj,bj,qi,Ki,xj,vj,Sj,ph,Xo=G(()=>{$r();ft();Cn();Wi();qu();fe();ia=pj(dj),mj={timeout:3e4,maxBuffer:8*1024*1024};Ku=null;mh="number,title,url,headRefName,headRefOid,baseRefName,isDraft,author,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup,autoMergeRequest,additions,deletions,createdAt,updatedAt,state,mergedAt,closedAt",nA=mh.replace("statusCheckRollup,","");wj=9e4,aa=new Map;eA=(e,t)=>e.number-t.number;yj=3e4,bj=1500,qi=new Map;Ki=new Set(["squash","merge","rebase"]);xj=2500,vj=9e4,Sj=e=>new Promise(t=>setTimeout(t,e));ph=new Map});import{execFile as $j}from"node:child_process";import{promisify as Rj}from"node:util";async function Mj(e,t){try{let{stdout:n}=await Oj("git",["-C",e,"rev-list","--count",t]);return Number(n.trim())||0}catch{return null}}async function Cj(e,t,n,{rebase:r=!1,listPrs:o=Nn}={}){let s=await Uo(e.dir,{ignorePlumbing:!0}).catch(()=>!1),a=await Ho(e.dir,n).catch(()=>0),i=t?await Mj(e.dir,`refs/remotes/origin/${t}..HEAD`):null,c=i==null?a>0:i>0,l=null,u="unknown";try{l=(await o(e.dir,{caller:"ship-state"})||[]).find(m=>m.headRefName===t)||null,u=l?"open":"none"}catch{}let d=s||a>0,p=[];s&&p.push("commit"),r&&p.push("rebase"),(s||c)&&p.push("push"),d&&(u!=="open"||s||c)&&p.push("pr");let f=p.filter(w=>!(w==="pr"&&u==="open"));return{name:e.name??null,slug:e.repo??null,dirty:s,unpushed:c,aheadBase:a,prState:u,openPr:l?{number:l.number,url:l.url??null,title:l.title??null}:null,available:zu.filter(w=>p.includes(w)),defaults:zu.filter(w=>f.includes(w))}}async function Vu(e,{branch:t,rebase:n=!1,listPrs:r=Nn}={}){let o=e?.workspace,s=o?.kind==="multi"?(o.repos||[]).filter(p=>p?.dir):o?.base&&(o.dir||e?.cwd)?[{name:o.base?.split("/").pop()??null,dir:o.dir||e.cwd,repo:o.repo??null,baseRef:o.baseRef}]:[];if(!s.length||!await ea(s[0].dir).catch(()=>!1))return null;let a=[];for(let p of s)a.push(await Cj(p,t,p.baseRef||o.baseRef,{rebase:n,listPrs:r}));let i=a.filter(p=>p.dirty||p.aheadBase>0||p.openPr),c=i.length?i:a,l=zu.filter(p=>c.some(f=>f.available.includes(p))),u=zu.filter(p=>c.some(f=>f.defaults.includes(p))),d=c.filter(p=>p.openPr);return{available:l,defaults:u,prState:d.length?"open":c.every(p=>p.prState==="none")?"none":"unknown",openPr:c.length===1?c[0].openPr:null,repos:c.map(p=>({name:p.name,slug:p.slug,dirty:p.dirty,unpushed:p.unpushed,prState:p.prState,openPr:p.openPr}))}}var Oj,zu,bh=G(()=>{Su();Xo();Oj=Rj($j),zu=["commit","rebase","push","pr"]});function Ju(e,t,n){let{state:r,reason:o}=Yf(t,n);if(r!=="unknown"){if(e){let a=Date.now();for(let[i,c]of Vi)a-c.at>=fA()&&Vi.delete(i);Vi.set(e,{busy:r==="busy",at:a})}return r==="busy"}if(o!=="narrow"||!e)return!1;let s=Vi.get(e);return s?Date.now()-s.at>=fA()?(Vi.delete(e),!1):s.busy:!1}async function kh(e,t){let n={working:!1,prompted:!1};if(!e)return n;let r=await Pe(e,{lines:Ye}).catch(()=>"");if(!Ju(e,t,r))return $0(t,r)?{working:!0,prompted:!1}:n;if(Vr(t,r)){let o=await sn(e).catch(()=>r),s=Mn({name:e,agent:t},o);if(s)return!vu({name:e,agent:t},s,o)||Pv(e)?{working:!1,prompted:!0}:{working:!1,prompted:!1}}return{working:!0,prompted:!1}}async function Zo(e,t){return(await kh(e,t)).working}var fA,Vi,Ji=G(()=>{ct();Ei();Um();Wm();fA=()=>Number(process.env.BOSTRAT_NARROW_CARRY_MS)||9e4,Vi=new Map});import{execFile as Nj}from"node:child_process";import{promisify as Pj}from"node:util";async function ro(e){if(!e)return null;let t=mA.get(e);if(t&&Date.now()-t.at<Bj)return t.branch;let n=null;try{let{stdout:r}=await Dj("git",["-C",e,"symbolic-ref","--short","-q","HEAD"],{timeout:5e3});n=r.trim()||null}catch{n=null}return mA.set(e,{at:Date.now(),branch:n}),n}function hA(e){return String(e||"").match(jj)?.[1]??null}function wA(e,t){let n=hA(e);return!!n&&!!t&&n===t}function gA(e,t){let n=hA(e);return!!n&&n!==t}function Lj(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 ua(e){let t=[],n=r=>{r&&!t.includes(r)&&t.push(r)};n(e?.workspace?.branch??null);for(let r of Lj(e))n(await ro(r));return t}async function Yu(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=>wA(t,a.id));if(s)return s;for(let a of r)if(!je(a)&&(await ua(a)).includes(t))return a;return null}function Fj(e,t,n){let r=e?.workspace;return r?.kind==="multi"?(r.repos??[]).some(o=>t&&o?.base===t||n&&o?.repo===n):!r?.base||!t||r.base===t||n&&r.repo===n}function Xu(e,{branch:t=null,repo:n=null,slug:r=null}={}){return wA(t,e?.id)?!0:Fj(e,n,r)}var Dj,Bj,mA,jj,Qo=G(()=>{Jt();Dj=Pj(Nj),Bj=5e3,mA=new Map;jj=/^track\/.+-([0-9a-f]{8})$/});import{execFile as Uj}from"node:child_process";import{promisify as Hj}from"node:util";function da({trackId:e,boxId:t,epoch:n}){return`${e}/${t}/${Number.isFinite(Number(n))?Number(n):0}`}function Qu(e){let t=/^([^/\s]+)\/([^/\s]+)\/(\d+)$/.exec(String(e||"").trim());return t?{trackId:t[1],boxId:t[2],epoch:Number(t[3])}:null}function td({trackId:e,boxId:t,epoch:n=0,provider:r=null,model:o=null}){let s=[],a=r?Vj[r]:null;return a&&s.push(a),s.push(`${vA}: ${da({trackId:e,boxId:t,epoch:n})}`),o&&s.push(`${SA}: ${String(o).trim()}`),s}function yA(e){let t={epoch:null,model:null,provider:null,cause:null};for(let n of String(e||"").split(`
190
+ `)){let r=n.trim(),o=/^([A-Za-z-]+):\s*(.+)$/.exec(r);if(!o)continue;let s=o[1].toLowerCase(),a=o[2].trim();if(s===vA.toLowerCase()&&!t.epoch)t.epoch=Qu(a);else if(s===SA.toLowerCase()&&!t.model)t.model=a;else if(s===AA.toLowerCase()&&!t.cause){let i=a.toLowerCase();Yi.includes(i)&&(t.cause=i)}else if(s==="co-authored-by"||s==="made-with"){let i=a.toLowerCase();t.provider||(i.startsWith("claude")?t.provider="claude":i.startsWith("codex")?t.provider="codex":i.startsWith("cursor")&&(t.provider="cursor"))}}return t}function Jj(e,t=oo){return e<=t?"rework":"drift"}function Yj(e,{window:t=oo,end:n=Th}={}){return!Number.isFinite(e)||e<=t?1:e>=n?0:1-(e-t)/(n-t)}function nd({subject:e="",trailerCause:t=null,wallReason:n=null,fixerCategory:r=null,ciFix:o=!1}={}){let s=String(e||"");return Xj.test(s)?{cause:"defect",level:"A",basis:"revert"}:o?{cause:"defect",level:"A",basis:"ci-fix"}:t?{cause:t,level:"E",basis:`${AA} trailer`}:Qj.test(s)&&!bA.test(s)?{cause:"style",level:"C",basis:"subject"}:bA.test(s)?{cause:"defect",level:"C",basis:"subject"}:Zj.test(s)?{cause:"design",level:"C",basis:"subject: refactor"}:n==="wrong-approach"?{cause:"design",level:"C",basis:"wall label: wrong-approach"}:r==="bug-fix"?{cause:"defect",level:"C",basis:"fixer prompt: bug-fix"}:null}function _h({heuristic:e=null,subject:t="",ref:n=null,promptKind:r=null,fixerCategory:o=null,ticketKind:s=null}={}){let a=String(t||""),i=eL.exec(a),c=i?i[1].toLowerCase():null;return e&&(e.level==="A"||e.level==="E")?{intent:"fix",basis:e.basis}:s&&/^bug/i.test(s)?{intent:"fix",basis:`linked ticket: ${s}`}:c&&tL.has(c)?{intent:"fix",basis:`subject prefix: ${c}:`}:c&&nL.has(c)?{intent:"planned",basis:`subject prefix: ${c}:`}:s&&/^(story|feature|task)/i.test(s)?{intent:"planned",basis:`linked ticket: ${s}`}:e?{intent:"likely-fix",basis:e.basis}:r==="followup-go"?{intent:"planned",basis:"operator-tapped follow-up"}:kA.test(String(n||""))||kA.test(a)?{intent:"planned",basis:"blueprint item"}:o&&rL.has(o)?{intent:"planned",basis:`prompt: ${o}`}:{intent:"unknown",basis:null}}function iL(e){let t=String(e||"");return oL.some(n=>n.test(t))?"excluded":sL.some(n=>n.test(t))?"docs":aL.some(n=>n.test(t))?"config":"code"}function cL(e){let t=[],n=null,r=null;for(let o of String(e||"").split(`
191
+ `)){if(o.startsWith("diff --git ")){n={oldPath:null,newPath:null,deleted:[],added:0,binary:!1,hunks:[]},r=null,t.push(n);continue}if(n)if(o.startsWith("--- ")&&!r){let s=o.slice(4).trim();n.oldPath=s==="/dev/null"?null:s.replace(/^a\//,"")}else if(o.startsWith("+++ ")&&!r){let s=o.slice(4).trim();n.newPath=s==="/dev/null"?null:s.replace(/^b\//,"")}else if(o.startsWith("Binary files"))n.binary=!0;else if(o.startsWith("@@")){let s=/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/.exec(o);if(!s)continue;let a=Number(s[1]),i=s[2]==null?1:Number(s[2]),c=Number(s[3]),l=s[4]==null?1:Number(s[4]);i>0&&n.deleted.push([a,i]),n.added+=l,r={oldStart:a,oldCount:i,newStart:c,newCount:l,del:[],add:[]},n.hunks.push(r)}else r&&o.startsWith("-")?r.del.push(o.slice(1)):r&&o.startsWith("+")&&r.add.push(o.slice(1))}return t}function lL(e,t){let n=Ah(e),r=Ah(t);if(n===r)return 1;if(!n.length||!r.length)return 0;n.length>Zu&&(n=n.slice(0,Zu)),r.length>Zu&&(r=r.slice(0,Zu));let o=new Array(r.length+1),s=new Array(r.length+1);for(let a=0;a<=r.length;a++)o[a]=a;for(let a=1;a<=n.length;a++){s[0]=a;let i=n.charCodeAt(a-1);for(let c=1;c<=r.length;c++){let l=i===r.charCodeAt(c-1)?0:1;s[c]=Math.min(o[c]+1,s[c-1]+1,o[c-1]+l)}[o,s]=[s,o]}return 1-o[r.length]/Math.max(n.length,r.length)}function uL(e,t=TA){let n=new Set,r=e?.del||[],o=e?.add||[];for(let s=0;s<r.length;s++){let a=e.oldStart+s;if(!Ah(r[s]).length){n.add(a);continue}s<o.length&&lL(r[s],o[s])>=t&&n.add(a)}return n}function dL(e){let t=[...e].sort((r,o)=>r-o),n=[];for(let r of t){let o=n[n.length-1];o&&o[0]+o[1]===r?o[1]+=1:n.push([r,1])}return n}function pL(e){let t=new Map,n=null;for(let r of String(e||"").split(`
192
+ `)){let o=/^([0-9a-f]{40}) (\d+) (\d+)(?: (\d+))?$/.exec(r);if(o){n={sha:o[1],line:Number(o[3]),time:null},t.set(n.line,n);continue}n&&r.startsWith("committer-time ")&&(n.time=Number(r.slice(15))*1e3)}return t}async function xA(e,t){let{stdout:n}=await Sh(e,["show","-s","--format=%H%n%P%n%ct%n%s%n%B",t]),[r,o,s,a,...i]=n.split(`
193
193
  `);return{sha:r.trim(),parents:o.trim()?o.trim().split(" "):[],ts:Number(s)*1e3,subject:a??"",message:i.join(`
194
- `)}}async function dT(e,t,{fixKey:n=null,window:r=Qr,resolveOrigin:o=null,context:s={}}={}){let a=await aT(e,t);if(a.parents.length!==1)return null;let i=a.parents[0],c=rT(a.message),l=n?zu(n):c.epoch,u=l?na(l):null,{stdout:d}=await ih(e,["diff","-U0","--no-color","-M","-C",i,t]),p=zj(d),f=0,w=0,m=0,g=0,y=0,x=0,b=0,O=new Map;for(let _ of p){if(_.binary)continue;let F=_.oldPath||_.newPath||"",V=_.deleted.reduce((z,[,fe])=>z+fe,0),A=Gj(F);if(A==="excluded"){m+=V;continue}if(A==="docs"){g+=V,y+=_.added;continue}if(A==="config"){x+=V;continue}f+=_.added;let E=new Set;for(let z of _.hunks||[])for(let fe of Jj(z))E.add(fe);b+=E.size;let N=[];for(let[z,fe]of _.deleted)for(let me=z;me<z+fe;me++)E.has(me)||N.push(me);if(w+=N.length,!_.oldPath||!N.length)continue;let H;try{let z=["blame","-w","-M","-C","--line-porcelain"];for(let[fe,me]of Yj(N))z.push("-L",`${fe},${fe+me-1}`);z.push(i,"--",_.oldPath),H=Xj((await ih(e,z)).stdout)}catch{continue}for(let{sha:z,time:fe}of H.values()){let me=O.get(z)??{lines:0,time:fe};me.lines+=1,O.set(z,me)}}let $=[],C=0,L=new Map;for(let[_,{lines:F,time:V}]of O){let A=L.get(_);if(!A){try{A=await aT(e,_)}catch{A=null}L.set(_,A)}let E=A?rT(A.message):{epoch:null},N=E.epoch,H=E.provider,z=E.model;if(!N&&o){let W=await o(_,A);W?.trackId&&W?.boxId!=null&&(N={trackId:W.trackId,boxId:W.boxId,epoch:W.epoch??0},H=H??W.provider??null,z=z??W.model??null)}if(!N){C+=F;continue}let fe=Number.isFinite(V)?V:A?.ts??a.ts,me=Math.max(0,(a.ts-fe)/Rj),Se=na(N),Ae=Se===u?"self":Nj(me,r);$.push({sha:_,key:Se,trackId:N.trackId,boxId:N.boxId,epoch:N.epoch,provider:H??null,model:z??null,lines:F,ageDays:Math.round(me*100)/100,class:Ae,decay:Ae==="rework"?1:Ae==="drift"?Math.round(Pj(me,{window:r})*1e3)/1e3:0})}$.sort((_,F)=>F.lines-_.lines);let q=Yu({subject:a.subject,trailerCause:c.cause,wallReason:s.wallReason??null,fixerCategory:s.fixerCategory??null,ciFix:s.ciFix===!0}),I=dh({heuristic:q,subject:a.subject,ref:s.ref??null,promptKind:s.promptKind??null,fixerCategory:s.fixerCategory??null,ticketKind:s.ticketKind??null});return{sha:a.sha,parent:i,subject:a.subject.slice(0,200),ts:a.ts,fixKey:u,fixProvider:c.provider??s.provider??null,fixModel:c.model??s.model??null,window:r,added:f,deleted:w,excludedDeleted:m,cosmeticDeleted:b,docsDeleted:g,docsAdded:y,configDeleted:x,codeDelta:f+w+b>0,origins:$,unattributedLines:C,ghost:w===0&&f>0,heuristic:q,intent:I}}function pT(e,{minLines:t=uh}={}){if(!e)return!1;let n=e.intent?.intent??"unknown";return ra.has(n)?Ki(e)>=t:!1}function Ki(e){return(e?.origins||[]).filter(t=>t.class==="rework").reduce((t,n)=>t+n.lines,0)}function ah(e){let t=e.genUsd;return{...e,genUsd:dn(t),reworkChargedUsd:dn(e.reworkChargedUsd),reworkPendingUsd:dn(e.reworkPendingUsd),trueUsd:dn(t+e.reworkChargedUsd),multiplier:t>0?dn((t+e.reworkChargedUsd)/t):null}}function fT(e,{window:t=Qr,boxMeta:n={}}={}){let r=e||[],o=r.filter(I=>I.type==="cost.recorded"),s=r.filter(I=>I.type==="code.committed"),a=r.filter(I=>I.type==="code.rework"),i=I=>Array.isArray(I?.shas)&&I.shas.length?I.shas:I?.sha?[I.sha]:[],c=new Map,l=new Set;for(let I of r)if(I.type==="rework.cause.offered")for(let _ of i(I.payload))l.add(_);else if(I.type==="rework.cause.answered"&&I.payload?.cause)for(let _ of i(I.payload))c.set(_,I.payload.cause);else if(I.type==="rework.cause.retracted")for(let _ of i(I.payload))c.delete(_);let u={},d=(I,_,F)=>na({trackId:I,boxId:_,epoch:F??0}),p=(I,_={})=>{if(!u[I]){let V=zu(I)||{};u[I]={key:I,...V,provider:null,model:null,...sh()}}let F=u[I];return _.provider&&!F.provider&&(F.provider=_.provider),_.model&&!F.model&&(F.model=_.model),F};for(let I of o){if(!I.boxId)continue;let _=d(I.trackId,I.boxId,I.epoch),{usd:F,model:V}=Kt(I),A=p(_,{provider:I.provider,model:V!=="unknown"?V:null});A.genUsd+=F}let f=new Map;for(let I of s){let _=`${I.trackId}/${I.boxId}`;(f.get(_)??f.set(_,[]).get(_)).push({...I,ts:I.payload?.ts??I.ts})}for(let I of f.values())I.sort((_,F)=>_.ts-F.ts);let w=(I,_,F,V)=>{let A=f.get(`${I}/${_}`)||[],E=-1/0;for(let z of A)z.ts<V&&(E=z.ts);let N=0,H=0;for(let z of o)z.trackId!==I||z.boxId!==_||(z.epoch??0)===(F??0)&&(z.ts<=E||z.ts>V||(N+=Kt(z).usd,H++));return{usd:N,turns:H,from:Number.isFinite(E)?E:null}},m={charged:0,pending:0,self:0,decayed:0,unattributed:0,ghost:0,planned:0},g={A:0,B:0,C:0,E:0,none:0},y={fix:0,"likely-fix":0,planned:0,unknown:0},x=0,b=[],O=[],$={},C={},L=new Set;for(let I of a){let _=I.payload||{};if(!_.sha||L.has(_.sha))continue;if(L.add(_.sha),_.codeDelta===!1){x++;continue}let F=zu(_.fixKey)||{trackId:I.trackId,boxId:I.boxId,epoch:I.epoch??0},{usd:V,turns:A}=w(F.trackId,F.boxId,F.epoch,_.ts??I.ts),E=Mj.includes(_.intent?.intent)?_.intent.intent:"unknown";y[E]+=1;let N=null;c.has(_.sha)?N={cause:c.get(_.sha),level:"B",basis:"operator"}:(_.heuristic?.level&&_.heuristic.level!=="C"||_.heuristic)&&(N=_.heuristic);let H=N?.level??"none";g[H]=(g[H]||0)+1;let z=Oj.has(H),fe=Number(_.deleted)||0,me=Array.isArray(_.origins)?_.origins:[],Se=me.filter(W=>W.class==="rework").reduce((W,te)=>W+te.lines,0),Ae={sha:_.sha,subject:_.subject??"",ts:_.ts??I.ts,trackId:I.trackId,fixKey:_.fixKey??null,fixProvider:_.fixProvider??I.provider??null,fixUsd:dn(V),fixTurns:A,linesReworked:Se,unattributedLines:Number(_.unattributedLines)||0,ghost:_.ghost===!0,intent:{intent:E,basis:_.intent?.basis??null},verdict:N?{cause:N.cause,level:H,basis:N.basis??null}:null,charged:dn(0),origins:[]};if(E==="planned"||N?.cause===Vu){m.planned+=V;for(let W of me)W.class==="rework"&&Ae.origins.push({key:W.key,provider:W.provider??null,model:W.model??null,lines:W.lines,ageDays:W.ageDays,class:W.class,usd:0})}else if(_.ghost||fe===0)m.ghost+=V;else{let W=0;for(let le of me){let J=le.lines/fe,ye=V*J;if(W+=ye,le.class==="self"){m.self+=ye;continue}let Ce=le.class==="rework"?1:Number(le.decay)||0,Ne=ye*Ce;if(m.decayed+=ye-Ne,Ne<=0)continue;let R=p(le.key,{provider:le.provider,model:le.model});R.fixes+=1,R.linesReworked+=le.class==="rework"?le.lines:0;let D=N?.cause&&Wi.includes(N.cause)?N.cause:"unclassified";R.causes[D]+=1,z?(R.reworkChargedUsd+=Ne,m.charged+=Ne,Ae.charged=dn(Ae.charged+Ne)):(R.reworkPendingUsd+=Ne,m.pending+=Ne),Ae.origins.push({key:le.key,provider:R.provider,model:R.model,lines:le.lines,ageDays:le.ageDays,class:le.class,usd:dn(Ne)})}let te=Math.max(0,V-W);m.unattributed+=te}b.push(Ae),!c.has(_.sha)&&l.has(_.sha)&&O.push(_.sha)}for(let I of Object.values(u)){let _=I.provider||"unknown",F=I.model||"unknown",V=A=>{A.genUsd+=I.genUsd,A.reworkChargedUsd+=I.reworkChargedUsd,A.reworkPendingUsd+=I.reworkPendingUsd,A.linesReworked+=I.linesReworked,A.fixes+=I.fixes;for(let E of Object.keys(A.causes))A.causes[E]+=I.causes[E]};V($[_]||=sh()),V(C[F]||=sh())}b.sort((I,_)=>_.ts-I.ts);let q=Object.values(u).map(I=>{let _=n[`${I.trackId}/${I.boxId}`]||{};return ah({...I,trackName:_.trackName??null,label:_.label??null})}).sort((I,_)=>_.reworkChargedUsd+_.reworkPendingUsd-(I.reworkChargedUsd+I.reworkPendingUsd)||_.genUsd-I.genUsd);return{window:t,basis:`rework = code lines a fix deletes/modifies that blame to another epoch's commit \u2264${t} d old (docs/config churn and in-place updates \u2265${uT} similar are counted, not blamed); fix cost = the fixing box's turns since its previous commit; charged only on an authoritative / operator / self-reported cause; planned work (follow-up, blueprint item, feat:/docs: prefix, non-fix prompt) is generation cost`,intents:y,noCodeDelta:x,byEpoch:Object.fromEntries(q.map(I=>[I.key,I])),epochs:q,byProvider:Object.fromEntries(Object.entries($).map(([I,_])=>[I,ah(_)])),byModel:Object.fromEntries(Object.entries(C).map(([I,_])=>[I,ah(_)])),buckets:Object.fromEntries(Object.entries(m).map(([I,_])=>[I,dn(_)])),fixUsdTotal:dn(Object.values(m).reduce((I,_)=>I+_,0)),fixes:b,verdicts:g,pendingTaps:O,commits:s.length}}var Ij,$j,ih,iT,cT,lT,Rj,Qr,lh,uh,Wi,Vu,Oj,Mj,ra,uT,Cj,Dj,oT,Bj,jj,Lj,Fj,Uj,sT,Hj,qj,Wj,Kj,ch,Gu,dn,sh,Xu=G(()=>{Lr();Ij=_j(Ej),$j=64*1024*1024,ih=(e,t)=>Ij("git",["-C",e,...t],{maxBuffer:$j,timeout:6e4}),iT="Bostrat-Epoch",cT="Bostrat-Model",lT="Bostrat-Fix-Cause",Rj=24*36e5,Qr=Number(process.env.BOSTRAT_REWORK_WINDOW_DAYS)||21,lh=90,uh=3,Wi=Object.freeze(["defect","design","requirements","style"]),Vu="not-a-fix",Oj=new Set(["A","B","E"]),Mj=Object.freeze(["fix","likely-fix","planned","unknown"]),ra=new Set(["fix","likely-fix"]),uT=.8;Cj={claude:"Co-Authored-By: Claude <noreply@anthropic.com>",codex:"Co-authored-by: Codex <noreply@openai.com>",cursor:"Made-with: Cursor"};Dj=/^revert\b|^revert "/i,oT=/\b(fix(es|ed)?|bug|hotfix|regression|crash|broken|npe|null ?pointer|off[- ]by[- ]one|leak)\b/i,Bj=/\b(refactor|rearchitect|re-architect|restructure|rework|rewrite|redesign|simplif(y|ied)|clean ?up)\b/i,jj=/\b(lint|format(ting)?|prettier|typo|whitespace|rename)\b/i;Lj=/^([a-z]+)(\([^)]*\))?!?:\s/i,Fj=new Set(["fix","hotfix","bugfix","revert"]),Uj=new Set(["feat","feature","docs","doc","test","tests","build","ci","chore"]),sT=/\bBP-[A-Z]*\d+\b/i,Hj=new Set(["feature-build","docs-writing","research","design","ops-infra","orchestration"]);qj=[/(^|\/)\.bostrat\//,/(^|\/)(package-lock\.json|yarn\.lock|pnpm-lock\.yaml|Cargo\.lock|poetry\.lock|Gemfile\.lock|go\.sum|composer\.lock)$/,/\.min\.(js|css)$/,/\.map$/,/\.snap$/,/(^|\/)(node_modules|dist|build|vendor|\.next|target)\//],Wj=[/\.(md|mdx|markdown|rst|txt|adoc|asciidoc)$/i,/(^|\/)(docs?|notes|business|design)\//i,/(^|\/)(README|CHANGELOG|CHANGES|LICENSE|CONTRIBUTING|AUTHORS|NOTICE)(\.[a-z]+)?$/i],Kj=[/\.(json|jsonc|json5|ya?ml|toml|ini|cfg|conf|properties|env|example)$/i,/(^|\/)\.[^/]+$/,/(^|\/)\.github\//,/(^|\/)(Dockerfile|Makefile|Procfile|fly\.toml)$/];ch=e=>String(e??"").replace(/\s+/g," ").trim(),Gu=400;dn=e=>Math.round(e*1e4)/1e4,sh=()=>({genUsd:0,reworkChargedUsd:0,reworkPendingUsd:0,linesReworked:0,fixes:0,causes:{defect:0,design:0,requirements:0,style:0,unclassified:0}})});import{execFile as Zj}from"node:child_process";import{promisify as Qj}from"node:util";function mT(e,t=Date.now()){return Vp(e,t)??0}function tL(e,t,n){for(let r=e.length-1;r>=0;r--){let o=e[r];if(o.type!=="cost.recorded"||o.boxId!==t||n!=null&&o.epoch!=null&&o.epoch!==n)continue;let s=o.payload?.model;if(s&&s!=="unknown")return s}return null}async function hT(e,t,{now:n=Date.now()}={}){let r=mT(t,n),o=await K(e);return Ju({trackId:e.id,boxId:t.name,epoch:r,provider:t.agent??null,model:tL(o,t.name,r)})}function nL(e,t){let n=null;for(let r=e.length-1;r>=0;r--){let o=e[r];if(o.type!=="turn.user"||o.boxId!==t||o.actor!=="user")continue;let s=o.payload||{};if(s.note?.kind!=="task"){if(o.source==="orchestrator"&&typeof s.text=="string"&&s.text.trim())return{text:s.text,kind:s.kind??null};!n&&typeof s.promptHead=="string"&&s.promptHead.trim()&&(n={text:s.promptHead,kind:s.kind??null})}}return n}function rL(e,t,n,r){let o=Array.isArray(t?.epochs)?t.epochs:[],s=r>0?o[r-1]:null,a=s?.endReason?.code??(typeof s?.endReason=="string"?s.endReason:null),i=nL(n,t.name),c=i?Zn(i.text)?.category??null:null;return{wallReason:a,fixerCategory:c,promptKind:i?.kind??null}}async function oL(e,t){try{let{stdout:n}=await ph(e,["show","--shortstat","--format=",t]),r=/(\d+) files? changed/.exec(n),o=/(\d+) insertions?\(\+\)/.exec(n),s=/(\d+) deletions?\(-\)/.exec(n);return{files:r?Number(r[1]):0,insertions:o?Number(o[1]):0,deletions:s?Number(s[1]):0}}catch{return{files:0,insertions:0,deletions:0}}}async function sL(e){try{let{stdout:t}=await ph(e,["rev-parse","--abbrev-ref","HEAD"]);return t.trim()||null}catch{return null}}async function wT(e,t,n,{cwd:r=t?.cwd,log:o=console,now:s=Date.now()}={}){if(!e?.id||!t?.name||!n||!r)return{recorded:!1,reason:"incomplete"};let a=await K(e);if(a.some(w=>w.type==="code.committed"&&w.payload?.sha===n))return{recorded:!1,reason:"duplicate"};let i=s;try{let{stdout:w}=await ph(r,["show","-s","--format=%ct",n]),m=Number(w.trim())*1e3;Number.isFinite(m)&&m>0&&(i=m)}catch{return{recorded:!1,reason:"unknown-sha"}}let c=mT(t,i),l=await oL(r,n),u=await sL(r),d=await M(e,{type:"code.committed",actor:"agent",source:"hook",boxId:t.name,provider:t.agent??null,payload:{sha:n,ref:u,...l,ts:i}}),p=null,f=!1;try{let w=await dT(r,n,{fixKey:na({trackId:e.id,boxId:t.name,epoch:c}),window:Qr,context:{...rL(e,t,a,c),ref:u,provider:t.agent??null}});if(w&&(p=await M(e,{type:"code.rework",actor:"system",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:d.id,payload:w}),!(e?.workspace?.kind==="worktree"&&!!e?.workspace?.branch)&&pT(w))){let g=Ki(w),y=w.origins.filter(x=>x.class==="rework").slice(0,3);await M(e,{type:"rework.cause.offered",actor:"orchestrator",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:p.id,payload:{sha:n,subject:w.subject,linesReworked:g,origins:y.map(x=>({key:x.key,provider:x.provider,model:x.model,lines:x.lines,ageDays:x.ageDays})),heuristic:w.heuristic,intent:w.intent,ts:i}}),f=!0}}catch(w){o.warn?.(`[rework] ${e.id}: analysis of ${String(n).slice(0,7)} failed: ${w?.message||w}`)}return{recorded:!0,event:d,rework:p,offered:f}}function gT(e,t){let n=0;for(let r of e)r.payload?.sha===t&&(r.type==="rework.cause.answered"?n++:r.type==="rework.cause.retracted"&&n--);return n>0}async function yT(e,t,n){if(!Wi.includes(n)&&n!==Vu)throw new Error(`bad cause "${n}" (${Wi.join("|")}|${Vu})`);let r=await K(e),o=r.find(s=>s.type==="rework.cause.offered"&&s.payload?.sha===t);if(!o)throw new Error("unknown rework offer");if(gT(r,t))throw new Error("already answered");return M(e,{type:"rework.cause.answered",actor:"user",source:"orchestrator",boxId:o.boxId??null,causationId:o.id,payload:{sha:t,...Array.isArray(o.payload?.shas)?{shas:o.payload.shas}:{},cause:n,level:"B",ts:Date.now()}})}async function bT(e,t){let n=await K(e);if(!gT(n,t))throw new Error("no standing answer to retract");let r=[...n].reverse().find(o=>o.type==="rework.cause.answered"&&o.payload?.sha===t);return M(e,{type:"rework.cause.retracted",actor:"user",source:"orchestrator",boxId:r?.boxId??null,causationId:r?.id,payload:{sha:t,...Array.isArray(r?.payload?.shas)?{shas:r.payload.shas}:{},ts:Date.now()}})}async function Zu(e,{repo:t=null,number:n,title:r="",branch:o=null,url:s=null}={},{log:a=console,now:i=Date.now()}={}){try{if(!e?.id||n==null)return{offered:!1,reason:"incomplete"};let c=await K(e);if(c.some(x=>x.type==="rework.cause.offered"&&x.payload?.pr?.number===n&&(t==null||x.payload.pr.repo===t)))return{offered:!1,reason:"duplicate"};let l=new Set;for(let x of c)if(x.type==="rework.cause.offered")for(let b of Array.isArray(x.payload?.shas)?x.payload.shas:[x.payload?.sha])b&&l.add(b);let u=new Map;for(let x of c)x.type==="code.committed"&&x.payload?.sha&&u.set(x.payload.sha,x.payload.ref??null);let d=dh({heuristic:Yu({subject:r}),subject:r,ref:o}),p=[];for(let x of c){if(x.type!=="code.rework")continue;let b=x.payload||{};if(!b.sha||l.has(b.sha)||b.codeDelta===!1||o&&u.has(b.sha)&&u.get(b.sha)!==o)continue;let O=b.intent?.intent??"unknown";(ra.has(O)||O==="unknown"&&ra.has(d.intent))&&Ki(b)!==0&&p.push(b)}let f=p.reduce((x,b)=>x+Ki(b),0);if(f<uh)return{offered:!1,reason:"below-threshold"};let w=new Map;for(let x of p)for(let b of x.origins??[]){if(b.class!=="rework")continue;let O=w.get(b.key)??{key:b.key,provider:b.provider??null,model:b.model??null,lines:0,ageDays:b.ageDays};O.lines+=b.lines,O.ageDays=Math.min(O.ageDays,b.ageDays),w.set(b.key,O)}let m=p.map(x=>x.sha),g=p.map(x=>x.heuristic).find(x=>x&&x.level!=="C")??Yu({subject:r})??p.map(x=>x.heuristic).find(Boolean)??null,y=ra.has(d.intent)?d:p.find(x=>ra.has(x.intent?.intent))?.intent??d;return await M(e,{type:"rework.cause.offered",actor:"orchestrator",source:"orchestrator",boxId:null,payload:{sha:m[m.length-1],shas:m,pr:{repo:t,number:n,title:String(r||"").slice(0,200),url:s,branch:o},subject:String(r||"").slice(0,200)||p[p.length-1].subject,linesReworked:f,origins:[...w.values()].sort((x,b)=>b.lines-x.lines).slice(0,3),heuristic:g,intent:y,ts:i}}),{offered:!0,shas:m}}catch(c){return a.warn?.(`[rework] ${e?.id}: PR-level offer for #${n} failed: ${c?.message||c}`),{offered:!1,reason:"error"}}}var eL,ph,Qu=G(()=>{de();Zl();Xu();eL=Qj(Zj),ph=(e,t)=>eL("git",["-C",e,...t],{maxBuffer:16*1024*1024,timeout:3e4})});import{execFile as aL}from"node:child_process";import{promisify as iL}from"node:util";async function fh(e,t,{midTurn:n=Ho,pollMs:r=cL,capMs:o=lL}={}){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 AT(e){let t=String(e||""),n=0;for(let r=0;r<64;r++){kT.lastIndex=n;let o=kT.exec(t);if(!o)break;n=o.index+o[0].length;let s=o[1]==="-",a=o[2]??o[3]??o[4],i=t.indexOf(`
195
- `,o.index);if(i<0)break;let l=new RegExp("^"+(s?"\\t*":"")+wL(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 mh(e,t){return e.slice(t).replace(/^[\s;&|)]+/,"").replace(/"[^"]*"|'[^']*'/g,'""').split(/[;&|\n]/)[0]}function _T(e){let t=AT(e),n=t.match(fL);if(!n)return null;let r=mh(t,n.index);return hL.test(r)?null:{repo:r.match(ET)?.[1]??null,head:r.match(gL)?.[1]??null}}function IT(e){let t=AT(e),n=t.match(mL);if(!n)return null;let r=mh(t,n.index),o=mh(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("-")){bL.has(c)&&i++;continue}s=c.replace(/^["']+|["']+$/g,"")||null;break}return{repo:r.match(ET)?.[1]??null,selector:s,auto:/\s--auto\b/.test(r)}}async function xL(e,t,{exclude:n=()=>!1}={}){let r=async i=>{rr("observer");let{stdout:c}=await xT("gh",["pr","list","--repo",e,"--author","@me","--state","all","--limit","10","--json",kL],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...i}}).catch(l=>{throw Yr(l)&&Xr(l),l});return JSON.parse(c||"[]")},o=i=>(i||[]).filter(c=>Date.parse(c.createdAt)>=t-uL&&!n(c)),s=await vn({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 vL(e,t){if(t)return[t];let n=[];for(let r of $T(e)){let o=await _e(r).catch(()=>null);o&&!n.includes(o)&&n.push(o)}for(let r of await Jn().catch(()=>[])){let o=await _e(r.path).catch(()=>null);o&&!n.includes(o)&&n.push(o)}return n}function $T(e){let t=e.workspace;return t?.kind==="multi"?(t.repos??[]).map(n=>n?.base).filter(Boolean):[t?.base||e.cwd].filter(Boolean)}async function SL(e,t,n){let r=await ta(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)||yL(c.headRefName,e.id),i=[];for(let c of await vL(e,t?.repo??null)){let l;try{l=await xL(c,n,{exclude:a})}catch{continue}for(let u of l){let d=await at(c,u.number);if(s(u.headRefName)){if(d&&d.trackId===e.id&&d.announced)return{settled:!0};if(d&&d.trackId!==e.id)continue;return{slug:c,pr:u}}d&&(d.trackId!==e.id||d.announced)||i.push({slug:c,pr:u})}}return i.length?(i.sort((c,l)=>Date.parse(l.pr.createdAt)-Date.parse(c.pr.createdAt)),i[0]):null}function RT(e){if(!e)return 0;let t=0;for(let n of sr)n.startsWith(`${e}|`)&&t++;return t}function OT(){for(let e of[...hh])e()}function MT(e,t,{delays:n=vT,turnEnd:r}={}){let o=_T(t.command);if(!o)return null;let s=!!IT(t.command),a=`${e.id}|${t.id??t.ts??t.command}`;if(sr.has(a))return null;sr.add(a);let i=t.ts??Date.now(),c=(async()=>{try{for(let l of n){await new Promise(m=>{let g=()=>{clearTimeout(y),hh.delete(g),m()},y=setTimeout(g,l);hh.add(g)});let u=await SL(e,o,i).catch(()=>null);if(u?.settled)return null;if(!u)continue;let{slug:d,pr:p}=u,{link:f,created:w}=await Mt({repo:d,number:p.number,trackId:e.id,url:p.url,headRef:p.headRefName,title:p.title,source:"observed"});return!w&&!(f?.trackId===e.id&&await tr(d,p.number))?null:(await fh(t.box,t.agent,r),await M({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Date.now(),change:"opened",number:p.number,url:p.url,title:p.title,branch:p.headRefName,repo:d,...s?{selfMerge:!0}:{}}}),p)}return null}finally{sr.delete(a)}})();return c.catch(()=>sr.delete(a)),c}function CT(e,t,{delays:n=vT,turnEnd:r,openedWait:o}={}){let s=IT(t.command);if(!s)return null;let a=`merge|${e.id}|${t.id??t.ts??t.command}`;if(sr.has(a))return null;sr.add(a);let i=(async()=>{try{let c=s.repo,l=s.selector,u=l?.match(/github\.com\/([\w.-]+\/[\w.-]+)\/pull\/(\d+)/);u&&([,c,l]=u);let d=[];if(c)d=[c];else{let w=$T(e);if(w.length>1&&/^\d+$/.test(String(s.selector??"")))return null;for(let m of w){let g=await _e(m).catch(()=>null);g&&!d.includes(g)&&d.push(g)}}if(l||=(await ta(e).catch(()=>[])).filter(w=>w!==e.workspace?.branch)[0]||e.workspace?.branch,!d.length||!l)return null;c=d[0];let p=async(w,m)=>{let g=await at(c,w.number);return g&&g.trackId!==e.id?null:(g||await Mt({repo:c,number:w.number,trackId:e.id,url:w.url,headRef:w.headRefName,title:w.title,source:"merge-observed"}),await Pi(c,w.number),m&&((await K(e).catch(()=>[])).some(b=>b.type==="pr.state.changed"&&(b.payload?.change==="auto-armed"||b.payload?.change==="merged")&&b.payload?.number===w.number)||(await fh(t.box,t.agent,r),await M({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Date.now(),change:"auto-armed",number:w.number,url:w.url,title:w.title,branch:w.headRefName,repo:c}}))),w)},f=null;for(let w of n){await new Promise(C=>setTimeout(C,w));let m=[];for(let C of d)try{rr("observer");let{stdout:L}=await xT("gh",["pr","view",String(l),"--repo",C,"--json",TL],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...await vn({slug:C})}}),q=JSON.parse(L||"null");q?.number&&m.push({slug:C,pr:q})}catch(L){Yr(L)&&Xr(L)}let g=m.find(C=>C.pr.state==="MERGED")??(m.length===1?m[0]:null);if(!g)continue;c=g.slug;let y=g.pr;if(!y?.number)continue;if(y.state==="CLOSED")return null;if(y.state!=="MERGED"){if(f=y,s.auto)return p(y,!0);continue}let x=await at(c,y.number);if(x&&x.trackId!==e.id)return null;x||await Mt({repo:c,number:y.number,trackId:e.id,url:y.url,headRef:y.headRefName,title:y.title,source:"merge-observed"}),await fh(t.box,t.agent,r);let b=await K(e).catch(()=>[]);if(b.some(C=>C.type==="pr.state.changed"&&C.payload?.change==="merged"&&C.payload?.number===y.number))return null;let O=C=>C.some(L=>L.type==="pr.state.changed"&&L.payload?.change==="opened"&&L.payload?.number===y.number),$=0;if(!O(b)){if(_T(t.command)&&await tr(c,y.number)){let C=Date.now();$=C+1,await M({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:C,change:"opened",number:y.number,url:y.url,title:y.title,branch:y.headRefName,repo:c,selfMerge:!0}})}else if((await at(c,y.number))?.announced){let C=o?.capMs??dL,L=o?.pollMs??pL,q=Date.now()+C;for(;Date.now()<q&&(await new Promise(I=>setTimeout(I,L)),!O(await K(e).catch(()=>[]))););}}return await M({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Math.max(Date.now(),$),change:"merged",number:y.number,url:y.url,title:y.title,branch:y.headRefName,repo:c}}),await Zu(e,{repo:c,number:y.number,title:y.title,branch:y.headRefName,url:y.url}).catch(()=>{}),await ir(c,y.number).catch(()=>{}),await ar(c,y.number).catch(()=>{}),await Vr(c,y.number,"merged"),y}return f?p(f,!1):null}finally{sr.delete(a)}})();return i.catch(()=>sr.delete(a)),i}var xT,vT,cL,lL,uL,dL,pL,ST,TT,fL,mL,hL,kT,wL,ET,gL,yL,bL,kL,sr,hh,TL,ed=G(()=>{de();Tr();pt();Bi();Rn();cr();qi();qo();Qu();xT=iL(aL),vT=[4e3,15e3,45e3],cL=2500,lL=5*6e4;uL=15e3,dL=9e4,pL=2e3,ST=/(?:^|[;&|\n({`]\s*|\)\s*)(?:(?:then|do|else|elif|if|while|until|time)\s+)?/.source,TT=/gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+/.source,fL=new RegExp(`${ST}${TT}create\\b`),mL=new RegExp(`${ST}${TT}merge\\b`),hL=/\s--web\b/,kT=/<<(-?)\s*(?:'([^'\n]+)'|"([^"\n]+)"|\\?([A-Za-z_][\w-]*))/g,wL=e=>e.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");ET=/(?:--repo|-R)[\s=]+([\w.-]+\/[\w.-]+)/,gL=/(?:--head|-H)[\s=]+([^\s"'`;&|]+)/,yL=nT;bL=new Set(["--subject","-t","--body","-b","--body-file","-F","--match-head-commit","--author-email","-A","--repo","-R"]);kL="number,url,title,headRefName,createdAt";sr=new Set;hh=new Set;TL="number,url,title,headRefName,state"});import AL from"node:fs/promises";import gh from"node:path";import EL from"node:os";function wh(e,t){let n=new RegExp(`\\b${t}="([^"]*)"`).exec(e);return n?n[1]:null}function td(e){let t=_L.exec(String(e||""));if(!t)return null;let[,n,r]=t,o=wh(n,"from"),s=o?o.replace(/^uds:/,""):null,a=NT(s);return{socket:s,pid:a,name:wh(n,"from-name"),mode:wh(n,"from-mode"),text:r.trim()}}function NT(e){let t=/(\d+)\.sock$/.exec(String(e||""));return t?Number(t[1]):null}function IL(){return process.env.CLAUDE_CONFIG_DIR?gh.join(process.env.CLAUDE_CONFIG_DIR,"sessions"):gh.join(EL.homedir(),".claude","sessions")}async function $L(e){let t=NT(e);if(!t)return null;try{let n=await AL.readFile(gh.join(IL(),`${t}.json`),"utf8"),r=JSON.parse(n);return{pid:t,sessionId:r.sessionId??null,cwd:r.cwd??null,name:r.name??null,tmux:r.tmux??null}}catch{return null}}async function PT(e,t){let n=await $L(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 _L,yh=G(()=>{_L=/<cross-session-message\b([^>]*)>([\s\S]*?)<\/cross-session-message>/});function bh(e=process.env){return!!(Re(e)&&e.BOSTRAT_PLANE_TOKEN)}async function kh({loopId:e,outcome:t,note:n=null,env:r=process.env}={}){if(!bh(r))return{ok:!1,source:"unconfigured"};let o=new AbortController,s=setTimeout(()=>o.abort(),DT);try{let a=await BT(`${Re(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 jT(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(!bh(s))return{ok:!1,source:"unconfigured"};let i=nd.get(e.id)||0;if(a()-i<RL)return{ok:!1,source:"debounced"};nd.set(e.id,a());let c=await Gi({env:s}),l=c.loops.find(p=>p.trackId===e.id);if(!l)return nd.delete(e.id),{ok:!1,source:c.source==="plane"?"no-loop":c.source};let u=`${t||"provider"} ${r?r+" ":""}${n}: ${String(o||"").replace(/\s+/g," ").trim()}`.slice(0,500),d=await kh({loopId:l.id,outcome:"errored",note:u,env:s});return d.ok||nd.delete(e.id),{...d,loop:{id:l.id,name:l.name}}}async function Gi({env:e=process.env}={}){if(!bh(e))return{loops:[],source:"unconfigured"};let t=new AbortController,n=setTimeout(()=>t.abort(),DT);try{let r=await BT(`${Re(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 DT,BT,RL,nd,xh=G(()=>{pt();DT=1e4,BT=(...e)=>fetch(...e);RL=10*6e4,nd=new Map});function LT(e=process.env){return!!(Re(e)&&e.BOSTRAT_PLANE_TOKEN)}async function FT(e,t,n=vh){let r=new AbortController,o=setTimeout(()=>r.abort(),n);try{return await ML(`${Re(t)}${e}`,{headers:CL(t),signal:r.signal})}finally{clearTimeout(o)}}async function zi({env:e=process.env,force:t=!1,timeoutMs:n=vh}={}){if(!LT(e))return{followups:[],source:"unconfigured"};if(!t&&Wo&&Date.now()-Wo.at<OL)return{followups:Wo.followups,source:"cache"};try{let r=await FT("/v1/followups?deleted=1",e,n);if(!r.ok)throw new Error(`plane ${r.status}`);let o=await r.json(),s=Array.isArray(o?.followups)?o.followups:[];return Wo={at:Date.now(),followups:s},{followups:s,source:"plane"}}catch(r){return Wo?{followups:Wo.followups,source:"stale",error:r?.message}:{followups:[],source:"unreachable",error:r?.message}}}async function UT(e,{env:t=process.env,timeoutMs:n=vh}={}){if(!e)return{followup:null,source:"unconfigured"};if(!LT(t))return{followup:null,source:"unconfigured"};try{let r=await FT(`/v1/followups/${encodeURIComponent(e)}`,t,n);if(r.status===404)return{followup:null,source:"gone"};if(!r.ok)throw new Error(`plane ${r.status}`);return{followup:(await r.json())?.followup??null,source:"plane"}}catch(r){let o=Wo?.followups.find(s=>s.id===e)??null;return o?{followup:o,source:"stale",error:r?.message}:{followup:null,source:"unreachable",error:r?.message}}}var OL,vh,Wo,ML,CL,HT=G(()=>{pt();OL=6e4,vh=5e3,Wo=null,ML=(...e)=>fetch(...e);CL=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});async function eo(e,t){if(Sh.has(e)){let n=new Error("offer already answered (answer in flight)");throw n.code="answer-in-flight",n}Sh.add(e);try{return await t()}finally{Sh.delete(e)}}var Sh,Vi=G(()=>{Sh=new Set});import{randomUUID as sa,createHash as NL}from"node:crypto";function GT(e){return String(e||"").toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}function LL(e){for(let[t,n]of jL)if(t.test(String(e||"")))return`a standing prompt must not embed this Track's specifics (${n}) \u2014 the card supplies them at fire time; arm a one-shot with \`offer\` instead`;return null}function zT(e,{standing:t=!1}={}){let n=e&&typeof e=="object"?e:{},r=oa(n.label).replace(/\s+/g," ");if(!r)throw new Error('label required (\u226460 chars, e.g. "Deploy to Pi")');if(r.length>qT)throw new Error(`label must be \u2264${qT} characters`);let o=oa(n.trigger)||(n.ship?"now":""),s=t?DL:KT.filter(u=>u!=="track.opened");if(!s.includes(o))throw new Error(`trigger must be one of ${s.join(" | ")}${t?" (a standing follow-up can't be `now` \u2014 it would fire every turn)":""}, got "${n.trigger??""}"`);let a=n.ship&&o==="now"?UL(n.ship):null,i=oa(n.prompt);if(!a&&!i)throw new Error("prompt required \u2014 the full instruction a fresh session could execute");if(Buffer.byteLength(i,"utf8")>WT)throw new Error(`prompt must be \u2264${WT} bytes`);if(t){let u=LL(i);if(u)throw new Error(u)}let c=oa(n.why).slice(0,PL)||null,l=t?FL(n.repo):null;return{label:r,prompt:i,trigger:o,why:c,...l?{repo:l}:{},...a?{ship:a}:{}}}function FL(e){if(e==null||e===""||e==="*")return null;let t=String(e).trim();if(!/^[\w.-]+\/[\w.-]+$/.test(t))throw new Error(`repo must be a forge slug like owner/name, got "${e}"`);return t}function UL(e){let t=e&&typeof e=="object"?e:{},n=Array.isArray(t.actions)?t.actions.map(i=>String(i).trim().toLowerCase()):Th.slice();for(let i of n)if(!Th.includes(i))throw new Error(`ship.actions may only contain ${Th.join(" | ")}, got "${i}"`);if(!n.length)throw new Error("ship.actions must name at least one of commit | push | pr");let r=t.rebase==null?"none":String(t.rebase).trim();if(!["offered","none"].includes(r))throw new Error(`ship.rebase must be "offered" or "none", got "${t.rebase}"`);let o=null;if(t.toPr!=null&&t.toPr!==""){let i=Number(t.toPr);if(!Number.isInteger(i)||i<=0)throw new Error(`ship.toPr must be a PR number, got "${t.toPr}"`);o=i}let s=oa(t.base)||null,a=null;if(t.repos!=null){if(!Array.isArray(t.repos))throw new Error("ship.repos must be an array of checkout names");a=t.repos.map(i=>oa(i)).filter(Boolean),a.length||(a=null)}return{actions:[...new Set(n)],rebase:r,toPr:o,base:s,repos:a}}function rd(e,{trigger:t=null}={}){let n=new Map;for(let r of e){let o=r.payload||{};if(r.type==="followup.armed"&&o.armId)o.replaces&&n.delete(o.replaces),n.set(o.armId,{...o,ts:o.ts??r.ts,boxId:r.boxId??null,provider:r.provider??null});else if(r.type==="followup.armed.cancelled"&&o.armId)n.delete(o.armId);else if(r.type==="followup.offered")for(let s of o.rows||[])s.armId&&n.delete(s.armId)}return[...n.values()].filter(r=>!t||r.trigger===t)}async function VT(e,t,{pull:n=zi,ship:r={}}={}){if(_h(e))throw new Error("follow-ups don't fire on a loop's run Track \u2014 report the outcome with `bostrat-loop report` instead");let o=zT(t);if(o.ship)return{kind:"ship",...await KL(e,o,r)};let s={id:e.id,cwd:e.cwd},a=(e.boxes||[]).find(g=>g.name===e.leadBox)||null,i={boxId:e.leadBox??null,provider:a?.agent??null};if(o.trigger==="now"){let g=sa(),y=sa();return await M(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:{ts:Date.now(),armId:g,trigger:"now",label:o.label,prompt:o.prompt,why:o.why}}),await M(s,{type:"followup.offered",actor:"system",source:"orchestrator",...i,payload:{ts:Date.now(),offerId:y,trigger:"now",repo:e.workspace?.repo||null,context:{},rows:[{armId:g,label:o.label,prompt:o.prompt,promptHash:Ah(o.prompt),origin:"agent",why:o.why}]}}),{kind:"now",armId:g,offerId:y,...o}}let c=e.workspace?.repo||null,{followups:l}=await n().catch(()=>({followups:[]})),u=GT(o.label),d=l.find(g=>g.status==="active"&&g.mode!=="off"&&g.trigger===o.trigger&&(g.repo==null||g.repo===c)&&g.dedupeKey===u);if(d)return{kind:"covered",covered:{id:d.id,label:d.label},...o};let p=await K(s),f=rd(p,{trigger:o.trigger}),w=f.length?f[f.length-1].armId:null,m=sa();return await M(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:{ts:Date.now(),armId:m,trigger:o.trigger,label:o.label,prompt:o.prompt,why:o.why,...w?{replaces:w}:{}}}),{kind:"armed",armId:m,replaces:w,...o}}async function JT(e,t){if(!t)throw new Error("armId required");let n={id:e.id,cwd:e.cwd},r=await K(n);if(!rd(r).some(o=>o.armId===t))throw new Error("unknown or already-settled arm");return await M(n,{type:"followup.armed.cancelled",actor:"user",source:"orchestrator",payload:{ts:Date.now(),armId:t}}),{armId:t}}async function YT(e,t,{pull:n=zi}={}){if(_h(e))throw new Error("propose from a lead Track, not a loop's run Track");let r=zT(t,{standing:!0}),o=r.repo??e.workspace?.repo??null,s={id:e.id,cwd:e.cwd};if((await K(s)).reduce((g,y)=>y.type==="followup.create.offered"?y.payload?.proposalId??g:y.type==="followup.create.answered"&&y.payload?.proposalId===g?null:g,null))throw new Error("a follow-up proposal is already waiting on the operator in this Track \u2014 one at a time");let{followups:c,source:l}=await n().catch(()=>({followups:[],source:"unreachable"}));if(l==="unreachable")throw new Error("plane unreachable \u2014 standing follow-ups live in the plane; try again shortly");let u=GT(r.label),d=c.filter(g=>g.dedupeKey===u&&g.trigger===r.trigger),p=d.find(g=>g.status==="deleted"),f=d.find(g=>g.status!=="deleted");if(f)throw new Error(`"${f.label}" (${Eh[f.trigger]||f.trigger}) already exists as a standing follow-up \u2014 not re-proposed`);if(p){let g=p.deletedAt?new Date(p.deletedAt).toISOString().slice(0,10):"earlier";throw new Error(`the operator deleted "${p.label}" on ${g} \u2014 do not re-propose it`)}let w=sa(),m=(e.boxes||[]).find(g=>g.name===e.leadBox)||null;return await M(s,{type:"followup.create.offered",actor:"agent",source:"cli",boxId:e.leadBox??null,provider:m?.agent??null,payload:{ts:Date.now(),proposalId:w,label:r.label,prompt:r.prompt,trigger:r.trigger,repo:o,why:r.why,origin:"agent"}}),{proposalId:w,label:r.label,prompt:r.prompt,trigger:r.trigger,repo:o,why:r.why}}async function XT(e,t,n,{followupId:r=null}={}){if(!t)throw new Error("proposalId required");let o={id:e.id,cwd:e.cwd},s=await K(o),a=s.find(c=>c.type==="followup.create.offered"&&c.payload?.proposalId===t);if(!a)throw new Error("unknown proposal");if(s.some(c=>c.type==="followup.create.answered"&&c.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await M(o,{type:"followup.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"dismiss"}}),{proposalId:t,action:"dismiss"};if(!r)throw new Error("followupId required \u2014 the follow-up is created on the plane before the card is answered");let i=a.payload;return await M(o,{type:"followup.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,followupId:String(r),label:i.label,trigger:i.trigger,repo:i.repo??null}}),await M(o,{type:"followup.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",followupId:String(r)}}),{proposalId:t,action:"created",followupId:String(r)}}async function Ji(e,t,n={},{pull:r=zi}={}){if(!e||_h(e))return null;let o={id:e.id,cwd:e.cwd},s=await K(o).catch(()=>[]),a=n.repo??e.workspace?.repo??null;if(t==="pr.merged"){let p=m=>{let g=(m?.prs||[]).filter(y=>Number.isFinite(Number(y?.number))).map(y=>`${y?.repo??m?.repo??""}#${Number(y.number)}`);return Number.isFinite(Number(m?.prNumber))&&g.push(`${m?.repo??""}#${Number(m.prNumber)}`),g},f=new Set(p(n));if(s.some(m=>m.type==="followup.offered"&&m.payload?.trigger==="pr.merged"&&p(m.payload?.context).some(g=>f.has(g))))return null}let i=rd(s,{trigger:t}).map(p=>({armId:p.armId,label:p.label,prompt:p.prompt,promptHash:Ah(p.prompt),origin:"agent",why:p.why??null})),c=[];if(t!=="now"){let{followups:p}=await r().catch(()=>({followups:[]}));c=p.filter(f=>f.status==="active"&&f.mode!=="off"&&f.trigger===t&&(f.repo==null||f.repo===a)).sort((f,w)=>{let m=g=>g.stats?.offered?(g.stats.accepted||0)/g.stats.offered:0;return m(w)-m(f)||(f.origin==="operator"?-1:0)-(w.origin==="operator"?-1:0)||(w.createdAt||0)-(f.createdAt||0)}).map(f=>({followupId:f.id,label:f.label,promptPreview:HL(f.prompt),promptHash:Ah(f.prompt),origin:f.origin,repo:f.repo??null}))}let l=[...i,...c].slice(0,BL);if(!l.length)return null;let u=sa(),d={ts:Date.now(),offerId:u,trigger:t,repo:a,context:{...n,repo:a},rows:l};return await M(o,{type:"followup.offered",actor:"system",source:"orchestrator",payload:d}),d}function qL(e){let t=e?.context||{},n=Array.isArray(t.prs)&&t.prs.length?t.prs:t.prNumber?[{number:t.prNumber,title:t.prTitle,url:t.prUrl,repo:t.repo}]:[],r=o=>`PR #${o.number}${o.title?` "${o.title}"`:""}${o.url?` (${o.url})`:""}${o.repo?` on ${o.repo}`:""}`;switch(e?.trigger){case"pr.merged":return n.length?`Follow-up the operator tapped after ${n.map(r).join(" and ")} merged:`:"Follow-up the operator tapped after this Track's PR merged:";case"pr.opened":return n.length?`Follow-up the operator tapped after ${n.map(r).join(" and ")} opened:`:"Follow-up the operator tapped after this Track's PR opened:";case"checks.green":return n.length?`Follow-up the operator tapped after CI went green on ${n.map(r).join(" and ")}:`:"Follow-up the operator tapped after CI went green:";case"ship.done":return"Follow-up the operator tapped after the ship you just ran completed:";default:return"Follow-up the operator tapped:"}}async function ZT(e,{offerId:t,followupId:n=null,armId:r=null,promoted:o=null}={},s={}){if(!t)throw new Error("offerId required");return eo(`fu:${e.id}:${t}`,()=>WL(e,{offerId:t,followupId:n,armId:r,promoted:o},s))}async function WL(e,{offerId:t,followupId:n,armId:r,promoted:o},s){let{sayToLead:a,unarchiveTrack:i,getFollowup:c=UT}=s,l={id:e.id,cwd:e.cwd},u=await K(l),d=u.find(b=>b.type==="followup.offered"&&b.payload?.offerId===t);if(!d)throw new Error("unknown offer");if(u.some(b=>b.type==="followup.answered"&&b.payload?.offerId===t))throw new Error("offer already answered");let p=d.payload.rows||[],f=b=>M(l,{type:"followup.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,...b}});if(!n&&!r)return await f({action:"dismiss",followupIds:p.map(b=>b.followupId).filter(Boolean),armIds:p.map(b=>b.armId).filter(Boolean)}),{offerId:t,action:"dismiss"};let w=null,m=null;if(n){if(!p.some($=>$.followupId===n))throw new Error("that follow-up is not on this card");let{followup:b,source:O}=await c(n);if(O==="unreachable")throw new Error("plane unreachable \u2014 the follow-up's current prompt can't be read; try again shortly");if(!b||b.status!=="active"){await f({action:"removed",followupId:n});let $=new Error("removed in Settings since it was offered");throw $.code="removed",$}w=b.prompt,m=b.label}else{let b=p.find($=>$.armId===r);if(!b)throw new Error("that arm is not on this card");if(w=u.find($=>$.type==="followup.armed"&&$.payload?.armId===r)?.payload?.prompt??b.prompt,m=b.label,!w)throw new Error("the arm's prompt is missing from the log")}let g=!1;if(e.archivedAt){if(!i)throw new Error("this Track is archived");await i(e.id,{freshSession:!0}),g=!0}if(!a)throw new Error("sayToLead unavailable");let y=`${qL(d.payload)}
194
+ `)}}async function EA(e,t,{fixKey:n=null,window:r=oo,resolveOrigin:o=null,context:s={}}={}){let a=await xA(e,t);if(a.parents.length!==1)return null;let i=a.parents[0],c=yA(a.message),l=n?Qu(n):c.epoch,u=l?da(l):null,{stdout:d}=await Sh(e,["diff","-U0","--no-color","-M","-C",i,t]),p=cL(d),f=0,w=0,m=0,g=0,y=0,x=0,b=0,R=new Map;for(let $ of p){if($.binary)continue;let L=$.oldPath||$.newPath||"",J=$.deleted.reduce((q,[,re])=>q+re,0),A=iL(L);if(A==="excluded"){m+=J;continue}if(A==="docs"){g+=J,y+=$.added;continue}if(A==="config"){x+=J;continue}f+=$.added;let S=new Set;for(let q of $.hunks||[])for(let re of uL(q))S.add(re);b+=S.size;let N=[];for(let[q,re]of $.deleted)for(let we=q;we<q+re;we++)S.has(we)||N.push(we);if(w+=N.length,!$.oldPath||!N.length)continue;let H;try{let q=["blame","-w","-M","-C","--line-porcelain"];for(let[re,we]of dL(N))q.push("-L",`${re},${re+we-1}`);q.push(i,"--",$.oldPath),H=pL((await Sh(e,q)).stdout)}catch{continue}for(let{sha:q,time:re}of H.values()){let we=R.get(q)??{lines:0,time:re};we.lines+=1,R.set(q,we)}}let _=[],C=0,U=new Map;for(let[$,{lines:L,time:J}]of R){let A=U.get($);if(!A){try{A=await xA(e,$)}catch{A=null}U.set($,A)}let S=A?yA(A.message):{epoch:null},N=S.epoch,H=S.provider,q=S.model;if(!N&&o){let Z=await o($,A);Z?.trackId&&Z?.boxId!=null&&(N={trackId:Z.trackId,boxId:Z.boxId,epoch:Z.epoch??0},H=H??Z.provider??null,q=q??Z.model??null)}if(!N){C+=L;continue}let re=Number.isFinite(J)?J:A?.ts??a.ts,we=Math.max(0,(a.ts-re)/Kj),Re=da(N),Ee=Re===u?"self":Jj(we,r);_.push({sha:$,key:Re,trackId:N.trackId,boxId:N.boxId,epoch:N.epoch,provider:H??null,model:q??null,lines:L,ageDays:Math.round(we*100)/100,class:Ee,decay:Ee==="rework"?1:Ee==="drift"?Math.round(Yj(we,{window:r})*1e3)/1e3:0})}_.sort(($,L)=>L.lines-$.lines);let B=nd({subject:a.subject,trailerCause:c.cause,wallReason:s.wallReason??null,fixerCategory:s.fixerCategory??null,ciFix:s.ciFix===!0}),T=_h({heuristic:B,subject:a.subject,ref:s.ref??null,promptKind:s.promptKind??null,fixerCategory:s.fixerCategory??null,ticketKind:s.ticketKind??null});return{sha:a.sha,parent:i,subject:a.subject.slice(0,200),ts:a.ts,fixKey:u,fixProvider:c.provider??s.provider??null,fixModel:c.model??s.model??null,window:r,added:f,deleted:w,excludedDeleted:m,cosmeticDeleted:b,docsDeleted:g,docsAdded:y,configDeleted:x,codeDelta:f+w+b>0,origins:_,unattributedLines:C,ghost:w===0&&f>0,heuristic:B,intent:T}}function _A(e,{minLines:t=Eh}={}){if(!e)return!1;let n=e.intent?.intent??"unknown";return pa.has(n)?Xi(e)>=t:!1}function Xi(e){return(e?.origins||[]).filter(t=>t.class==="rework").reduce((t,n)=>t+n.lines,0)}function vh(e){let t=e.genUsd;return{...e,genUsd:pn(t),reworkChargedUsd:pn(e.reworkChargedUsd),reworkPendingUsd:pn(e.reworkPendingUsd),trueUsd:pn(t+e.reworkChargedUsd),multiplier:t>0?pn((t+e.reworkChargedUsd)/t):null}}function IA(e,{window:t=oo,boxMeta:n={}}={}){let r=e||[],o=r.filter(T=>T.type==="cost.recorded"),s=r.filter(T=>T.type==="code.committed"),a=r.filter(T=>T.type==="code.rework"),i=T=>Array.isArray(T?.shas)&&T.shas.length?T.shas:T?.sha?[T.sha]:[],c=new Map,l=new Set;for(let T of r)if(T.type==="rework.cause.offered")for(let $ of i(T.payload))l.add($);else if(T.type==="rework.cause.answered"&&T.payload?.cause)for(let $ of i(T.payload))c.set($,T.payload.cause);else if(T.type==="rework.cause.retracted")for(let $ of i(T.payload))c.delete($);let u={},d=(T,$,L)=>da({trackId:T,boxId:$,epoch:L??0}),p=(T,$={})=>{if(!u[T]){let J=Qu(T)||{};u[T]={key:T,...J,provider:null,model:null,...xh()}}let L=u[T];return $.provider&&!L.provider&&(L.provider=$.provider),$.model&&!L.model&&(L.model=$.model),L};for(let T of o){if(!T.boxId)continue;let $=d(T.trackId,T.boxId,T.epoch),{usd:L,model:J}=Vt(T),A=p($,{provider:T.provider,model:J!=="unknown"?J:null});A.genUsd+=L}let f=new Map;for(let T of s){let $=`${T.trackId}/${T.boxId}`;(f.get($)??f.set($,[]).get($)).push({...T,ts:T.payload?.ts??T.ts})}for(let T of f.values())T.sort(($,L)=>$.ts-L.ts);let w=(T,$,L,J)=>{let A=f.get(`${T}/${$}`)||[],S=-1/0;for(let q of A)q.ts<J&&(S=q.ts);let N=0,H=0;for(let q of o)q.trackId!==T||q.boxId!==$||(q.epoch??0)===(L??0)&&(q.ts<=S||q.ts>J||(N+=Vt(q).usd,H++));return{usd:N,turns:H,from:Number.isFinite(S)?S:null}},m={charged:0,pending:0,self:0,decayed:0,unattributed:0,ghost:0,planned:0},g={A:0,B:0,C:0,E:0,none:0},y={fix:0,"likely-fix":0,planned:0,unknown:0},x=0,b=[],R=[],_={},C={},U=new Set;for(let T of a){let $=T.payload||{};if(!$.sha||U.has($.sha))continue;if(U.add($.sha),$.codeDelta===!1){x++;continue}let L=Qu($.fixKey)||{trackId:T.trackId,boxId:T.boxId,epoch:T.epoch??0},{usd:J,turns:A}=w(L.trackId,L.boxId,L.epoch,$.ts??T.ts),S=zj.includes($.intent?.intent)?$.intent.intent:"unknown";y[S]+=1;let N=null;c.has($.sha)?N={cause:c.get($.sha),level:"B",basis:"operator"}:($.heuristic?.level&&$.heuristic.level!=="C"||$.heuristic)&&(N=$.heuristic);let H=N?.level??"none";g[H]=(g[H]||0)+1;let q=Gj.has(H),re=Number($.deleted)||0,we=Array.isArray($.origins)?$.origins:[],Re=we.filter(Z=>Z.class==="rework").reduce((Z,ye)=>Z+ye.lines,0),Ee={sha:$.sha,subject:$.subject??"",ts:$.ts??T.ts,trackId:T.trackId,fixKey:$.fixKey??null,fixProvider:$.fixProvider??T.provider??null,fixUsd:pn(J),fixTurns:A,linesReworked:Re,unattributedLines:Number($.unattributedLines)||0,ghost:$.ghost===!0,intent:{intent:S,basis:$.intent?.basis??null},verdict:N?{cause:N.cause,level:H,basis:N.basis??null}:null,charged:pn(0),origins:[]};if(S==="planned"||N?.cause===ed){m.planned+=J;for(let Z of we)Z.class==="rework"&&Ee.origins.push({key:Z.key,provider:Z.provider??null,model:Z.model??null,lines:Z.lines,ageDays:Z.ageDays,class:Z.class,usd:0})}else if($.ghost||re===0)m.ghost+=J;else{let Z=0;for(let X of we){let Y=X.lines/re,ie=J*Y;if(Z+=ie,X.class==="self"){m.self+=ie;continue}let ve=X.class==="rework"?1:Number(X.decay)||0,Ne=ie*ve;if(m.decayed+=ie-Ne,Ne<=0)continue;let O=p(X.key,{provider:X.provider,model:X.model});O.fixes+=1,O.linesReworked+=X.class==="rework"?X.lines:0;let D=N?.cause&&Yi.includes(N.cause)?N.cause:"unclassified";O.causes[D]+=1,q?(O.reworkChargedUsd+=Ne,m.charged+=Ne,Ee.charged=pn(Ee.charged+Ne)):(O.reworkPendingUsd+=Ne,m.pending+=Ne),Ee.origins.push({key:X.key,provider:O.provider,model:O.model,lines:X.lines,ageDays:X.ageDays,class:X.class,usd:pn(Ne)})}let ye=Math.max(0,J-Z);m.unattributed+=ye}b.push(Ee),!c.has($.sha)&&l.has($.sha)&&R.push($.sha)}for(let T of Object.values(u)){let $=T.provider||"unknown",L=T.model||"unknown",J=A=>{A.genUsd+=T.genUsd,A.reworkChargedUsd+=T.reworkChargedUsd,A.reworkPendingUsd+=T.reworkPendingUsd,A.linesReworked+=T.linesReworked,A.fixes+=T.fixes;for(let S of Object.keys(A.causes))A.causes[S]+=T.causes[S]};J(_[$]||=xh()),J(C[L]||=xh())}b.sort((T,$)=>$.ts-T.ts);let B=Object.values(u).map(T=>{let $=n[`${T.trackId}/${T.boxId}`]||{};return vh({...T,trackName:$.trackName??null,label:$.label??null})}).sort((T,$)=>$.reworkChargedUsd+$.reworkPendingUsd-(T.reworkChargedUsd+T.reworkPendingUsd)||$.genUsd-T.genUsd);return{window:t,basis:`rework = code lines a fix deletes/modifies that blame to another epoch's commit \u2264${t} d old (docs/config churn and in-place updates \u2265${TA} similar are counted, not blamed); fix cost = the fixing box's turns since its previous commit; charged only on an authoritative / operator / self-reported cause; planned work (follow-up, blueprint item, feat:/docs: prefix, non-fix prompt) is generation cost`,intents:y,noCodeDelta:x,byEpoch:Object.fromEntries(B.map(T=>[T.key,T])),epochs:B,byProvider:Object.fromEntries(Object.entries(_).map(([T,$])=>[T,vh($)])),byModel:Object.fromEntries(Object.entries(C).map(([T,$])=>[T,vh($)])),buckets:Object.fromEntries(Object.entries(m).map(([T,$])=>[T,pn($)])),fixUsdTotal:pn(Object.values(m).reduce((T,$)=>T+$,0)),fixes:b,verdicts:g,pendingTaps:R,commits:s.length}}var Wj,qj,Sh,vA,SA,AA,Kj,oo,Th,Eh,Yi,ed,Gj,zj,pa,TA,Vj,Xj,bA,Zj,Qj,eL,tL,nL,kA,rL,oL,sL,aL,Ah,Zu,pn,xh,rd=G(()=>{Wr();Wj=Hj(Uj),qj=64*1024*1024,Sh=(e,t)=>Wj("git",["-C",e,...t],{maxBuffer:qj,timeout:6e4}),vA="Bostrat-Epoch",SA="Bostrat-Model",AA="Bostrat-Fix-Cause",Kj=24*36e5,oo=Number(process.env.BOSTRAT_REWORK_WINDOW_DAYS)||21,Th=90,Eh=3,Yi=Object.freeze(["defect","design","requirements","style"]),ed="not-a-fix",Gj=new Set(["A","B","E"]),zj=Object.freeze(["fix","likely-fix","planned","unknown"]),pa=new Set(["fix","likely-fix"]),TA=.8;Vj={claude:"Co-Authored-By: Claude <noreply@anthropic.com>",codex:"Co-authored-by: Codex <noreply@openai.com>",cursor:"Made-with: Cursor"};Xj=/^revert\b|^revert "/i,bA=/\b(fix(es|ed)?|bug|hotfix|regression|crash|broken|npe|null ?pointer|off[- ]by[- ]one|leak)\b/i,Zj=/\b(refactor|rearchitect|re-architect|restructure|rework|rewrite|redesign|simplif(y|ied)|clean ?up)\b/i,Qj=/\b(lint|format(ting)?|prettier|typo|whitespace|rename)\b/i;eL=/^([a-z]+)(\([^)]*\))?!?:\s/i,tL=new Set(["fix","hotfix","bugfix","revert"]),nL=new Set(["feat","feature","docs","doc","test","tests","build","ci","chore"]),kA=/\bBP-[A-Z]*\d+\b/i,rL=new Set(["feature-build","docs-writing","research","design","ops-infra","orchestration"]);oL=[/(^|\/)\.bostrat\//,/(^|\/)(package-lock\.json|yarn\.lock|pnpm-lock\.yaml|Cargo\.lock|poetry\.lock|Gemfile\.lock|go\.sum|composer\.lock)$/,/\.min\.(js|css)$/,/\.map$/,/\.snap$/,/(^|\/)(node_modules|dist|build|vendor|\.next|target)\//],sL=[/\.(md|mdx|markdown|rst|txt|adoc|asciidoc)$/i,/(^|\/)(docs?|notes|business|design)\//i,/(^|\/)(README|CHANGELOG|CHANGES|LICENSE|CONTRIBUTING|AUTHORS|NOTICE)(\.[a-z]+)?$/i],aL=[/\.(json|jsonc|json5|ya?ml|toml|ini|cfg|conf|properties|env|example)$/i,/(^|\/)\.[^/]+$/,/(^|\/)\.github\//,/(^|\/)(Dockerfile|Makefile|Procfile|fly\.toml)$/];Ah=e=>String(e??"").replace(/\s+/g," ").trim(),Zu=400;pn=e=>Math.round(e*1e4)/1e4,xh=()=>({genUsd:0,reworkChargedUsd:0,reworkPendingUsd:0,linesReworked:0,fixes:0,causes:{defect:0,design:0,requirements:0,style:0,unclassified:0}})});import{execFile as fL}from"node:child_process";import{promisify as mL}from"node:util";function $A(e,t=Date.now()){return df(e,t)??0}function wL(e,t,n){for(let r=e.length-1;r>=0;r--){let o=e[r];if(o.type!=="cost.recorded"||o.boxId!==t||n!=null&&o.epoch!=null&&o.epoch!==n)continue;let s=o.payload?.model;if(s&&s!=="unknown")return s}return null}async function RA(e,t,{now:n=Date.now()}={}){let r=$A(t,n),o=await K(e);return td({trackId:e.id,boxId:t.name,epoch:r,provider:t.agent??null,model:wL(o,t.name,r)})}function gL(e,t){let n=null;for(let r=e.length-1;r>=0;r--){let o=e[r];if(o.type!=="turn.user"||o.boxId!==t||o.actor!=="user")continue;let s=o.payload||{};if(s.note?.kind!=="task"){if(o.source==="orchestrator"&&typeof s.text=="string"&&s.text.trim())return{text:s.text,kind:s.kind??null};!n&&typeof s.promptHead=="string"&&s.promptHead.trim()&&(n={text:s.promptHead,kind:s.kind??null})}}return n}function yL(e,t,n,r){let o=Array.isArray(t?.epochs)?t.epochs:[],s=r>0?o[r-1]:null,a=s?.endReason?.code??(typeof s?.endReason=="string"?s.endReason:null),i=gL(n,t.name),c=i?nr(i.text)?.category??null:null;return{wallReason:a,fixerCategory:c,promptKind:i?.kind??null}}async function bL(e,t){try{let{stdout:n}=await Ih(e,["show","--shortstat","--format=",t]),r=/(\d+) files? changed/.exec(n),o=/(\d+) insertions?\(\+\)/.exec(n),s=/(\d+) deletions?\(-\)/.exec(n);return{files:r?Number(r[1]):0,insertions:o?Number(o[1]):0,deletions:s?Number(s[1]):0}}catch{return{files:0,insertions:0,deletions:0}}}async function kL(e){try{let{stdout:t}=await Ih(e,["rev-parse","--abbrev-ref","HEAD"]);return t.trim()||null}catch{return null}}async function OA(e,t,n,{cwd:r=t?.cwd,log:o=console,now:s=Date.now()}={}){if(!e?.id||!t?.name||!n||!r)return{recorded:!1,reason:"incomplete"};let a=await K(e);if(a.some(w=>w.type==="code.committed"&&w.payload?.sha===n))return{recorded:!1,reason:"duplicate"};let i=s;try{let{stdout:w}=await Ih(r,["show","-s","--format=%ct",n]),m=Number(w.trim())*1e3;Number.isFinite(m)&&m>0&&(i=m)}catch{return{recorded:!1,reason:"unknown-sha"}}let c=$A(t,i),l=await bL(r,n),u=await kL(r),d=await M(e,{type:"code.committed",actor:"agent",source:"hook",boxId:t.name,provider:t.agent??null,payload:{sha:n,ref:u,...l,ts:i}}),p=null,f=!1;try{let w=await EA(r,n,{fixKey:da({trackId:e.id,boxId:t.name,epoch:c}),window:oo,context:{...yL(e,t,a,c),ref:u,provider:t.agent??null}});if(w&&(p=await M(e,{type:"code.rework",actor:"system",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:d.id,payload:w}),!(e?.workspace?.kind==="worktree"&&!!e?.workspace?.branch)&&_A(w))){let g=Xi(w),y=w.origins.filter(x=>x.class==="rework").slice(0,3);await M(e,{type:"rework.cause.offered",actor:"orchestrator",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:p.id,payload:{sha:n,subject:w.subject,linesReworked:g,origins:y.map(x=>({key:x.key,provider:x.provider,model:x.model,lines:x.lines,ageDays:x.ageDays})),heuristic:w.heuristic,intent:w.intent,ts:i}}),f=!0}}catch(w){o.warn?.(`[rework] ${e.id}: analysis of ${String(n).slice(0,7)} failed: ${w?.message||w}`)}return{recorded:!0,event:d,rework:p,offered:f}}function MA(e,t){let n=0;for(let r of e)r.payload?.sha===t&&(r.type==="rework.cause.answered"?n++:r.type==="rework.cause.retracted"&&n--);return n>0}async function CA(e,t,n){if(!Yi.includes(n)&&n!==ed)throw new Error(`bad cause "${n}" (${Yi.join("|")}|${ed})`);let r=await K(e),o=r.find(s=>s.type==="rework.cause.offered"&&s.payload?.sha===t);if(!o)throw new Error("unknown rework offer");if(MA(r,t))throw new Error("already answered");return M(e,{type:"rework.cause.answered",actor:"user",source:"orchestrator",boxId:o.boxId??null,causationId:o.id,payload:{sha:t,...Array.isArray(o.payload?.shas)?{shas:o.payload.shas}:{},cause:n,level:"B",ts:Date.now()}})}async function NA(e,t){let n=await K(e);if(!MA(n,t))throw new Error("no standing answer to retract");let r=[...n].reverse().find(o=>o.type==="rework.cause.answered"&&o.payload?.sha===t);return M(e,{type:"rework.cause.retracted",actor:"user",source:"orchestrator",boxId:r?.boxId??null,causationId:r?.id,payload:{sha:t,...Array.isArray(r?.payload?.shas)?{shas:r.payload.shas}:{},ts:Date.now()}})}async function od(e,{repo:t=null,number:n,title:r="",branch:o=null,url:s=null}={},{log:a=console,now:i=Date.now()}={}){try{if(!e?.id||n==null)return{offered:!1,reason:"incomplete"};let c=await K(e);if(c.some(x=>x.type==="rework.cause.offered"&&x.payload?.pr?.number===n&&(t==null||x.payload.pr.repo===t)))return{offered:!1,reason:"duplicate"};let l=new Set;for(let x of c)if(x.type==="rework.cause.offered")for(let b of Array.isArray(x.payload?.shas)?x.payload.shas:[x.payload?.sha])b&&l.add(b);let u=new Map;for(let x of c)x.type==="code.committed"&&x.payload?.sha&&u.set(x.payload.sha,x.payload.ref??null);let d=_h({heuristic:nd({subject:r}),subject:r,ref:o}),p=[];for(let x of c){if(x.type!=="code.rework")continue;let b=x.payload||{};if(!b.sha||l.has(b.sha)||b.codeDelta===!1||o&&u.has(b.sha)&&u.get(b.sha)!==o)continue;let R=b.intent?.intent??"unknown";(pa.has(R)||R==="unknown"&&pa.has(d.intent))&&Xi(b)!==0&&p.push(b)}let f=p.reduce((x,b)=>x+Xi(b),0);if(f<Eh)return{offered:!1,reason:"below-threshold"};let w=new Map;for(let x of p)for(let b of x.origins??[]){if(b.class!=="rework")continue;let R=w.get(b.key)??{key:b.key,provider:b.provider??null,model:b.model??null,lines:0,ageDays:b.ageDays};R.lines+=b.lines,R.ageDays=Math.min(R.ageDays,b.ageDays),w.set(b.key,R)}let m=p.map(x=>x.sha),g=p.map(x=>x.heuristic).find(x=>x&&x.level!=="C")??nd({subject:r})??p.map(x=>x.heuristic).find(Boolean)??null,y=pa.has(d.intent)?d:p.find(x=>pa.has(x.intent?.intent))?.intent??d;return await M(e,{type:"rework.cause.offered",actor:"orchestrator",source:"orchestrator",boxId:null,payload:{sha:m[m.length-1],shas:m,pr:{repo:t,number:n,title:String(r||"").slice(0,200),url:s,branch:o},subject:String(r||"").slice(0,200)||p[p.length-1].subject,linesReworked:f,origins:[...w.values()].sort((x,b)=>b.lines-x.lines).slice(0,3),heuristic:g,intent:y,ts:i}}),{offered:!0,shas:m}}catch(c){return a.warn?.(`[rework] ${e?.id}: PR-level offer for #${n} failed: ${c?.message||c}`),{offered:!1,reason:"error"}}}var hL,Ih,sd=G(()=>{fe();ru();rd();hL=mL(fL),Ih=(e,t)=>hL("git",["-C",e,...t],{maxBuffer:16*1024*1024,timeout:3e4})});import{execFile as xL}from"node:child_process";import{promisify as vL}from"node:util";async function $h(e,t,{midTurn:n=Zo,pollMs:r=SL,capMs:o=AL}={}){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 FA(e){let t=String(e||""),n=0;for(let r=0;r<64;r++){PA.lastIndex=n;let o=PA.exec(t);if(!o)break;n=o.index+o[0].length;let s=o[1]==="-",a=o[2]??o[3]??o[4],i=t.indexOf(`
195
+ `,o.index);if(i<0)break;let l=new RegExp("^"+(s?"\\t*":"")+OL(a)+"[ \\t]*$","m").exec(t.slice(i+1));if(!l)continue;let u=i+1+l.index+l[0].length;t=t.slice(0,i)+t.slice(u)}return t}function Rh(e,t){return e.slice(t).replace(/^[\s;&|)]+/,"").replace(/"[^"]*"|'[^']*'/g,'""').split(/[;&|\n]/)[0]}function HA(e){let t=FA(e),n=t.match(IL);if(!n)return null;let r=Rh(t,n.index);return RL.test(r)?null:{repo:r.match(UA)?.[1]??null,head:r.match(ML)?.[1]??null}}function WA(e){let t=FA(e),n=t.match($L);if(!n)return null;let r=Rh(t,n.index),o=Rh(t,n.index+n[0].length),s=null,a=o.trim().split(/\s+/).filter(Boolean);for(let i=0;i<a.length;i++){let c=a[i];if(c.startsWith("-")){NL.has(c)&&i++;continue}s=c.replace(/^["']+|["']+$/g,"")||null;break}return{repo:r.match(UA)?.[1]??null,selector:s,auto:/\s--auto\b/.test(r)}}async function DL(e,t,{exclude:n=()=>!1}={}){let r=async i=>{ir("observer");let{stdout:c}=await DA("gh",["pr","list","--repo",e,"--author","@me","--state","all","--limit","10","--json",PL],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...i}}).catch(l=>{throw to(l)&&no(l),l});return JSON.parse(c||"[]")},o=i=>(i||[]).filter(c=>Date.parse(c.createdAt)>=t-TL&&!n(c)),s=await An({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 BL(e,t){if(t)return[t];let n=[];for(let r of qA(e)){let o=await _e(r).catch(()=>null);o&&!n.includes(o)&&n.push(o)}for(let r of await Zn().catch(()=>[])){let o=await _e(r.path).catch(()=>null);o&&!n.includes(o)&&n.push(o)}return n}function qA(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 jL(e,t,n){let r=await ua(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)||CL(c.headRefName,e.id),i=[];for(let c of await BL(e,t?.repo??null)){let l;try{l=await DL(c,n,{exclude:a})}catch{continue}for(let u of l){let d=await at(c,u.number);if(s(u.headRefName)){if(d&&d.trackId===e.id&&d.announced)return{settled:!0};if(d&&d.trackId!==e.id)continue;return{slug:c,pr:u}}d&&(d.trackId!==e.id||d.announced)||i.push({slug:c,pr:u})}}return i.length?(i.sort((c,l)=>Date.parse(l.pr.createdAt)-Date.parse(c.pr.createdAt)),i[0]):null}function KA(e){if(!e)return 0;let t=0;for(let n of lr)n.startsWith(`${e}|`)&&t++;return t}function GA(){for(let e of[...Oh])e()}function zA(e,t,{delays:n=BA,turnEnd:r}={}){let o=HA(t.command);if(!o)return null;let s=!!WA(t.command),a=`${e.id}|${t.id??t.ts??t.command}`;if(lr.has(a))return null;lr.add(a);let i=t.ts??Date.now(),c=(async()=>{try{for(let l of n){await new Promise(m=>{let g=()=>{clearTimeout(y),Oh.delete(g),m()},y=setTimeout(g,l);Oh.add(g)});let u=await jL(e,o,i).catch(()=>null);if(u?.settled)return null;if(!u)continue;let{slug:d,pr:p}=u,{link:f,created:w}=await Bt({repo:d,number:p.number,trackId:e.id,url:p.url,headRef:p.headRefName,title:p.title,source:"observed"});return!w&&!(f?.trackId===e.id&&await sr(d,p.number))?null:(await $h(t.box,t.agent,r),await M({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Date.now(),change:"opened",number:p.number,url:p.url,title:p.title,branch:p.headRefName,repo:d,...s?{selfMerge:!0}:{}}}),p)}return null}finally{lr.delete(a)}})();return c.catch(()=>lr.delete(a)),c}function VA(e,t,{delays:n=BA,turnEnd:r,openedWait:o}={}){let s=WA(t.command);if(!s)return null;let a=`merge|${e.id}|${t.id??t.ts??t.command}`;if(lr.has(a))return null;lr.add(a);let i=(async()=>{try{let c=s.repo,l=s.selector,u=l?.match(/github\.com\/([\w.-]+\/[\w.-]+)\/pull\/(\d+)/);u&&([,c,l]=u);let d=[];if(c)d=[c];else{let w=qA(e);if(w.length>1&&/^\d+$/.test(String(s.selector??"")))return null;for(let m of w){let g=await _e(m).catch(()=>null);g&&!d.includes(g)&&d.push(g)}}if(l||=(await ua(e).catch(()=>[])).filter(w=>w!==e.workspace?.branch)[0]||e.workspace?.branch,!d.length||!l)return null;c=d[0];let p=async(w,m)=>{let g=await at(c,w.number);return g&&g.trackId!==e.id?null:(g||await Bt({repo:c,number:w.number,trackId:e.id,url:w.url,headRef:w.headRefName,title:w.title,source:"merge-observed"}),await Ui(c,w.number),m&&((await K(e).catch(()=>[])).some(b=>b.type==="pr.state.changed"&&(b.payload?.change==="auto-armed"||b.payload?.change==="merged")&&b.payload?.number===w.number)||(await $h(t.box,t.agent,r),await M({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Date.now(),change:"auto-armed",number:w.number,url:w.url,title:w.title,branch:w.headRefName,repo:c}}))),w)},f=null;for(let w of n){await new Promise(C=>setTimeout(C,w));let m=[];for(let C of d)try{ir("observer");let{stdout:U}=await DA("gh",["pr","view",String(l),"--repo",C,"--json",LL],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...await An({slug:C})}}),B=JSON.parse(U||"null");B?.number&&m.push({slug:C,pr:B})}catch(U){to(U)&&no(U)}let g=m.find(C=>C.pr.state==="MERGED")??(m.length===1?m[0]:null);if(!g)continue;c=g.slug;let y=g.pr;if(!y?.number)continue;if(y.state==="CLOSED")return null;if(y.state!=="MERGED"){if(f=y,s.auto)return p(y,!0);continue}let x=await at(c,y.number);if(x&&x.trackId!==e.id)return null;x||await Bt({repo:c,number:y.number,trackId:e.id,url:y.url,headRef:y.headRefName,title:y.title,source:"merge-observed"}),await $h(t.box,t.agent,r);let b=await K(e).catch(()=>[]);if(b.some(C=>C.type==="pr.state.changed"&&C.payload?.change==="merged"&&C.payload?.number===y.number))return null;let R=C=>C.some(U=>U.type==="pr.state.changed"&&U.payload?.change==="opened"&&U.payload?.number===y.number),_=0;if(!R(b)){if(HA(t.command)&&await sr(c,y.number)){let C=Date.now();_=C+1,await M({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:C,change:"opened",number:y.number,url:y.url,title:y.title,branch:y.headRefName,repo:c,selfMerge:!0}})}else if((await at(c,y.number))?.announced){let C=o?.capMs??EL,U=o?.pollMs??_L,B=Date.now()+C;for(;Date.now()<B&&(await new Promise(T=>setTimeout(T,U)),!R(await K(e).catch(()=>[]))););}}return await M({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Math.max(Date.now(),_),change:"merged",number:y.number,url:y.url,title:y.title,branch:y.headRefName,repo:c}}),await od(e,{repo:c,number:y.number,title:y.title,branch:y.headRefName,url:y.url}).catch(()=>{}),await dr(c,y.number).catch(()=>{}),await ur(c,y.number).catch(()=>{}),await Qr(c,y.number,"merged"),y}return f?p(f,!1):null}finally{lr.delete(a)}})();return i.catch(()=>lr.delete(a)),i}var DA,BA,SL,AL,TL,EL,_L,jA,LA,IL,$L,RL,PA,OL,UA,ML,CL,NL,PL,lr,Oh,LL,ad=G(()=>{fe();$r();ft();Wi();Cn();pr();Ji();Qo();sd();DA=vL(xL),BA=[4e3,15e3,45e3],SL=2500,AL=5*6e4;TL=15e3,EL=9e4,_L=2e3,jA=/(?:^|[;&|\n({`]\s*|\)\s*)(?:(?:then|do|else|elif|if|while|until|time)\s+)?/.source,LA=/gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+/.source,IL=new RegExp(`${jA}${LA}create\\b`),$L=new RegExp(`${jA}${LA}merge\\b`),RL=/\s--web\b/,PA=/<<(-?)\s*(?:'([^'\n]+)'|"([^"\n]+)"|\\?([A-Za-z_][\w-]*))/g,OL=e=>e.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");UA=/(?:--repo|-R)[\s=]+([\w.-]+\/[\w.-]+)/,ML=/(?:--head|-H)[\s=]+([^\s"'`;&|]+)/,CL=gA;NL=new Set(["--subject","-t","--body","-b","--body-file","-F","--match-head-commit","--author-email","-A","--repo","-R"]);PL="number,url,title,headRefName,createdAt";lr=new Set;Oh=new Set;LL="number,url,title,headRefName,state"});import FL from"node:fs/promises";import Ch from"node:path";import UL from"node:os";function Mh(e,t){let n=new RegExp(`\\b${t}="([^"]*)"`).exec(e);return n?n[1]:null}function id(e){let t=HL.exec(String(e||""));if(!t)return null;let[,n,r]=t,o=Mh(n,"from"),s=o?o.replace(/^uds:/,""):null,a=JA(s);return{socket:s,pid:a,name:Mh(n,"from-name"),mode:Mh(n,"from-mode"),text:r.trim()}}function JA(e){let t=/(\d+)\.sock$/.exec(String(e||""));return t?Number(t[1]):null}function WL(){return process.env.CLAUDE_CONFIG_DIR?Ch.join(process.env.CLAUDE_CONFIG_DIR,"sessions"):Ch.join(UL.homedir(),".claude","sessions")}async function qL(e){let t=JA(e);if(!t)return null;try{let n=await FL.readFile(Ch.join(WL(),`${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 YA(e,t){let n=await qL(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 HL,Nh=G(()=>{HL=/<cross-session-message\b([^>]*)>([\s\S]*?)<\/cross-session-message>/});function Ph(e=process.env){return!!(Oe(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Dh({loopId:e,outcome:t,note:n=null,env:r=process.env}={}){if(!Ph(r))return{ok:!1,source:"unconfigured"};let o=new AbortController,s=setTimeout(()=>o.abort(),XA);try{let a=await ZA(`${Oe(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 QA(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(!Ph(s))return{ok:!1,source:"unconfigured"};let i=cd.get(e.id)||0;if(a()-i<KL)return{ok:!1,source:"debounced"};cd.set(e.id,a());let c=await Zi({env:s}),l=c.loops.find(p=>p.trackId===e.id);if(!l)return cd.delete(e.id),{ok:!1,source:c.source==="plane"?"no-loop":c.source};let u=`${t||"provider"} ${r?r+" ":""}${n}: ${String(o||"").replace(/\s+/g," ").trim()}`.slice(0,500),d=await Dh({loopId:l.id,outcome:"errored",note:u,env:s});return d.ok||cd.delete(e.id),{...d,loop:{id:l.id,name:l.name}}}async function Zi({env:e=process.env}={}){if(!Ph(e))return{loops:[],source:"unconfigured"};let t=new AbortController,n=setTimeout(()=>t.abort(),XA);try{let r=await ZA(`${Oe(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 XA,ZA,KL,cd,Bh=G(()=>{ft();XA=1e4,ZA=(...e)=>fetch(...e);KL=10*6e4,cd=new Map});function eT(e=process.env){return!!(Oe(e)&&e.BOSTRAT_PLANE_TOKEN)}async function tT(e,t,n=jh){let r=new AbortController,o=setTimeout(()=>r.abort(),n);try{return await zL(`${Oe(t)}${e}`,{headers:VL(t),signal:r.signal})}finally{clearTimeout(o)}}async function Qi({env:e=process.env,force:t=!1,timeoutMs:n=jh}={}){if(!eT(e))return{followups:[],source:"unconfigured"};if(!t&&es&&Date.now()-es.at<GL)return{followups:es.followups,source:"cache"};try{let r=await tT("/v1/followups?deleted=1",e,n);if(!r.ok)throw new Error(`plane ${r.status}`);let o=await r.json(),s=Array.isArray(o?.followups)?o.followups:[];return es={at:Date.now(),followups:s},{followups:s,source:"plane"}}catch(r){return es?{followups:es.followups,source:"stale",error:r?.message}:{followups:[],source:"unreachable",error:r?.message}}}async function nT(e,{env:t=process.env,timeoutMs:n=jh}={}){if(!e)return{followup:null,source:"unconfigured"};if(!eT(t))return{followup:null,source:"unconfigured"};try{let r=await tT(`/v1/followups/${encodeURIComponent(e)}`,t,n);if(r.status===404)return{followup:null,source:"gone"};if(!r.ok)throw new Error(`plane ${r.status}`);return{followup:(await r.json())?.followup??null,source:"plane"}}catch(r){let o=es?.followups.find(s=>s.id===e)??null;return o?{followup:o,source:"stale",error:r?.message}:{followup:null,source:"unreachable",error:r?.message}}}var GL,jh,es,zL,VL,rT=G(()=>{ft();GL=6e4,jh=5e3,es=null,zL=(...e)=>fetch(...e);VL=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});async function so(e,t){if(Lh.has(e)){let n=new Error("offer already answered (answer in flight)");throw n.code="answer-in-flight",n}Lh.add(e);try{return await t()}finally{Lh.delete(e)}}var Lh,ec=G(()=>{Lh=new Set});import{randomUUID as ma,createHash as JL}from"node:crypto";function iT(e){return String(e||"").toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}function eF(e){for(let[t,n]of QL)if(t.test(String(e||"")))return`a standing prompt must not embed this Track's specifics (${n}) \u2014 the card supplies them at fire time; arm a one-shot with \`offer\` instead`;return null}function cT(e,{standing:t=!1}={}){let n=e&&typeof e=="object"?e:{},r=fa(n.label).replace(/\s+/g," ");if(!r)throw new Error('label required (\u226460 chars, e.g. "Deploy to Pi")');if(r.length>oT)throw new Error(`label must be \u2264${oT} characters`);let o=fa(n.trigger)||(n.ship?"now":""),s=t?XL:aT.filter(u=>u!=="track.opened");if(!s.includes(o))throw new Error(`trigger must be one of ${s.join(" | ")}${t?" (a standing follow-up can't be `now` \u2014 it would fire every turn)":""}, got "${n.trigger??""}"`);let a=n.ship&&o==="now"?nF(n.ship):null,i=fa(n.prompt);if(!a&&!i)throw new Error("prompt required \u2014 the full instruction a fresh session could execute");if(Buffer.byteLength(i,"utf8")>sT)throw new Error(`prompt must be \u2264${sT} bytes`);if(t){let u=eF(i);if(u)throw new Error(u)}let c=fa(n.why).slice(0,YL)||null,l=t?tF(n.repo):null;return{label:r,prompt:i,trigger:o,why:c,...l?{repo:l}:{},...a?{ship:a}:{}}}function tF(e){if(e==null||e===""||e==="*")return null;let t=String(e).trim();if(!/^[\w.-]+\/[\w.-]+$/.test(t))throw new Error(`repo must be a forge slug like owner/name, got "${e}"`);return t}function nF(e){let t=e&&typeof e=="object"?e:{},n=Array.isArray(t.actions)?t.actions.map(i=>String(i).trim().toLowerCase()):Fh.slice();for(let i of n)if(!Fh.includes(i))throw new Error(`ship.actions may only contain ${Fh.join(" | ")}, got "${i}"`);if(!n.length)throw new Error("ship.actions must name at least one of commit | push | pr");let r=t.rebase==null?"none":String(t.rebase).trim();if(!["offered","none"].includes(r))throw new Error(`ship.rebase must be "offered" or "none", got "${t.rebase}"`);let o=null;if(t.toPr!=null&&t.toPr!==""){let i=Number(t.toPr);if(!Number.isInteger(i)||i<=0)throw new Error(`ship.toPr must be a PR number, got "${t.toPr}"`);o=i}let s=fa(t.base)||null,a=null;if(t.repos!=null){if(!Array.isArray(t.repos))throw new Error("ship.repos must be an array of checkout names");a=t.repos.map(i=>fa(i)).filter(Boolean),a.length||(a=null)}return{actions:[...new Set(n)],rebase:r,toPr:o,base:s,repos:a}}function ld(e,{trigger:t=null}={}){let n=new Map;for(let r of e){let o=r.payload||{};if(r.type==="followup.armed"&&o.armId)o.replaces&&n.delete(o.replaces),n.set(o.armId,{...o,ts:o.ts??r.ts,boxId:r.boxId??null,provider:r.provider??null});else if(r.type==="followup.armed.cancelled"&&o.armId)n.delete(o.armId);else if(r.type==="followup.offered")for(let s of o.rows||[])s.armId&&n.delete(s.armId)}return[...n.values()].filter(r=>!t||r.trigger===t)}async function lT(e,t,{pull:n=Qi,ship:r={}}={}){if(Wh(e))throw new Error("follow-ups don't fire on a loop's run Track \u2014 report the outcome with `bostrat-loop report` instead");let o=cT(t);if(o.ship)return{kind:"ship",...await aF(e,o,r)};let s={id:e.id,cwd:e.cwd},a=(e.boxes||[]).find(g=>g.name===e.leadBox)||null,i={boxId:e.leadBox??null,provider:a?.agent??null};if(o.trigger==="now"){let g=ma(),y=ma();return await M(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:{ts:Date.now(),armId:g,trigger:"now",label:o.label,prompt:o.prompt,why:o.why}}),await M(s,{type:"followup.offered",actor:"system",source:"orchestrator",...i,payload:{ts:Date.now(),offerId:y,trigger:"now",repo:e.workspace?.repo||null,context:{},rows:[{armId:g,label:o.label,prompt:o.prompt,promptHash:Uh(o.prompt),origin:"agent",why:o.why}]}}),{kind:"now",armId:g,offerId:y,...o}}let c=e.workspace?.repo||null,{followups:l}=await n().catch(()=>({followups:[]})),u=iT(o.label),d=l.find(g=>g.status==="active"&&g.mode!=="off"&&g.trigger===o.trigger&&(g.repo==null||g.repo===c)&&g.dedupeKey===u);if(d)return{kind:"covered",covered:{id:d.id,label:d.label},...o};let p=await K(s),f=ld(p,{trigger:o.trigger}),w=f.length?f[f.length-1].armId:null,m=ma();return await M(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:{ts:Date.now(),armId:m,trigger:o.trigger,label:o.label,prompt:o.prompt,why:o.why,...w?{replaces:w}:{}}}),{kind:"armed",armId:m,replaces:w,...o}}async function uT(e,t){if(!t)throw new Error("armId required");let n={id:e.id,cwd:e.cwd},r=await K(n);if(!ld(r).some(o=>o.armId===t))throw new Error("unknown or already-settled arm");return await M(n,{type:"followup.armed.cancelled",actor:"user",source:"orchestrator",payload:{ts:Date.now(),armId:t}}),{armId:t}}async function dT(e,t,{pull:n=Qi}={}){if(Wh(e))throw new Error("propose from a lead Track, not a loop's run Track");let r=cT(t,{standing:!0}),o=r.repo??e.workspace?.repo??null,s={id:e.id,cwd:e.cwd};if((await K(s)).reduce((g,y)=>y.type==="followup.create.offered"?y.payload?.proposalId??g:y.type==="followup.create.answered"&&y.payload?.proposalId===g?null:g,null))throw new Error("a follow-up proposal is already waiting on the operator in this Track \u2014 one at a time");let{followups:c,source:l}=await n().catch(()=>({followups:[],source:"unreachable"}));if(l==="unreachable")throw new Error("plane unreachable \u2014 standing follow-ups live in the plane; try again shortly");let u=iT(r.label),d=c.filter(g=>g.dedupeKey===u&&g.trigger===r.trigger),p=d.find(g=>g.status==="deleted"),f=d.find(g=>g.status!=="deleted");if(f)throw new Error(`"${f.label}" (${Hh[f.trigger]||f.trigger}) already exists as a standing follow-up \u2014 not re-proposed`);if(p){let g=p.deletedAt?new Date(p.deletedAt).toISOString().slice(0,10):"earlier";throw new Error(`the operator deleted "${p.label}" on ${g} \u2014 do not re-propose it`)}let w=ma(),m=(e.boxes||[]).find(g=>g.name===e.leadBox)||null;return await M(s,{type:"followup.create.offered",actor:"agent",source:"cli",boxId:e.leadBox??null,provider:m?.agent??null,payload:{ts:Date.now(),proposalId:w,label:r.label,prompt:r.prompt,trigger:r.trigger,repo:o,why:r.why,origin:"agent"}}),{proposalId:w,label:r.label,prompt:r.prompt,trigger:r.trigger,repo:o,why:r.why}}async function pT(e,t,n,{followupId:r=null}={}){if(!t)throw new Error("proposalId required");let o={id:e.id,cwd:e.cwd},s=await K(o),a=s.find(c=>c.type==="followup.create.offered"&&c.payload?.proposalId===t);if(!a)throw new Error("unknown proposal");if(s.some(c=>c.type==="followup.create.answered"&&c.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await M(o,{type:"followup.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"dismiss"}}),{proposalId:t,action:"dismiss"};if(!r)throw new Error("followupId required \u2014 the follow-up is created on the plane before the card is answered");let i=a.payload;return await M(o,{type:"followup.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,followupId:String(r),label:i.label,trigger:i.trigger,repo:i.repo??null}}),await M(o,{type:"followup.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",followupId:String(r)}}),{proposalId:t,action:"created",followupId:String(r)}}async function tc(e,t,n={},{pull:r=Qi}={}){if(!e||Wh(e))return null;let o={id:e.id,cwd:e.cwd},s=await K(o).catch(()=>[]),a=n.repo??e.workspace?.repo??null;if(t==="pr.merged"){let p=m=>{let g=(m?.prs||[]).filter(y=>Number.isFinite(Number(y?.number))).map(y=>`${y?.repo??m?.repo??""}#${Number(y.number)}`);return Number.isFinite(Number(m?.prNumber))&&g.push(`${m?.repo??""}#${Number(m.prNumber)}`),g},f=new Set(p(n));if(s.some(m=>m.type==="followup.offered"&&m.payload?.trigger==="pr.merged"&&p(m.payload?.context).some(g=>f.has(g))))return null}let i=ld(s,{trigger:t}).map(p=>({armId:p.armId,label:p.label,prompt:p.prompt,promptHash:Uh(p.prompt),origin:"agent",why:p.why??null})),c=[];if(t!=="now"){let{followups:p}=await r().catch(()=>({followups:[]}));c=p.filter(f=>f.status==="active"&&f.mode!=="off"&&f.trigger===t&&(f.repo==null||f.repo===a)).sort((f,w)=>{let m=g=>g.stats?.offered?(g.stats.accepted||0)/g.stats.offered:0;return m(w)-m(f)||(f.origin==="operator"?-1:0)-(w.origin==="operator"?-1:0)||(w.createdAt||0)-(f.createdAt||0)}).map(f=>({followupId:f.id,label:f.label,promptPreview:rF(f.prompt),promptHash:Uh(f.prompt),origin:f.origin,repo:f.repo??null}))}let l=[...i,...c].slice(0,ZL);if(!l.length)return null;let u=ma(),d={ts:Date.now(),offerId:u,trigger:t,repo:a,context:{...n,repo:a},rows:l};return await M(o,{type:"followup.offered",actor:"system",source:"orchestrator",payload:d}),d}function oF(e){let t=e?.context||{},n=Array.isArray(t.prs)&&t.prs.length?t.prs:t.prNumber?[{number:t.prNumber,title:t.prTitle,url:t.prUrl,repo:t.repo}]:[],r=o=>`PR #${o.number}${o.title?` "${o.title}"`:""}${o.url?` (${o.url})`:""}${o.repo?` on ${o.repo}`:""}`;switch(e?.trigger){case"pr.merged":return n.length?`Follow-up the operator tapped after ${n.map(r).join(" and ")} merged:`:"Follow-up the operator tapped after this Track's PR merged:";case"pr.opened":return n.length?`Follow-up the operator tapped after ${n.map(r).join(" and ")} opened:`:"Follow-up the operator tapped after this Track's PR opened:";case"checks.green":return n.length?`Follow-up the operator tapped after CI went green on ${n.map(r).join(" and ")}:`:"Follow-up the operator tapped after CI went green:";case"ship.done":return"Follow-up the operator tapped after the ship you just ran completed:";default:return"Follow-up the operator tapped:"}}async function fT(e,{offerId:t,followupId:n=null,armId:r=null,promoted:o=null}={},s={}){if(!t)throw new Error("offerId required");return so(`fu:${e.id}:${t}`,()=>sF(e,{offerId:t,followupId:n,armId:r,promoted:o},s))}async function sF(e,{offerId:t,followupId:n,armId:r,promoted:o},s){let{sayToLead:a,unarchiveTrack:i,getFollowup:c=nT}=s,l={id:e.id,cwd:e.cwd},u=await K(l),d=u.find(b=>b.type==="followup.offered"&&b.payload?.offerId===t);if(!d)throw new Error("unknown offer");if(u.some(b=>b.type==="followup.answered"&&b.payload?.offerId===t))throw new Error("offer already answered");let p=d.payload.rows||[],f=b=>M(l,{type:"followup.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,...b}});if(!n&&!r)return await f({action:"dismiss",followupIds:p.map(b=>b.followupId).filter(Boolean),armIds:p.map(b=>b.armId).filter(Boolean)}),{offerId:t,action:"dismiss"};let w=null,m=null;if(n){if(!p.some(_=>_.followupId===n))throw new Error("that follow-up is not on this card");let{followup:b,source:R}=await c(n);if(R==="unreachable")throw new Error("plane unreachable \u2014 the follow-up's current prompt can't be read; try again shortly");if(!b||b.status!=="active"){await f({action:"removed",followupId:n});let _=new Error("removed in Settings since it was offered");throw _.code="removed",_}w=b.prompt,m=b.label}else{let b=p.find(_=>_.armId===r);if(!b)throw new Error("that arm is not on this card");if(w=u.find(_=>_.type==="followup.armed"&&_.payload?.armId===r)?.payload?.prompt??b.prompt,m=b.label,!w)throw new Error("the arm's prompt is missing from the log")}let g=!1;if(e.archivedAt){if(!i)throw new Error("this Track is archived");await i(e.id,{freshSession:!0}),g=!0}if(!a)throw new Error("sayToLead unavailable");let y=`${oF(d.payload)}
196
196
 
197
- ${w}`,x=await a(e.id,y,{kind:"followup-go"});return await f({action:"sent",...n?{followupId:n}:{armId:r},label:m,...o?{promoted:String(o)}:{},...g?{revived:!0}:{},source:n?`followup:${n}`:`arm:${r}`}),{offerId:t,action:"sent",followupId:n,armId:r,promoted:o,revived:g,queued:!!x?.queued}}async function KL(e,t,{changedRepos:n=null,probe:r=Hu,branchOf:o=Zr}={}){let s=t.ship;if(!e.workspace?.branch)throw new Error("this Track has no branch to ship \u2014 a ship offer needs a worktree Track");let a={id:e.id,cwd:e.cwd},i=(e.boxes||[]).find(g=>g.name===e.leadBox)||null,c=e.workspace?.kind==="multi",l;if(c&&n){let g=await n(e).catch(()=>[]),y=s.repos?g.filter(x=>s.repos.includes(x.name)):g;l=y.length?y.map(x=>({name:x.name,slug:x.repo??null})):void 0}let u=(c?null:await o(e.cwd).catch(()=>null))||e.workspace.branch,d=s.rebase==="offered",p=await r(e,{branch:u,rebase:d}).catch(()=>null),f=[...d?["rebase"]:[],...s.actions].filter(g=>Gr.includes(g));if(p&&p.available.length===0)return{skipped:!0,reason:"nothing to ship \u2014 the tree is clean, pushed, and its PR is open",shipState:p};let w=sa(),m=t.why?`${t.label} \u2014 ${t.why}`:t.label;return await M(a,{type:"pr.offered",actor:"agent",source:"cli",boxId:e.leadBox??null,provider:i?.agent??null,payload:{offerId:w,ts:Date.now(),excerpt:m,via:"cli",branch:u,base:s.base||e.workspace.baseRef?.replace(/^origin\//,"")||null,boxRole:"lead",available:p?.available,defaults:p?p.defaults.filter(g=>f.includes(g)||g==="rebase"):void 0,prState:p?.prState,openPr:p?.openPr||void 0,repos:p?.repos||l,offered:p?f.filter(g=>p.available.includes(g)):f,toPr:s.toPr?{number:s.toPr}:void 0}}),{offerId:w,branch:u,offered:f,available:p?.available??null,prState:p?.prState??null}}function QT(e){let t=!1;for(let n of e)n.type==="pr.offered"&&(n.source==="cli"||n.payload?.via==="cli")?t=!0:(n.type==="turn.user"&&!n.payload?.kind||n.type==="pr.offer.answered")&&(t=!1);return t}function eA(e){let t=null;for(let n of e){let r=n.payload||{};n.type==="pr.offer.answered"?t=r.action&&r.action!=="dismiss"&&r.action!=="pr-exists"?r.offerId:null:n.type==="pr.exists.answered"?t=r.choice&&r.choice!=="dismiss"?r.offerId??t:null:(n.type==="turn.user"&&!r.kind||n.type==="followup.offered"&&r.trigger==="ship.done"&&r.context?.shipOfferId&&r.context.shipOfferId===t)&&(t=null)}return t}async function tA(e,{pull:t=zi}={}){let{followups:n,source:r,error:o}=await t().catch(a=>({followups:[],source:"unreachable",error:a?.message})),s=e?await K({id:e.id,cwd:e.cwd}).catch(()=>[]):[];return{followups:n,source:r,error:o,arms:e?rd(s):[]}}var qT,WT,PL,KT,DL,Eh,BL,Th,Ah,oa,jL,_h,HL,od=G(()=>{de();Do();rh();qo();HT();Vi();qT=60,WT=8*1024,PL=200,KT=["now","pr.merged","ship.done","pr.opened","checks.green","track.opened"],DL=KT.filter(e=>e!=="now"&&e!=="track.opened"),Eh={now:"now","pr.merged":"after merge","ship.done":"after ship","pr.opened":"after PR opens","checks.green":"after CI goes green","track.opened":"when a Track opens"},BL=3,Th=["commit","push","pr"];Ah=e=>NL("sha256").update(String(e)).digest("hex").slice(0,16),oa=e=>typeof e=="string"?e.trim():"",jL=[[/(^|[^\w&])#\d+\b/,"a PR/issue number"],[/https?:\/\/\S+/i,"a URL"],[/\b[0-9a-f]{7,40}\b/i,"a commit SHA"],[/\bv\d+\.\d+\.\d+\b/,"a release tag"]];_h=e=>String(e?.name||"").startsWith("\u21BB");HL=e=>String(e||"").split(`
197
+ ${w}`,x=await a(e.id,y,{kind:"followup-go"});return await f({action:"sent",...n?{followupId:n}:{armId:r},label:m,...o?{promoted:String(o)}:{},...g?{revived:!0}:{},source:n?`followup:${n}`:`arm:${r}`}),{offerId:t,action:"sent",followupId:n,armId:r,promoted:o,revived:g,queued:!!x?.queued}}async function aF(e,t,{changedRepos:n=null,probe:r=Vu,branchOf:o=ro}={}){let s=t.ship;if(!e.workspace?.branch)throw new Error("this Track has no branch to ship \u2014 a ship offer needs a worktree Track");let a={id:e.id,cwd:e.cwd},i=(e.boxes||[]).find(g=>g.name===e.leadBox)||null,c=e.workspace?.kind==="multi",l;if(c&&n){let g=await n(e).catch(()=>[]),y=s.repos?g.filter(x=>s.repos.includes(x.name)):g;l=y.length?y.map(x=>({name:x.name,slug:x.repo??null})):void 0}let u=(c?null:await o(e.cwd).catch(()=>null))||e.workspace.branch,d=s.rebase==="offered",p=await r(e,{branch:u,rebase:d}).catch(()=>null),f=[...d?["rebase"]:[],...s.actions].filter(g=>Xr.includes(g));if(p&&p.available.length===0)return{skipped:!0,reason:"nothing to ship \u2014 the tree is clean, pushed, and its PR is open",shipState:p};let w=ma(),m=t.why?`${t.label} \u2014 ${t.why}`:t.label;return await M(a,{type:"pr.offered",actor:"agent",source:"cli",boxId:e.leadBox??null,provider:i?.agent??null,payload:{offerId:w,ts:Date.now(),excerpt:m,via:"cli",branch:u,base:s.base||e.workspace.baseRef?.replace(/^origin\//,"")||null,boxRole:"lead",available:p?.available,defaults:p?p.defaults.filter(g=>f.includes(g)||g==="rebase"):void 0,prState:p?.prState,openPr:p?.openPr||void 0,repos:p?.repos||l,offered:p?f.filter(g=>p.available.includes(g)):f,toPr:s.toPr?{number:s.toPr}:void 0}}),{offerId:w,branch:u,offered:f,available:p?.available??null,prState:p?.prState??null}}function mT(e){let t=!1;for(let n of e)n.type==="pr.offered"&&(n.source==="cli"||n.payload?.via==="cli")?t=!0:(n.type==="turn.user"&&!n.payload?.kind||n.type==="pr.offer.answered")&&(t=!1);return t}function hT(e){let t=null;for(let n of e){let r=n.payload||{};n.type==="pr.offer.answered"?t=r.action&&r.action!=="dismiss"&&r.action!=="pr-exists"?r.offerId:null:n.type==="pr.exists.answered"?t=r.choice&&r.choice!=="dismiss"?r.offerId??t:null:(n.type==="turn.user"&&!r.kind||n.type==="followup.offered"&&r.trigger==="ship.done"&&r.context?.shipOfferId&&r.context.shipOfferId===t)&&(t=null)}return t}async function wT(e,{pull:t=Qi}={}){let{followups:n,source:r,error:o}=await t().catch(a=>({followups:[],source:"unreachable",error:a?.message})),s=e?await K({id:e.id,cwd:e.cwd}).catch(()=>[]):[];return{followups:n,source:r,error:o,arms:e?ld(s):[]}}var oT,sT,YL,aT,XL,Hh,ZL,Fh,Uh,fa,QL,Wh,rF,ud=G(()=>{fe();Go();bh();Qo();rT();ec();oT=60,sT=8*1024,YL=200,aT=["now","pr.merged","ship.done","pr.opened","checks.green","track.opened"],XL=aT.filter(e=>e!=="now"&&e!=="track.opened"),Hh={now:"now","pr.merged":"after merge","ship.done":"after ship","pr.opened":"after PR opens","checks.green":"after CI goes green","track.opened":"when a Track opens"},ZL=3,Fh=["commit","push","pr"];Uh=e=>JL("sha256").update(String(e)).digest("hex").slice(0,16),fa=e=>typeof e=="string"?e.trim():"",QL=[[/(^|[^\w&])#\d+\b/,"a PR/issue number"],[/https?:\/\/\S+/i,"a URL"],[/\b[0-9a-f]{7,40}\b/i,"a commit SHA"],[/\bv\d+\.\d+\.\d+\b/,"a release tag"]];Wh=e=>String(e?.name||"").startsWith("\u21BB");rF=e=>String(e||"").split(`
198
198
  `).slice(0,3).join(`
199
- `).slice(0,400)});import{randomUUID as GL}from"node:crypto";function Yi(e){return e.sourceId?`${e.role}|id:${e.sourceId}`:`${e.role}|${e.ts??"?"}|${String(e.text||"").slice(0,40)}`}function nA(e){return e.id?`cmd|${e.box}|id:${e.id}`:`cmd|${e.box}|${e.ts??"?"}|${String(e.command||"").slice(0,40)}`}function rA(e){return`job|${e.box}|id:${e.id}`}async function $h(e){return Ih.has(e.id)?Ih.get(e.id):(sd.has(e.id)||sd.set(e.id,K(e).then(t=>{let n={keys:new Set,cmdN:new Map};for(let r of t)if((r.type==="turn.user"||r.type==="turn.agent"||r.type==="provider.error")&&r.payload?.text!=null){let o=r.type==="turn.user"?"user":"assistant";r.payload.sourceId&&n.keys.add(Yi({role:o,sourceId:r.payload.sourceId})),n.keys.add(Yi({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(Yi({role:"user",sourceId:r.payload.sourceId})),n.keys.add(Yi({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(nA({id:o.id,box:r.boxId,ts:o.ts,command:o.command})),Number(o.n)>(n.cmdN.get(r.boxId)??0)&&n.cmdN.set(r.boxId,Number(o.n))}else r.type==="job.started"&&r.payload?.id&&n.keys.add(rA({id:r.payload.id,box:r.boxId}));return Ih.set(e.id,n),n}).finally(()=>sd.delete(e.id))),sd.get(e.id))}async function oA(e,t){let n=new Set;try{let r=(await $h(e)).keys;for(let o of t||[]){if(!o||o.ts==null||!String(o.text||"").trim()&&!o.images?.length)continue;let s=Yi(o);if(r.has(s))continue;r.add(s);let a=o.role==="user"?td(o.text):null;if(a){await M(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 PT(a,Xi),boxRole:o.boxRole,sourceId:o.sourceId||void 0}});continue}let i=Vk(o);if(i){await M(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}}),jT(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 M(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=oS(o.text);if(c&&QT(await K(e).catch(()=>[])))continue;if(c){let l=iS(c),u;if(e.workspace?.kind==="multi"){let w=await Ko(e).catch(()=>[]);u=w.length?w.map(m=>({name:m.name,slug:m.repo??null})):void 0}let d=(e.workspace?.kind==="multi"?null:await Zr(e.cwd).catch(()=>null))||e.workspace.branch,p=await Hu(e,{branch:d,rebase:l}).catch(()=>null),f=p?null:aS(c);if(p&&p.available.length===0)continue;await M(e,{type:"pr.offered",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{offerId:GL(),ts:o.ts,excerpt:c,branch:d,base:e.workspace.baseRef?.replace(/^origin\//,"")||null,boxRole:o.boxRole,available:p?.available,defaults:p?.defaults,prState:p?.prState,openPr:p?.openPr||void 0,repos:p?.repos||u,offered:p?.defaults||f?.offered||void 0,toPr:f?.toPr||void 0}})}}}}catch{}return{agentTurnBoxes:n}}async function sA(e,t){try{let n=await $h(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=nA(o);if(n.keys.has(s))continue;n.keys.add(s);let a=(n.cmdN.get(o.box)??0)+1;n.cmdN.set(o.box,a),await M(e,{type:"tool.called",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{id:o.id??null,tool:o.tool||null,command:o.command,description:o.description||"",summary:o.summary||o.command,ts:o.ts??null,boxRole:o.boxRole,n:a}}),MT(e,o),CT(e,o)}}catch{}}async function aA(e,t){try{let n=await $h(e),r=[...t||[]].filter(o=>o&&o.id).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=rA(o);n.keys.has(s)||(n.keys.add(s),await M(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 Ih,sd,iA=G(()=>{de();Do();rh();ed();qo();yh();cr();Kl();xh();od();Ih=new Map,sd=new Map});function zL(e){let t=[],n=null;for(let r of String(e||"").split(`
200
- `)){let o=r.trim();if(!o||o[0]!=="{")continue;let s;try{s=JSON.parse(o)}catch{continue}let a=s.payload||{};if(s.type==="turn_context"&&a.model&&(n=a.model),s.type==="event_msg"&&a.type==="token_count"&&a.info?.last_token_usage){let i=a.info.last_token_usage;t.push({ts:s.timestamp?Date.parse(s.timestamp):null,model:n,last:{input:i.input_tokens||0,cachedInput:i.cached_input_tokens||0,output:i.output_tokens||0,reasoningOutput:i.reasoning_output_tokens||0},occupancy:i.total_tokens??null,contextWindow:a.info.model_context_window??null})}}return t}async function VL(e,t){let n=`${e.id}:${t.name}`;if(!Rh.has(n)){let r=await K(e),o=new Set;for(let s of r)s.type==="cost.recorded"&&s.boxId===t.name&&s.payload?.codexTs!=null&&o.add(s.payload.codexTs);Rh.set(n,o)}return Rh.get(n)}async function cA(e,t){try{if(t?.agent!=="codex"||!t.cwd)return;let n=await Eo(t.cwd,t.pinned?t.sessionId:null);if(!n)return;let r=await VL(e,t),o=zL(await _t(n.file,262144)),s=o[o.length-1];for(let a of o){if(a.ts==null||r.has(a.ts))continue;r.add(a.ts);let i={input:Math.max(0,a.last.input-a.last.cachedInput),output:a.last.output,cacheRead:a.last.cachedInput,cacheWrite:0},c=a.model||t.model||"gpt-5.5";await M(e,{type:"cost.recorded",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{usd:In(c,i,a.ts),model:c,tokens:i,reasoningOutput:a.last.reasoningOutput||void 0,codexTs:a.ts,ts:a.ts}}),a===s&&a.contextWindow&&await M(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 Rh,lA=G(()=>{de();Io();an();Qn();Rh=new Map});import ad from"node:fs";import Mh from"node:path";import JL from"node:os";async function ZL({sinceMs:e,cookie:t,fetchImpl:n=fetch}){let r=[];for(let o=1;o<=20;o++){let s=await n(XL,{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:uA})});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<uA)break}return r}function QL(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 pA(){try{return JSON.parse(ad.readFileSync(id(),"utf8"))}catch{return{sinceMs:0,seen:[]}}}function tF(e){try{ad.mkdirSync(Mh.dirname(id()),{recursive:!0});let t=id()+".tmp";ad.writeFileSync(t,JSON.stringify(e)),ad.renameSync(t,id())}catch{}}async function rF({fetchImpl:e,now:t=Date.now()}={}){if(to.rows&&t-to.at<eF)return to.rows;let n=process.env.BOSTRAT_CURSOR_USAGE_COOKIE;if(!n)return null;let r=pA(),o=Math.max(r.sinceMs-6e4,t-24*36e5);try{let s=await ZL({sinceMs:o,cookie:n,fetchImpl:e});to={at:t,rows:s.map(QL).filter(Boolean),error:null}}catch(s){to={at:t,rows:null,error:String(s?.message||s)}}return to.rows}async function oF(e,t){let n=`${e.id}:${t.name}`;if(!Oh.has(n)){let r=await K(e),o=new Set;for(let s of r)s.type==="cost.recorded"&&s.boxId===t.name&&s.payload?.cursorEventId&&o.add(s.payload.cursorEventId);Oh.set(n,o)}return Oh.get(n)}async function fA(e,t,{fetchImpl:n}={}){try{if(t?.agent!=="cursor"||!t.cwd||!dA())return;let r=await rF({fetchImpl:n});if(!r||!r.length)return;let o=await Xx(t.cwd,t.pinned?t.sessionId:null);if(!o?.chatId)return;let s=await oF(e,t),a=pA(),i=new Set(a.seen||[]),c=a.sinceMs||0;for(let l of r){if(!l.conversationId||l.conversationId!==o.chatId||s.has(l.id)||i.has(`${e.id}:${t.name}:${l.id}`))continue;s.add(l.id),i.add(`${e.id}:${t.name}:${l.id}`),l.ts&&l.ts>c&&(c=l.ts);let u=l.model||o.models[o.models.length-1]||"cursor-unknown",d=l.tokens||null,p=l.vendorCents!=null?l.vendorCents/100:0;!p&&d&&(p=In(u,d,l.ts??void 0)),!p&&l.chargedCents!=null&&(p=l.chargedCents/100),await M(e,{type:"cost.recorded",actor:"agent",source:"vendor",boxId:t.name,provider:"cursor",payload:{usd:p,model:u,...d?{tokens:d}:{},...l.vendorCents!=null?{vendorCents:l.vendorCents}:{},...l.chargedCents!=null?{chargedCents:l.chargedCents}:{},...l.kind?{kind:l.kind}:{},conversationId:l.conversationId,cursorEventId:l.id,ts:l.ts??void 0}})}tF({sinceMs:c,seen:[...i].slice(-nF)})}catch{}}var YL,dA,XL,uA,eF,to,id,nF,Ch,Oh,Nh=G(()=>{de();pm();Qn();YL=process.env.BOSTRAT_STATE_DIR||Mh.join(process.env.HOME||JL.tmpdir(),".bostrat"),dA=(e=process.env)=>!!e.BOSTRAT_CURSOR_USAGE_COOKIE,XL="https://cursor.com/api/dashboard/get-filtered-usage-events",uA=100;eF=5*6e4,to={at:0,rows:null,error:null},id=()=>Mh.join(YL,"cursor-usage.json");nF=5e3;Ch=()=>({enabled:dA(),lastPollAt:to.at||null,error:to.error}),Oh=new Map});import{randomUUID as sF,createHmac as aF}from"node:crypto";function hA(e){Dh=typeof e=="string"&&e?e:null}function iF(e){if(!Dh)return null;let t=Fe(e);return t?aF("sha256",Buffer.from(Dh,"base64url")).update(t,"utf8").digest("hex").slice(0,16):null}function yA(){let e={};for(let t of gA)e[String(t)]=0;return e.inf=0,{buckets:e,sumMs:0,count:0}}function mA(e,t){let n=Math.max(0,Number(t)||0);for(let r of gA)n<=r&&(e.buckets[String(r)]+=1);e.buckets.inf+=1,e.sumMs+=n,e.count+=1}function bA(){let e={};for(let t of wA)e[t]=0;return e}function lF(){Cn={total:new Map,holds:bA(),queueWaitMs:yA(),readyWaitMs:new Map,verify:new Map,retries:new Map}}function kA({queueDepth:e=0,queueOldestAgeMs:t=0}={}){let n=Cn;return{total:[...n.total].map(([r,o])=>{let[s,a,i]=r.split("|");return{provider:s,producer:a,outcome:i,n:o}}),holds:{...n.holds},queueWaitMs:{buckets:{...n.queueWaitMs.buckets},sumMs:n.queueWaitMs.sumMs,count:n.queueWaitMs.count},readyWaitMs:[...n.readyWaitMs].map(([r,o])=>{let[s,a]=r.split("|");return{provider:s,outcome:a,buckets:{...o.buckets},sumMs:o.sumMs,count:o.count}}),verify:[...n.verify].map(([r,o])=>{let[s,a]=r.split("|");return{provider:s,verdict:a,n:o}}),retries:[...n.retries].map(([r,o])=>({provider:r,n:o})),queueDepth:Number(e)||0,queueOldestAgeMs:Number(t)||0}}function Zi({kind:e=null,producer:t=null,orchestration:n=!1}={}){return n?`orchestration:${e||"orchestration"}`:e?`scripted:${e}`:cF.has(t)?t:"composer"}function Qi({text:e="",producer:t="composer",kind:n=null,provider:r=null,attachments:o=0,now:s=Date.now}={}){let a=s();return{id:sF(),producer:t,kind:n||null,provider:r||null,textBytes:Buffer.byteLength(String(e||""),"utf8"),textHmac16:iF(e),attachments:Number(o)||0,paste:null,t0:a,queuedAt:null,dequeuedAt:null,holds:bA(),requeued:0,readyWaitMs:null,readyOutcome:null,verify:null,settled:!1,outcome:null}}async function ec(e,t,{position:n=null,reason:r="busy"}={}){!t||!e||(t.queuedAt=Date.now(),await M(e,{type:"delivery.queued",actor:"system",source:"orchestrator",boxId:e.leadBox??null,provider:t.provider,payload:{ts:t.queuedAt,deliveryId:t.id,producer:t.producer,...t.kind?{kind:t.kind}:{},reason:r,position:n,textBytes:t.textBytes,textHmac16:t.textHmac16,requeued:t.requeued}}).catch(()=>{}))}function xA(e,t){wA.includes(t)&&(e?.holds&&(e.holds[t]+=1),Cn.holds[t]+=1)}function tc(e,{ms:t,outcome:n}){e&&(e.readyWaitMs=Math.max(0,Number(t)||0),e.readyOutcome=n||null)}async function Nn(e,t,n,{now:r=Date.now}={}){if(!t||t.settled)return null;t.settled=!0,t.outcome=n;let o=r(),s=t.provider||"unknown",a=t.queuedAt!=null,i=a?Math.max(0,(t.dequeuedAt??o)-t.queuedAt):null;if(Ph(Cn.total,`${s}|${t.producer}|${n}`),a&&mA(Cn.queueWaitMs,i),t.readyWaitMs!=null){let l=`${s}|${t.readyOutcome||"unknown"}`;Cn.readyWaitMs.has(l)||Cn.readyWaitMs.set(l,yA()),mA(Cn.readyWaitMs.get(l),t.readyWaitMs)}t.verify?.verdict&&(Ph(Cn.verify,`${s}|${t.verify.verdict}`),t.verify.retries&&Ph(Cn.retries,s,t.verify.retries));let c={ts:o,deliveryId:t.id,producer:t.producer,...t.kind?{kind:t.kind}:{},cliVersion:null,textBytes:t.textBytes,textHmac16:t.textHmac16,paste:t.paste,attachments:t.attachments,outcome:n,queued:a,queueWaitMs:i,queueHolds:{...t.holds},requeued:t.requeued,readyWaitMs:t.readyWaitMs,readyOutcome:t.readyOutcome,verify:t.verify?{...t.verify}:null,receiptMs:null,totalMs:Math.max(0,o-t.t0)};return e&&await M(e,{type:"delivery.settled",actor:"system",source:"orchestrator",boxId:e.leadBox??null,provider:t.provider,payload:c}).catch(()=>{}),c}function aa(e){if(e?.usageCap)return"refused:cap";if(e?.interrupted)return"interrupted";if(e?.code)return`failed:${e.code}`;let t=String(e?.message||"");return/not running/i.test(t)?"failed:not-running":/archived/i.test(t)?"failed:archived":/blocked on an interactive prompt|isn't signed in|is waiting on its|stuck on its update/i.test(t)?"failed:blocked":"failed:error"}var Dh,wA,gA,cF,Cn,Ph,Bh=G(()=>{de();vi();Dh=null;wA=["busy","prompt","handoff","noSession","cap","grace"],gA=[500,2e3,1e4,6e4,6e5],cF=new Set(["composer","voice","loop"]);Cn=null;lF();Ph=(e,t,n=1)=>e.set(t,(e.get(t)||0)+n)});import oc from"node:fs/promises";import It from"node:path";import uF from"node:os";import dF from"node:net";import{randomUUID as pF}from"node:crypto";import{execFile as fF}from"node:child_process";import{promisify as mF}from"node:util";function xF(e){for(let t of Wh(e))if(!_A.test(t))return t;return null}function IA(e){let t=Wh(e),n=t.indexOf("--");return n===-1?t:t.slice(0,n)}function vF(e,t){let n=IA(t);for(let r=0;r<n.length;r++){let o=/^--prefix=(.+)$/.exec(n[r]);if(o)return It.resolve(e,o[1]);if(n[r]==="--prefix"&&n[r+1])return It.resolve(e,n[r+1])}return e}function TF(e){let t=!1,n=!1;for(let r of Wh(e)){if(!t){if(_A.test(r))continue;t=!0;continue}if(r.startsWith("-")){let o=r.indexOf("="),s=o===-1?null:r.slice(o+1);if(s&&jh(s))return`serves the filesystem root ("${s}")`;n=o===-1;continue}if(n){if(n=!1,jh(r))return`serves the filesystem root ("${r}")`;continue}if(jh(r))return`serves the filesystem root ("${r}")`;if(SF(r))return`serves a path that escapes the workspace ("${r}")`}return null}async function EF(e,t){if(It.resolve(e)===It.resolve(t))return!0;let[n,r]=await Promise.all([cd(e),cd(t)]);return n===r}async function _F(e){let n=(await oc.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 $A(It.join(e,o.name,Uh))?`./${o.name}`:null))).filter(Boolean)}async function IF(e,t){let[n,r]=await Promise.all([cd(e),cd(t)]),o=It.relative(n,r);if(o&&(o.startsWith("..")||It.isAbsolute(o)))throw nc(`serve directory escapes the Track workspace: ${t}`)}async function $F(e,t){let n=TF(t);if(n)throw nc(`refusing this view: the command ${n} \u2014 serve a build dir, not the filesystem root`);if(!await AF(e))throw nc(`serve directory does not exist: ${e}`);let r=xF(t);if(!r)return;if(!r.includes("/")&&!await kk(r,{loginShell:!0,failOpen:!0}))throw nc(`\`${r}\` is not on the box's PATH \u2014 install it in the box first`);if(yF.test(t)||bF.has(r)||!gF.has(r)||!IA(t).includes("run")||kF.test(t))return;let o=vF(e,t);if(await $A(It.join(o,Uh)))return;let s=await _F(o),a=s.length?` \u2014 found one in ${s.join(", ")}; run bostrat-view from there`:"";throw nc(`no ${Uh} in ${o}${a}`)}async function dr(){return Pn||(Lh||=(async()=>{try{Pn=JSON.parse(await oc.readFile(EA,"utf8"))}catch{Pn={views:[],adoptWatermarks:{}}}finally{Lh=null}return Pn.views||=[],Pn.adoptWatermarks||={},Pn})(),Lh)}async function Bn(){await Et(EA,Pn)}function ur(e,t,n={}){return M({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 Gh(e){return rc.get(e)||null}function OA(e,{name:t,box:n}={}){let r=rc.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 rc.set(e,o),o}function Hh(e,t){let n=rc.get(e);n&&!n.finishedAt&&!n.viewId&&(n.viewId=t,n.step="booting")}function ld(e,{error:t=null}={}){let n=rc.get(e);return!n||n.finishedAt?null:(n.finishedAt=Date.now(),t&&(n.error=t),n)}function MA(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 qh(e){return String(e||"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40).replace(/-+$/g,"")||"view"}function RF(e,t){let n=qh(t),r=new Set(e.views.map(o=>o.slug));if(!r.has(n)&&!TA.has(n))return n;for(let o=2;;o++){let s=`${n}-${o}`;if(!r.has(s)&&!TA.has(s))return s}}function sc(e,{timeoutMs:t=1200}={}){return new Promise(n=>{let r=dF.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 zh(e){if(process.platform!=="darwin"){await Dn("fuser",["-k",`${e}/tcp`]).catch(()=>{});return}let t="";try{({stdout:t}=await Dn("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 CA(e=process.env){return new Set([Number(e.PORT)||3362,Number(e.BOSTRAT_TLS_PORT)||3443])}async function OF(e,t){let n=new Set(e.views.map(o=>o.port)),r=CA();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=vA;o<=SA;o++)if(!(n.has(o)||r.has(o))&&!await sc(o,{timeoutMs:250}))return o;throw new Error(`no free view port in ${vA}-${SA}`)}async function MF(e){try{let{stdout:t}=await Dn(Y,Z("list-sessions","-F","#{session_name}"));return t.split(`
201
- `).some(n=>n.trim()===ia(e))}catch{return!1}}async function ac(e){try{await Dn(Y,Z("kill-session","-t",ia(e)))}catch{}}async function Vh(e){if(!await ci())throw new Error("host tmux server not running and auto-start failed \u2014 cannot spawn a view server");let t=ia(e.slug),n=e.serveCwd??e.cwd,r=It.dirname(process.execPath);await Dn(Y,Z("new-session","-d","-s",t,"-c",n)),await Dn(Y,Z("send-keys","-t",t,"-l",`export PORT=${e.port} PATH="${r}:$PATH"`)),await Dn(Y,Z("send-keys","-t",t,"Enter")),await Dn(Y,Z("send-keys","-t",t,"-l",e.cmd)),await Dn(Y,Z("send-keys","-t",t,"Enter"))}async function AA(e,t=12){try{let{stdout:n}=await Dn(Y,Z("capture-pane","-t",ia(e),"-p"));return String(n||"").trimEnd().split(`
199
+ `).slice(0,400)});import{randomUUID as iF}from"node:crypto";function nc(e){return e.sourceId?`${e.role}|id:${e.sourceId}`:`${e.role}|${e.ts??"?"}|${String(e.text||"").slice(0,40)}`}function gT(e){return e.id?`cmd|${e.box}|id:${e.id}`:`cmd|${e.box}|${e.ts??"?"}|${String(e.command||"").slice(0,40)}`}function yT(e){return`job|${e.box}|id:${e.id}`}async function Kh(e){return qh.has(e.id)?qh.get(e.id):(dd.has(e.id)||dd.set(e.id,K(e).then(t=>{let n={keys:new Set,cmdN:new Map};for(let r of t)if((r.type==="turn.user"||r.type==="turn.agent"||r.type==="provider.error")&&r.payload?.text!=null){let o=r.type==="turn.user"?"user":"assistant";r.payload.sourceId&&n.keys.add(nc({role:o,sourceId:r.payload.sourceId})),n.keys.add(nc({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(nc({role:"user",sourceId:r.payload.sourceId})),n.keys.add(nc({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(gT({id:o.id,box:r.boxId,ts:o.ts,command:o.command})),Number(o.n)>(n.cmdN.get(r.boxId)??0)&&n.cmdN.set(r.boxId,Number(o.n))}else r.type==="job.started"&&r.payload?.id&&n.keys.add(yT({id:r.payload.id,box:r.boxId}));return qh.set(e.id,n),n}).finally(()=>dd.delete(e.id))),dd.get(e.id))}async function bT(e,t){let n=new Set;try{let r=(await Kh(e)).keys;for(let o of t||[]){if(!o||o.ts==null||!String(o.text||"").trim()&&!o.images?.length)continue;let s=nc(o);if(r.has(s))continue;r.add(s);let a=o.role==="user"?id(o.text):null;if(a){await M(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 YA(a,rc),boxRole:o.boxRole,sourceId:o.sourceId||void 0}});continue}let i=u0(o);if(i){await M(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}}),QA(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 M(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=bS(o.text);if(c&&mT(await K(e).catch(()=>[])))continue;if(c){let l=vS(c),u;if(e.workspace?.kind==="multi"){let w=await ts(e).catch(()=>[]);u=w.length?w.map(m=>({name:m.name,slug:m.repo??null})):void 0}let d=(e.workspace?.kind==="multi"?null:await ro(e.cwd).catch(()=>null))||e.workspace.branch,p=await Vu(e,{branch:d,rebase:l}).catch(()=>null),f=p?null:xS(c);if(p&&p.available.length===0)continue;await M(e,{type:"pr.offered",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{offerId:iF(),ts:o.ts,excerpt:c,branch:d,base:e.workspace.baseRef?.replace(/^origin\//,"")||null,boxRole:o.boxRole,available:p?.available,defaults:p?.defaults,prState:p?.prState,openPr:p?.openPr||void 0,repos:p?.repos||u,offered:p?.defaults||f?.offered||void 0,toPr:f?.toPr||void 0}})}}}}catch{}return{agentTurnBoxes:n}}async function kT(e,t){try{let n=await Kh(e),r=[...t||[]].filter(o=>o&&String(o.command||"").trim()).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=gT(o);if(n.keys.has(s))continue;n.keys.add(s);let a=(n.cmdN.get(o.box)??0)+1;n.cmdN.set(o.box,a),await M(e,{type:"tool.called",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{id:o.id??null,tool:o.tool||null,command:o.command,description:o.description||"",summary:o.summary||o.command,ts:o.ts??null,boxRole:o.boxRole,n:a}}),zA(e,o),VA(e,o)}}catch{}}async function xT(e,t){try{let n=await Kh(e),r=[...t||[]].filter(o=>o&&o.id).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=yT(o);n.keys.has(s)||(n.keys.add(s),await M(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 qh,dd,vT=G(()=>{fe();Go();bh();ad();Qo();Nh();pr();Yl();Bh();ud();qh=new Map,dd=new Map});function cF(e){let t=[],n=null;for(let r of String(e||"").split(`
200
+ `)){let o=r.trim();if(!o||o[0]!=="{")continue;let s;try{s=JSON.parse(o)}catch{continue}let a=s.payload||{};if(s.type==="turn_context"&&a.model&&(n=a.model),s.type==="event_msg"&&a.type==="token_count"&&a.info?.last_token_usage){let i=a.info.last_token_usage;t.push({ts:s.timestamp?Date.parse(s.timestamp):null,model:n,last:{input:i.input_tokens||0,cachedInput:i.cached_input_tokens||0,output:i.output_tokens||0,reasoningOutput:i.reasoning_output_tokens||0},occupancy:i.total_tokens??null,contextWindow:a.info.model_context_window??null})}}return t}async function lF(e,t){let n=`${e.id}:${t.name}`;if(!Gh.has(n)){let r=await K(e),o=new Set;for(let s of r)s.type==="cost.recorded"&&s.boxId===t.name&&s.payload?.codexTs!=null&&o.add(s.payload.codexTs);Gh.set(n,o)}return Gh.get(n)}async function ST(e,t){try{if(t?.agent!=="codex"||!t.cwd)return;let n=await Mo(t.cwd,t.pinned?t.sessionId:null);if(!n)return;let r=await lF(e,t),o=cF(await Rt(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 M(e,{type:"cost.recorded",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{usd:On(c,i,a.ts),model:c,tokens:i,reasoningOutput:a.last.reasoningOutput||void 0,codexTs:a.ts,ts:a.ts}}),a===s&&a.contextWindow&&await M(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 Gh,AT=G(()=>{fe();No();cn();rr();Gh=new Map});import pd from"node:fs";import Vh from"node:path";import uF from"node:os";async function fF({sinceMs:e,cookie:t,fetchImpl:n=fetch}){let r=[];for(let o=1;o<=20;o++){let s=await n(pF,{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:TT})});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<TT)break}return r}function mF(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 _T(){try{return JSON.parse(pd.readFileSync(fd(),"utf8"))}catch{return{sinceMs:0,seen:[]}}}function wF(e){try{pd.mkdirSync(Vh.dirname(fd()),{recursive:!0});let t=fd()+".tmp";pd.writeFileSync(t,JSON.stringify(e)),pd.renameSync(t,fd())}catch{}}async function yF({fetchImpl:e,now:t=Date.now()}={}){if(ao.rows&&t-ao.at<hF)return ao.rows;let n=process.env.BOSTRAT_CURSOR_USAGE_COOKIE;if(!n)return null;let r=_T(),o=Math.max(r.sinceMs-6e4,t-24*36e5);try{let s=await fF({sinceMs:o,cookie:n,fetchImpl:e});ao={at:t,rows:s.map(mF).filter(Boolean),error:null}}catch(s){ao={at:t,rows:null,error:String(s?.message||s)}}return ao.rows}async function bF(e,t){let n=`${e.id}:${t.name}`;if(!zh.has(n)){let r=await K(e),o=new Set;for(let s of r)s.type==="cost.recorded"&&s.boxId===t.name&&s.payload?.cursorEventId&&o.add(s.payload.cursorEventId);zh.set(n,o)}return zh.get(n)}async function IT(e,t,{fetchImpl:n}={}){try{if(t?.agent!=="cursor"||!t.cwd||!ET())return;let r=await yF({fetchImpl:n});if(!r||!r.length)return;let o=await mv(t.cwd,t.pinned?t.sessionId:null);if(!o?.chatId)return;let s=await bF(e,t),a=_T(),i=new Set(a.seen||[]),c=a.sinceMs||0;for(let l of r){if(!l.conversationId||l.conversationId!==o.chatId||s.has(l.id)||i.has(`${e.id}:${t.name}:${l.id}`))continue;s.add(l.id),i.add(`${e.id}:${t.name}:${l.id}`),l.ts&&l.ts>c&&(c=l.ts);let u=l.model||o.models[o.models.length-1]||"cursor-unknown",d=l.tokens||null,p=l.vendorCents!=null?l.vendorCents/100:0;!p&&d&&(p=On(u,d,l.ts??void 0)),!p&&l.chargedCents!=null&&(p=l.chargedCents/100),await M(e,{type:"cost.recorded",actor:"agent",source:"vendor",boxId:t.name,provider:"cursor",payload:{usd:p,model:u,...d?{tokens:d}:{},...l.vendorCents!=null?{vendorCents:l.vendorCents}:{},...l.chargedCents!=null?{chargedCents:l.chargedCents}:{},...l.kind?{kind:l.kind}:{},conversationId:l.conversationId,cursorEventId:l.id,ts:l.ts??void 0}})}wF({sinceMs:c,seen:[...i].slice(-gF)})}catch{}}var dF,ET,pF,TT,hF,ao,fd,gF,Jh,zh,Yh=G(()=>{fe();Em();rr();dF=process.env.BOSTRAT_STATE_DIR||Vh.join(process.env.HOME||uF.tmpdir(),".bostrat"),ET=(e=process.env)=>!!e.BOSTRAT_CURSOR_USAGE_COOKIE,pF="https://cursor.com/api/dashboard/get-filtered-usage-events",TT=100;hF=5*6e4,ao={at:0,rows:null,error:null},fd=()=>Vh.join(dF,"cursor-usage.json");gF=5e3;Jh=()=>({enabled:ET(),lastPollAt:ao.at||null,error:ao.error}),zh=new Map});import{randomUUID as kF,createHmac as xF}from"node:crypto";function RT(e){Zh=typeof e=="string"&&e?e:null}function vF(e){if(!Zh)return null;let t=Fe(e);return t?xF("sha256",Buffer.from(Zh,"base64url")).update(t,"utf8").digest("hex").slice(0,16):null}function CT(){let e={};for(let t of MT)e[String(t)]=0;return e.inf=0,{buckets:e,sumMs:0,count:0}}function $T(e,t){let n=Math.max(0,Number(t)||0);for(let r of MT)n<=r&&(e.buckets[String(r)]+=1);e.buckets.inf+=1,e.sumMs+=n,e.count+=1}function NT(){let e={};for(let t of OT)e[t]=0;return e}function AF(){Dn={total:new Map,holds:NT(),queueWaitMs:CT(),readyWaitMs:new Map,verify:new Map,retries:new Map}}function PT({queueDepth:e=0,queueOldestAgeMs:t=0}={}){let n=Dn;return{total:[...n.total].map(([r,o])=>{let[s,a,i]=r.split("|");return{provider:s,producer:a,outcome:i,n:o}}),holds:{...n.holds},queueWaitMs:{buckets:{...n.queueWaitMs.buckets},sumMs:n.queueWaitMs.sumMs,count:n.queueWaitMs.count},readyWaitMs:[...n.readyWaitMs].map(([r,o])=>{let[s,a]=r.split("|");return{provider:s,outcome:a,buckets:{...o.buckets},sumMs:o.sumMs,count:o.count}}),verify:[...n.verify].map(([r,o])=>{let[s,a]=r.split("|");return{provider:s,verdict:a,n:o}}),retries:[...n.retries].map(([r,o])=>({provider:r,n:o})),queueDepth:Number(e)||0,queueOldestAgeMs:Number(t)||0}}function oc({kind:e=null,producer:t=null,orchestration:n=!1}={}){return n?`orchestration:${e||"orchestration"}`:e?`scripted:${e}`:SF.has(t)?t:"composer"}function sc({text:e="",producer:t="composer",kind:n=null,provider:r=null,attachments:o=0,now:s=Date.now}={}){let a=s();return{id:kF(),producer:t,kind:n||null,provider:r||null,textBytes:Buffer.byteLength(String(e||""),"utf8"),textHmac16:vF(e),attachments:Number(o)||0,paste:null,t0:a,queuedAt:null,dequeuedAt:null,holds:NT(),requeued:0,readyWaitMs:null,readyOutcome:null,verify:null,settled:!1,outcome:null}}async function ac(e,t,{position:n=null,reason:r="busy"}={}){!t||!e||(t.queuedAt=Date.now(),await M(e,{type:"delivery.queued",actor:"system",source:"orchestrator",boxId:e.leadBox??null,provider:t.provider,payload:{ts:t.queuedAt,deliveryId:t.id,producer:t.producer,...t.kind?{kind:t.kind}:{},reason:r,position:n,textBytes:t.textBytes,textHmac16:t.textHmac16,requeued:t.requeued}}).catch(()=>{}))}function DT(e,t){OT.includes(t)&&(e?.holds&&(e.holds[t]+=1),Dn.holds[t]+=1)}function ic(e,{ms:t,outcome:n}){e&&(e.readyWaitMs=Math.max(0,Number(t)||0),e.readyOutcome=n||null)}async function Bn(e,t,n,{now:r=Date.now}={}){if(!t||t.settled)return null;t.settled=!0,t.outcome=n;let o=r(),s=t.provider||"unknown",a=t.queuedAt!=null,i=a?Math.max(0,(t.dequeuedAt??o)-t.queuedAt):null;if(Xh(Dn.total,`${s}|${t.producer}|${n}`),a&&$T(Dn.queueWaitMs,i),t.readyWaitMs!=null){let l=`${s}|${t.readyOutcome||"unknown"}`;Dn.readyWaitMs.has(l)||Dn.readyWaitMs.set(l,CT()),$T(Dn.readyWaitMs.get(l),t.readyWaitMs)}t.verify?.verdict&&(Xh(Dn.verify,`${s}|${t.verify.verdict}`),t.verify.retries&&Xh(Dn.retries,s,t.verify.retries));let c={ts:o,deliveryId:t.id,producer:t.producer,...t.kind?{kind:t.kind}:{},cliVersion:null,textBytes:t.textBytes,textHmac16:t.textHmac16,paste:t.paste,attachments:t.attachments,outcome:n,queued:a,queueWaitMs:i,queueHolds:{...t.holds},requeued:t.requeued,readyWaitMs:t.readyWaitMs,readyOutcome:t.readyOutcome,verify:t.verify?{...t.verify}:null,receiptMs:null,totalMs:Math.max(0,o-t.t0)};return e&&await M(e,{type:"delivery.settled",actor:"system",source:"orchestrator",boxId:e.leadBox??null,provider:t.provider,payload:c}).catch(()=>{}),c}function ha(e){if(e?.usageCap)return"refused:cap";if(e?.interrupted)return"interrupted";if(e?.code)return`failed:${e.code}`;let t=String(e?.message||"");return/not running/i.test(t)?"failed:not-running":/archived/i.test(t)?"failed:archived":/blocked on an interactive prompt|isn't signed in|is waiting on its|stuck on its update/i.test(t)?"failed:blocked":"failed:error"}var Zh,OT,MT,SF,Dn,Xh,Qh=G(()=>{fe();$i();Zh=null;OT=["busy","prompt","handoff","noSession","cap","grace"],MT=[500,2e3,1e4,6e4,6e5],SF=new Set(["composer","voice","loop"]);Dn=null;AF();Xh=(e,t,n=1)=>e.set(t,(e.get(t)||0)+n)});import uc from"node:fs/promises";import Ot from"node:path";import TF from"node:os";import EF from"node:net";import{randomUUID as _F}from"node:crypto";import{execFile as IF}from"node:child_process";import{promisify as $F}from"node:util";function DF(e){for(let t of aw(e))if(!HT.test(t))return t;return null}function WT(e){let t=aw(e),n=t.indexOf("--");return n===-1?t:t.slice(0,n)}function BF(e,t){let n=WT(t);for(let r=0;r<n.length;r++){let o=/^--prefix=(.+)$/.exec(n[r]);if(o)return Ot.resolve(e,o[1]);if(n[r]==="--prefix"&&n[r+1])return Ot.resolve(e,n[r+1])}return e}function LF(e){let t=!1,n=!1;for(let r of aw(e)){if(!t){if(HT.test(r))continue;t=!0;continue}if(r.startsWith("-")){let o=r.indexOf("="),s=o===-1?null:r.slice(o+1);if(s&&ew(s))return`serves the filesystem root ("${s}")`;n=o===-1;continue}if(n){if(n=!1,ew(r))return`serves the filesystem root ("${r}")`;continue}if(ew(r))return`serves the filesystem root ("${r}")`;if(jF(r))return`serves a path that escapes the workspace ("${r}")`}return null}async function UF(e,t){if(Ot.resolve(e)===Ot.resolve(t))return!0;let[n,r]=await Promise.all([md(e),md(t)]);return n===r}async function HF(e){let n=(await uc.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 qT(Ot.join(e,o.name,rw))?`./${o.name}`:null))).filter(Boolean)}async function WF(e,t){let[n,r]=await Promise.all([md(e),md(t)]),o=Ot.relative(n,r);if(o&&(o.startsWith("..")||Ot.isAbsolute(o)))throw cc(`serve directory escapes the Track workspace: ${t}`)}async function qF(e,t){let n=LF(t);if(n)throw cc(`refusing this view: the command ${n} \u2014 serve a build dir, not the filesystem root`);if(!await FF(e))throw cc(`serve directory does not exist: ${e}`);let r=DF(t);if(!r)return;if(!r.includes("/")&&!await Dk(r,{loginShell:!0,failOpen:!0}))throw cc(`\`${r}\` is not on the box's PATH \u2014 install it in the box first`);if(CF.test(t)||NF.has(r)||!MF.has(r)||!WT(t).includes("run")||PF.test(t))return;let o=BF(e,t);if(await qT(Ot.join(o,rw)))return;let s=await HF(o),a=s.length?` \u2014 found one in ${s.join(", ")}; run bostrat-view from there`:"";throw cc(`no ${rw} in ${o}${a}`)}async function hr(){return jn||(tw||=(async()=>{try{jn=JSON.parse(await uc.readFile(UT,"utf8"))}catch{jn={views:[],adoptWatermarks:{}}}finally{tw=null}return jn.views||=[],jn.adoptWatermarks||={},jn})(),tw)}async function Fn(){await It(UT,jn)}function mr(e,t,n={}){return M({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 cw(e){return lc.get(e)||null}function GT(e,{name:t,box:n}={}){let r=lc.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 lc.set(e,o),o}function ow(e,t){let n=lc.get(e);n&&!n.finishedAt&&!n.viewId&&(n.viewId=t,n.step="booting")}function hd(e,{error:t=null}={}){let n=lc.get(e);return!n||n.finishedAt?null:(n.finishedAt=Date.now(),t&&(n.error=t),n)}function zT(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 sw(e){return String(e||"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40).replace(/-+$/g,"")||"view"}function KF(e,t){let n=sw(t),r=new Set(e.views.map(o=>o.slug));if(!r.has(n)&&!LT.has(n))return n;for(let o=2;;o++){let s=`${n}-${o}`;if(!r.has(s)&&!LT.has(s))return s}}function dc(e,{timeoutMs:t=1200}={}){return new Promise(n=>{let r=EF.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 lw(e){if(process.platform!=="darwin"){await Ln("fuser",["-k",`${e}/tcp`]).catch(()=>{});return}let t="";try{({stdout:t}=await Ln("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 VT(e=process.env){return new Set([Number(e.PORT)||3362,Number(e.BOSTRAT_TLS_PORT)||3443])}async function GF(e,t){let n=new Set(e.views.map(o=>o.port)),r=VT();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=BT;o<=jT;o++)if(!(n.has(o)||r.has(o))&&!await dc(o,{timeoutMs:250}))return o;throw new Error(`no free view port in ${BT}-${jT}`)}async function zF(e){try{let{stdout:t}=await Ln(ee,ne("list-sessions","-F","#{session_name}"));return t.split(`
201
+ `).some(n=>n.trim()===wa(e))}catch{return!1}}async function pc(e){try{await Ln(ee,ne("kill-session","-t",wa(e)))}catch{}}async function uw(e){if(!await wi())throw new Error("host tmux server not running and auto-start failed \u2014 cannot spawn a view server");let t=wa(e.slug),n=e.serveCwd??e.cwd,r=Ot.dirname(process.execPath);await Ln(ee,ne("new-session","-d","-s",t,"-c",n)),await Ln(ee,ne("send-keys","-t",t,"-l",`export PORT=${e.port} PATH="${r}:$PATH"`)),await Ln(ee,ne("send-keys","-t",t,"Enter")),await Ln(ee,ne("send-keys","-t",t,"-l",e.cmd)),await Ln(ee,ne("send-keys","-t",t,"Enter"))}async function FT(e,t=12){try{let{stdout:n}=await Ln(ee,ne("capture-pane","-t",wa(e),"-p"));return String(n||"").trimEnd().split(`
202
202
  `).filter(Boolean).slice(-t).join(`
203
- `)}catch{return""}}async function NF(e){if(e.state==="stopped"||e.state==="error")return!1;let t=e.origin!=="detected",n=t?await MF(e.slug):!0;if(t&&!n){let s=e.state==="starting";return e.state=s?"error":"stopped",s&&(e.error=await AA(e.slug)||"server exited before listening"),lr.delete(e.id),await ur(e,e.state,e.error?{error:e.error}:{}),!0}if(await sc(e.port))return lr.delete(e.id),e.lastHealthyAt=Date.now(),e.state!=="live"?(e.state="live",e.error=null,await ur(e,"live"),!0):!1;if(e.state==="starting")return Date.now()-e.createdAt>CF?(e.state="error",e.error=await AA(e.slug)||"never started listening",await ur(e,"error",{error:e.error}),!0):!1;let o=(lr.get(e.id)||0)+1;return lr.set(e.id,o),o>=3&&e.state==="live"?(e.state="unhealthy",!0):!1}async function ud(){if(!Fh){Fh=!0;try{let e=await dr(),t=!1;for(let n of e.views)await NF(n)&&(t=!0);t&&await Bn()}finally{Fh=!1}}}async function Jh({trackId:e}={}){await ud();let t=await dr();return(e?t.views.filter(r=>r.trackId===e):t.views).map(r=>({...r}))}async function NA(e){let n=(await dr()).views.find(r=>r.id===e);return n?{...n}:null}function Yh(e){return Pn&&Pn.views.find(t=>t.slug===e)||null}async function Xh({trackId:e,name:t,cmd:n,cwd:r,serveCwd:o,port:s,box:a,origin:i="agent",branch:c=null}){if(!e)throw new Error("trackId required");if(typeof t!="string"||!t.trim())throw new Error("name (string) required");if(i!=="detected"&&(typeof n!="string"||!n.trim()))throw new Error("cmd (string) required");if(!r)throw new Error("cwd required");let l=o!=null,u=It.resolve(r,o??"."),d=i==="detected"?null:async()=>{await IF(r,u),await $F(u,n)},p=await dr();if(i!=="detected"){let m=qh(t),g=String(n).trim(),y=p.views.find(x=>x.trackId===e&&(x.slug===m||qh(x.name)===m||x.cmd===g&&It.resolve(x.serveCwd??x.cwd)===u));if(y)return PF(p,y,{cmd:g,box:a,branch:c,serveCwd:l?u:void 0,validate:d})}if(d&&await d(),p.views.filter(m=>m.state==="live"||m.state==="starting").length>=no)throw new Error(`view cap reached (${no} live) \u2014 stop one first`);let w={id:pF().slice(0,8),trackId:e,box:a||null,name:t.trim(),slug:RF(p,t),cmd:n?String(n).trim():null,cwd:r,serveCwd:u,branch:c,port:await OF(p,s),origin:i,state:"starting",error:null,createdAt:Date.now(),lastHealthyAt:null};return i!=="detected"&&await Vh(w),p.views.push(w),await Bn(),await ur(w,"created",{origin:i}),Hh(e,w.id),i==="detected"&&await sc(w.port)&&(w.state="live",w.lastHealthyAt=Date.now(),await Bn(),await ur(w,"live")),{...w}}async function PF(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 EF(t.serveCwd??t.cwd,s);if((t.state==="live"||t.state==="starting")&&!i&&!c&&await sc(t.port))return await Bn(),Hh(t.trackId,t.id),{...t,reused:!0};if(a&&await a(),e.views.filter(d=>d.id!==t.id&&(d.state==="live"||d.state==="starting")).length>=no)throw new Error(`view cap reached (${no} live) \u2014 stop one first`);return t.origin==="detected"?(await zh(t.port),t.origin="agent"):await ac(t.slug),t.cmd=n,s!==void 0&&(t.serveCwd=s),t.state="starting",t.error=null,t.createdAt=Date.now(),lr.delete(t.id),await Vh(t),await Bn(),await ur(t,"created",{restarted:!0,reused:!0}),Hh(t.trackId,t.id),{...t,reused:!0}}async function PA(e){let n=(await dr()).views.find(r=>r.id===e);if(!n)throw new Error("view not found");return n.origin==="detected"?await zh(n.port):await ac(n.slug),n.state!=="stopped"&&(n.state="stopped",lr.delete(n.id),await Bn(),await ur(n,"stopped")),{...n}}async function DA(e){let t=await dr(),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>=no)throw new Error(`view cap reached (${no} live) \u2014 stop one first`);return await ac(n.slug),n.state="starting",n.error=null,n.createdAt=Date.now(),lr.delete(n.id),await Vh(n),await Bn(),await ur(n,"created",{restarted:!0}),{...n}}async function BA(e){let t=await dr(),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 zh(r.port):await ac(r.slug),t.views.splice(n,1),lr.delete(r.id),await Bn(),await ur(r,"deleted"),{ok:!0,id:e,slug:r.slug}}async function jA(e){let t=await dr(),n=t.views.filter(r=>r.trackId===e);for(let r of n)r.origin!=="detected"&&await ac(r.slug),lr.delete(r.id);return n.length&&(t.views=t.views.filter(r=>r.trackId!==e),await Bn()),n.length}async function LA(e,t){if(!e?.id||!Array.isArray(t)||!t.length)return[];let n=await dr(),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 Bn()),!o.length)return[];let a=new Set;for(let c of o)for(let l of String(c.text||"").matchAll(DF)){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(!CA().has(c)&&!n.views.some(l=>l.port===c)&&await sc(c))try{i.push(await Xh({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 Dn,hF,EA,vA,SA,no,wF,ia,TA,nc,gF,Uh,yF,bF,kF,Wh,_A,jh,SF,AF,$A,cd,Pn,Lh,rc,Kh,RA,lr,CF,Fh,DF,dd=G(()=>{ct();de();Er();Dn=mF(fF),hF=process.env.BOSTRAT_STATE_DIR||It.join(process.env.HOME||uF.tmpdir(),".bostrat"),EA=It.join(hF,"views.json"),[vA,SA]=(process.env.BOSTRAT_VIEW_PORTS||"4300-4349").split("-").map(e=>Number(e)||0),no=Number(process.env.BOSTRAT_VIEW_MAX)||3,wF="bostrat-view-",ia=e=>`${wF}${e}`,TA=new Set(["bostrat","www","api","views","app"]),nc=e=>Object.assign(new Error(e),{status:400}),gF=new Set(["npm","pnpm","yarn","bun"]),Uh="package.json",yF=/[|;&`]|\$\(/,bF=new Set(["sh","bash","zsh","dash","env","exec","nohup","time"]),kF=/(^|\s)(-C|--cwd|--manifest-path|--dir)(=|\s)/,Wh=e=>String(e).trim().split(/\s+/).filter(Boolean),_A=/^[A-Za-z_][A-Za-z0-9_]*=/;jh=e=>e==="/",SF=e=>e===".."||e.startsWith("../")||e.includes("/../")||e.endsWith("/..");AF=e=>oc.stat(e).then(t=>t.isDirectory(),()=>!1),$A=e=>oc.stat(e).then(t=>t.isFile(),()=>!1),cd=e=>oc.realpath(e).catch(()=>It.resolve(e));Pn=null,Lh=null;rc=new Map,Kh=Number(process.env.BOSTRAT_VIEW_JOB_TIMEOUT)||3e5,RA=12e3;lr=new Map,CF=12e4;Fh=!1;DF=/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::(\d{2,5}))?(?:\/|\b)/g});function ca(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>Qh?null:n}function jF(e,t){return e?.firstSeen==null||t?.ts==null||e.firstSeen<t.ts}async function pd(e,{bypassThrottle:t=!1}={}){let n=e?.workspace?.branch;if(!n)return;let r;try{r=await K(e)}catch{return}let o=ca(r);if(o==null)return;let s=(e.boxes||[]).find(d=>d.name===e.leadBox);if(await Ho(e.leadBox,s?.agent).catch(()=>!1))return;let a=Date.now();if(!t&&a-(Zh.get(e.id)||0)<BF)return;Zh.set(e.id,a);let i;try{i=await On(e.cwd,{caller:"reconcile"})}catch{return}let c=await ta(e).catch(()=>[n]),l=(i||[]).find(d=>c.includes(d.headRefName));if(!l)return;let u=await _e(e.cwd).catch(()=>null);if(u){let{link:d,created:p}=await Mt({repo:u,number:l.number,trackId:e.id,url:l.url,headRef:l.headRefName||n,title:l.title,source:"reconciled"});if(!p&&!(d?.trackId===e.id&&await tr(u,l.number))){if(!jF(d,o))return;let f=await K(e).catch(()=>null);if(f&&ca(f)==null)return;await M(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:{ts:Date.now(),change:"pushed",number:l.number,url:l.url,title:l.title,branch:n,repo:u}});return}}await M(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:{ts:Date.now(),change:"opened",number:l.number,url:l.url,title:l.title,branch:n,...u?{repo:u}:{}}}).catch(()=>{}),Zh.delete(e.id)}var BF,Zh,Qh,ic=G(()=>{de();Uo();Tr();Rn();qi();qo();BF=6e3,Zh=new Map,Qh=30*6e4});import ew from"node:os";import{execFile as LF}from"node:child_process";import{promisify as FF}from"node:util";async function fd(){if(process.platform!=="darwin")return ew.freemem();try{let{stdout:e}=await UF("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:ew.freemem()}catch{return ew.freemem()}}var UF,tw=G(()=>{UF=FF(LF)});import Xe from"node:fs/promises";import et from"node:path";import qA from"node:os";import{randomUUID as HF}from"node:crypto";import{execFile as qF}from"node:child_process";import{promisify as WF}from"node:util";import{chromium as KF}from"playwright-core";async function Fn(){return Go||(nw||=(async()=>{try{Go=JSON.parse(await Xe.readFile(KA,"utf8"))}catch{Go={mocks:[]}}finally{nw=null}return Go.mocks||=[],Go})(),nw)}async function Jt(){await Et(KA,Go)}function JA(e,t){Ln(e,t.v,t.videoRel?.endsWith(".webm")?"webm":"mp4"),t.posterRel&&Ln(e,t.v,"png")}function kt(e,t,n={}){return M({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 Yt(e,t){let n=lc(e.cwd);return{html:et.join(n,`${e.id}.v${t}.html`),png:et.join(n,`${e.id}.v${t}.png`)}}function cc(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?et.join(e.cwd,r):null}function pn(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 sw(e){return e.length<24||e.readUInt32BE(12)!==1229472850?null:{width:e.readUInt32BE(16),height:e.readUInt32BE(20)}}function md(e){return Buffer.isBuffer(e)&&e.length>24&&e.subarray(0,8).equals(ZF)}function QF(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 eU(e){let t=Buffer.alloc(24),n=await Xe.open(e,"r");try{await n.read(t,0,24,0)}finally{await n.close()}return t}function tU({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 nU(e,t){return e.evaluate(async n=>{let r=new Image;await new Promise((w,m)=>{r.onload=w,r.onerror=()=>m(new Error("decode failed")),r.src=`data:image/png;base64,${n}`});let o=r.naturalWidth,s=r.naturalHeight;if(!o||!s||o*s>24e6)return null;let a=document.createElement("canvas");a.width=o,a.height=s;let i=a.getContext("2d",{willReadFrequently:!0});i.drawImage(r,0,0);let c=i.getImageData(0,0,o,s).data,l=[c[0],c[1],c[2]],u=o,d=s,p=-1,f=-1;for(let w=0;w<s;w++)for(let m=w*o*4,g=0;g<o;g++,m+=4)Math.abs(c[m]-l[0])+Math.abs(c[m+1]-l[1])+Math.abs(c[m+2]-l[2])>24&&(g<u&&(u=g),g>p&&(p=g),w<d&&(d=w),f=w);return p<0?null:{imgW:o,imgH:s,bg:l,bbox:{left:u,top:d,right:p,bottom:f}}},t.toString("base64"))}async function rU(e,t,{bg:n,crop:r}){let o=await e.evaluate(async({b64:s,bg:a,crop:i})=>{let c=new Image;await new Promise((d,p)=>{c.onload=d,c.onerror=()=>p(new Error("decode failed")),c.src=`data:image/png;base64,${s}`});let l=document.createElement("canvas");l.width=i.outW,l.height=i.outH;let u=l.getContext("2d");return u.fillStyle=`rgb(${a[0]},${a[1]},${a[2]})`,u.fillRect(0,0,i.outW,i.outH),u.drawImage(c,i.sx,i.sy,i.sw,i.sh,i.dx,i.dy,i.sw,i.sh),l.toDataURL("image/png").split(",")[1]},{b64:t.toString("base64"),bg:n,crop:r});return Buffer.from(o,"base64")}async function oU({htmlPath:e,outPath:t,width:n}){let r=Date.now(),o;try{o=await KF.launch({executablePath:GA,args:["--disable-gpu"],timeout:3e4})}catch(s){throw new Ct("chromium failed to launch",s?.message||"")}try{let a=await(await o.newContext({viewport:{width:n,height:800},deviceScaleFactor:la})).newPage();a.setDefaultTimeout(ua),await a.goto(`file://${e}`,{waitUntil:"load",timeout:ua}),await a.waitForTimeout(250);let i;for(let l=1;;l++)try{i=await a.screenshot({fullPage:!0,timeout:ua});break}catch(u){if(l>=3||!/captureScreenshot|Unable to capture/i.test(u?.message||""))throw u;await a.waitForTimeout(500)}try{let l=await nU(a,i),u=l&&tU({...l,pad:VF*la,align:la});u&&(i=await rU(a,i,{bg:l.bg,crop:u}))}catch{}if(i.length<zA)throw new Ct(`capture produced a ${i.length}-byte image`);let c=sw(i);if(!c)throw new Ct("output is not a PNG");return await Xe.writeFile(t,i),{width:Math.round(c.width/la),height:Math.round(c.height/la),dpr:la,renderMs:Date.now()-r}}catch(s){throw s instanceof Ct?s:new Ct(/timeout/i.test(s?.message||"")?`render timed out after ${ua}ms`:"chromium render failed",s?.message||"")}finally{await o.close().catch(()=>{})}}async function HA({htmlPath:e,outPath:t,width:n}){let r=await Xe.mkdtemp(et.join(qA.tmpdir(),"bostrat-mock-profile-")),o=Date.now(),s="";try{try{s=(await ow(FA,["--headless","--no-remote","--profile",r,`--window-size=${n}`,"--screenshot",t,`file://${e}`],{env:{...process.env,MOZ_HEADLESS:"1"},timeout:ua,killSignal:"SIGKILL",maxBuffer:4194304})).stderr||""}catch(c){throw s=c?.stderr||"",c?.code==="ENOENT"?new Ct(`firefox not found (${FA})`,""):new Ct(c?.killed?`render timed out after ${ua}ms`:"firefox exited non-zero",s)}let a=await Xe.stat(t).catch(()=>null);if(!a||a.size<zA)throw new Ct(`render produced ${a?`a ${a.size}-byte file`:"no file"} (silent no-op \u2014 another firefox holding the profile?)`,s);let i=sw(await eU(t));if(!i)throw new Ct("output is not a PNG",s);return{width:i.width,height:i.height,dpr:1,renderMs:Date.now()-o}}finally{await Xe.rm(r,{recursive:!0,force:!0}).catch(()=>{})}}async function sU(e){if(GF==="firefox")return HA(e);try{return await oU(e)}catch(t){if(!/failed to launch/i.test(t?.message||""))throw t;try{return await HA(e)}catch(n){throw/not found/.test(n?.message||"")?new Ct(`no browser installed \u2014 chromium missing at ${GA} 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 YA(e){return rw=rw.then(e,e),rw}async function XA(e,t){let n=await Fn(),r=n.mocks.find(o=>o.id===e);if(r){r.state="rendering",await Jt(),await kt(r,"rendering",{version:t});try{let o=await fd();if(o<JF)throw new Ct(`box is low on memory (${Math.round(o/1e6)} MB available) \u2014 not spawning a browser`);let s=Yt(r,t),a=await aU({htmlPath:s.html,outPath:s.png,width:r.width});if(!n.mocks.some(i=>i.id===e)){await Xe.rm(s.png,{force:!0}).catch(()=>{});return}aw(r,{v:t,source:"html",htmlRel:et.relative(r.cwd,s.html),pngRel:et.relative(r.cwd,s.png),width:a.width,height:a.height,dpr:a.dpr,renderMs:a.renderMs,createdAt:Date.now()}),await Jt(),await kt(r,"ready",{version:t,width:a.width,height:a.height,dpr:a.dpr}),jn(r),Ln(r,t,"png")}catch(o){if(!n.mocks.some(s=>s.id===e))return;r.state="error",r.error=o?.message||String(o),await Jt(),await kt(r,"error",{version:t,error:r.error}),jn(r)}}}function aw(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 iU({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?zF:Number(r);if(!Number.isInteger(o)||o<320||o>4e3)throw new Error("invalid width (320-4000)");return o}async function uc({trackId:e,group:t}={}){let n=await Fn(),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 pr(e){let n=(await Fn()).mocks.find(r=>r.id===e);return n?{...n}:null}function ZA({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&&!md(t))throw new Error("image must be a PNG");if(n){let o=QF(n);if(!o)throw new Error("video must be an mp4 or webm (magic-byte check failed)");if(n.length>UA)throw new Error(`video must be ${UA/(1024*1024)} MB or smaller (got ${Math.round(n.length/(1024*1024))} MB)`);return o}return null}async function QA({trackId:e,name:t,html:n,image:r,video:o,cwd:s,width:a,group:i,box:c,agent:l,prompt:u}){let d=iU({trackId:e,name:t,cwd:s,width:a}),p=typeof n=="string"&&n.trim(),f=ZA({html:n,image:r,video:o}),w=await Fn(),m={id:HF().slice(0,8),trackId:e,box:c||null,agent:l||null,name:t.trim(),prompt:u?String(u).slice(0,500):null,group:i?String(i).trim():null,cwd:s,width:d,height:null,dpr:null,state:"queued",source:p?"html":o?"video":"image",kind:o?"video":"image",version:1,readyVersion:null,versions:[],error:null,renderMs:null,createdAt:Date.now(),updatedAt:Date.now()};return await Xe.mkdir(lc(s),{recursive:!0}),w.mocks.push(m),p?(await Xe.writeFile(Yt(m,1).html,n),await Jt(),await kt(m,"created"),jn(m),Ln(m,1,"html"),YA(()=>XA(m.id,1))):o?(await tE(m,1,o,f),await Jt(),await kt(m,"created"),await kt(m,"ready",{version:1,width:m.width,height:m.height,dpr:m.dpr,durationS:m.versions[0]?.durationS??null}),jn(m),JA(m,m.versions[0])):(await nE(m,1,r),await Jt(),await kt(m,"created"),await kt(m,"ready",{version:1,width:m.width,height:m.height,dpr:m.dpr}),jn(m),Ln(m,1,"png")),{...m}}async function eE(e,{html:t,image:n,video:r,width:o}={}){let a=(await Fn()).mocks.find(u=>u.id===e);if(!a)throw new Error("mock not found");let i=typeof t=="string"&&t.trim(),c=ZA({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 Xe.mkdir(lc(a.cwd),{recursive:!0}),i?(a.state="queued",await Xe.writeFile(Yt(a,l).html,t),await Jt(),await kt(a,"updated",{version:l}),jn(a),Ln(a,l,"html"),YA(()=>XA(a.id,l))):r?(await tE(a,l,r,c),await Jt(),await kt(a,"updated",{version:l}),await kt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr,durationS:pn(a)?.durationS??null}),jn(a),JA(a,a.versions.find(u=>u.v===l))):(await nE(a,l,n),await Jt(),await kt(a,"updated",{version:l}),await kt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr}),jn(a),Ln(a,l,"png")),{...a}}async function cU(e){try{let{stdout:t}=await ow(YF,["-v","error","-print_format","json","-show_format","-show_streams",e],{timeout:VA,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 lU(e,t){try{await ow(XF,["-y","-v","error","-i",e,"-frames:v","1","-f","image2",t],{timeout:VA,killSignal:"SIGKILL",maxBuffer:4*1024*1024});let n=await Xe.stat(t).catch(()=>null);return!!n&&n.size>0}catch{return!1}}async function tE(e,t,n,r){let o=lc(e.cwd),s=et.join(o,`${e.id}.v${t}.${r.ext}`),a=et.join(o,`${e.id}.v${t}.poster.png`);await Xe.writeFile(s,n);let i=await cU(s),c=await lU(s,a);aw(e,{v:t,source:"video",htmlRel:null,pngRel:null,videoRel:et.relative(e.cwd,s),posterRel:c?et.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 nE(e,t,n){let r=sw(n);if(!r)throw new Error("image must be a PNG");let o=Yt(e,t);await Xe.writeFile(o.png,n),aw(e,{v:t,source:"image",htmlRel:null,pngRel:et.relative(e.cwd,o.png),width:r.width,height:r.height,dpr:1,renderMs:null,createdAt:Date.now()}),e.width=r.width}async function rE(e){let t=await Fn(),n=t.mocks.find(o=>o.id===e);if(!n)throw new Error("mock not found");if(n.readyVersion==null)throw new Error(`mock is ${n.state} \u2014 nothing to pick yet`);let r=n.group?t.mocks.filter(o=>o.trackId===n.trackId&&o.group===n.group&&o.id!==e&&o.readyVersion!=null).map(o=>({mockId:o.id,name:o.name})):[];return await kt(n,"picked",{version:n.readyVersion,siblings:r}),{mock:{...n},siblings:r}}async function oE(e){let t=await Fn(),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=Yt(r,o);await Xe.rm(s.html,{force:!0}).catch(()=>{}),await Xe.rm(s.png,{force:!0}).catch(()=>{})}for(let o of r.versions||[])for(let s of[o.videoRel,o.posterRel])s&&await Xe.rm(et.join(r.cwd,s),{force:!0}).catch(()=>{});return await Jt(),await kt(r,"deleted"),tn("mocks",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function sE(e){let n=(await Fn()).mocks.filter(i=>i.trackId===e.id);if(!n.length)return 0;let r=et.join(WA,"mock-archive",e.id),o=lc(e.cwd),s=et.join(r,".bostrat","mocks");await Xe.mkdir(s,{recursive:!0});let a=await Xe.readdir(o).catch(()=>[]);for(let i of a)await Xe.copyFile(et.join(o,i),et.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 Xe.stat(et.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(),jn(i)}return await Jt(),n.length}async function aE(e){let t=await Fn(),n=t.mocks.filter(r=>r.trackId===e);if(n.length){t.mocks=t.mocks.filter(r=>r.trackId!==e),await Jt();for(let r of n)tn("mocks",r.id).catch(()=>{})}return n.length}async function iE(){if(!He())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("mocks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Fn();for(let r of n.mocks){await jn(r);for(let o of r.versions||[])o.htmlRel&&await Ln(r,o.v,"html"),(o.pngRel||o.posterRel)&&await Ln(r,o.v,"png"),o.videoRel&&await Ln(r,o.v,o.videoRel.endsWith(".webm")?"webm":"mp4")}return{pushed:n.mocks.length,source:"plane"}}var ow,WA,KA,GF,GA,FA,zF,la,VF,zA,ua,JF,UA,YF,XF,VA,Ct,Go,nw,jn,Ln,lc,ZF,aU,rw,da=G(()=>{de();Er();tw();Ir();ow=WF(qF),WA=process.env.BOSTRAT_STATE_DIR||et.join(process.env.HOME||qA.tmpdir(),".bostrat"),KA=et.join(WA,"mocks.json"),GF=process.env.BOSTRAT_MOCK_ENGINE||"chromium",GA=process.env.BOSTRAT_CHROMIUM_BIN||"/usr/bin/chromium",FA=process.env.BOSTRAT_FIREFOX_BIN||"firefox",zF=1300,la=2,VF=32,zA=1500,ua=Number(process.env.BOSTRAT_MOCK_TIMEOUT_MS)||75e3,JF=700*1024*1024,UA=100*1024*1024,YF=process.env.BOSTRAT_FFPROBE_BIN||"ffprobe",XF=process.env.BOSTRAT_FFMPEG_BIN||"ffmpeg",VA=2e4,Ct=class extends Error{constructor(t,n=""){super(n?`${t}
203
+ `)}catch{return""}}async function JF(e){if(e.state==="stopped"||e.state==="error")return!1;let t=e.origin!=="detected",n=t?await zF(e.slug):!0;if(t&&!n){let s=e.state==="starting";return e.state=s?"error":"stopped",s&&(e.error=await FT(e.slug)||"server exited before listening"),fr.delete(e.id),await mr(e,e.state,e.error?{error:e.error}:{}),!0}if(await dc(e.port))return fr.delete(e.id),e.lastHealthyAt=Date.now(),e.state!=="live"?(e.state="live",e.error=null,await mr(e,"live"),!0):!1;if(e.state==="starting")return Date.now()-e.createdAt>VF?(e.state="error",e.error=await FT(e.slug)||"never started listening",await mr(e,"error",{error:e.error}),!0):!1;let o=(fr.get(e.id)||0)+1;return fr.set(e.id,o),o>=3&&e.state==="live"?(e.state="unhealthy",!0):!1}async function wd(){if(!nw){nw=!0;try{let e=await hr(),t=!1;for(let n of e.views)await JF(n)&&(t=!0);t&&await Fn()}finally{nw=!1}}}async function dw({trackId:e}={}){await wd();let t=await hr();return(e?t.views.filter(r=>r.trackId===e):t.views).map(r=>({...r}))}async function JT(e){let n=(await hr()).views.find(r=>r.id===e);return n?{...n}:null}function pw(e){return jn&&jn.views.find(t=>t.slug===e)||null}async function fw({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=Ot.resolve(r,o??"."),d=i==="detected"?null:async()=>{await WF(r,u),await qF(u,n)},p=await hr();if(i!=="detected"){let m=sw(t),g=String(n).trim(),y=p.views.find(x=>x.trackId===e&&(x.slug===m||sw(x.name)===m||x.cmd===g&&Ot.resolve(x.serveCwd??x.cwd)===u));if(y)return YF(p,y,{cmd:g,box:a,branch:c,serveCwd:l?u:void 0,validate:d})}if(d&&await d(),p.views.filter(m=>m.state==="live"||m.state==="starting").length>=io)throw new Error(`view cap reached (${io} live) \u2014 stop one first`);let w={id:_F().slice(0,8),trackId:e,box:a||null,name:t.trim(),slug:KF(p,t),cmd:n?String(n).trim():null,cwd:r,serveCwd:u,branch:c,port:await GF(p,s),origin:i,state:"starting",error:null,createdAt:Date.now(),lastHealthyAt:null};return i!=="detected"&&await uw(w),p.views.push(w),await Fn(),await mr(w,"created",{origin:i}),ow(e,w.id),i==="detected"&&await dc(w.port)&&(w.state="live",w.lastHealthyAt=Date.now(),await Fn(),await mr(w,"live")),{...w}}async function YF(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 UF(t.serveCwd??t.cwd,s);if((t.state==="live"||t.state==="starting")&&!i&&!c&&await dc(t.port))return await Fn(),ow(t.trackId,t.id),{...t,reused:!0};if(a&&await a(),e.views.filter(d=>d.id!==t.id&&(d.state==="live"||d.state==="starting")).length>=io)throw new Error(`view cap reached (${io} live) \u2014 stop one first`);return t.origin==="detected"?(await lw(t.port),t.origin="agent"):await pc(t.slug),t.cmd=n,s!==void 0&&(t.serveCwd=s),t.state="starting",t.error=null,t.createdAt=Date.now(),fr.delete(t.id),await uw(t),await Fn(),await mr(t,"created",{restarted:!0,reused:!0}),ow(t.trackId,t.id),{...t,reused:!0}}async function YT(e){let n=(await hr()).views.find(r=>r.id===e);if(!n)throw new Error("view not found");return n.origin==="detected"?await lw(n.port):await pc(n.slug),n.state!=="stopped"&&(n.state="stopped",fr.delete(n.id),await Fn(),await mr(n,"stopped")),{...n}}async function XT(e){let t=await hr(),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>=io)throw new Error(`view cap reached (${io} live) \u2014 stop one first`);return await pc(n.slug),n.state="starting",n.error=null,n.createdAt=Date.now(),fr.delete(n.id),await uw(n),await Fn(),await mr(n,"created",{restarted:!0}),{...n}}async function ZT(e){let t=await hr(),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 lw(r.port):await pc(r.slug),t.views.splice(n,1),fr.delete(r.id),await Fn(),await mr(r,"deleted"),{ok:!0,id:e,slug:r.slug}}async function mw(e){let t=await hr(),n=t.views.filter(r=>r.trackId===e);for(let r of n)r.origin!=="detected"&&await pc(r.slug),fr.delete(r.id);return n.length&&(t.views=t.views.filter(r=>r.trackId!==e),await Fn()),n.length}async function QT(e,t){if(!e?.id||!Array.isArray(t)||!t.length)return[];let n=await hr(),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 Fn()),!o.length)return[];let a=new Set;for(let c of o)for(let l of String(c.text||"").matchAll(XF)){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(!VT().has(c)&&!n.views.some(l=>l.port===c)&&await dc(c))try{i.push(await fw({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 Ln,RF,UT,BT,jT,io,OF,wa,LT,cc,MF,rw,CF,NF,PF,aw,HT,ew,jF,FF,qT,md,jn,tw,lc,iw,KT,fr,VF,nw,XF,gd=G(()=>{ct();fe();Or();Ln=$F(IF),RF=process.env.BOSTRAT_STATE_DIR||Ot.join(process.env.HOME||TF.tmpdir(),".bostrat"),UT=Ot.join(RF,"views.json"),[BT,jT]=(process.env.BOSTRAT_VIEW_PORTS||"4300-4349").split("-").map(e=>Number(e)||0),io=Number(process.env.BOSTRAT_VIEW_MAX)||3,OF="bostrat-view-",wa=e=>`${OF}${e}`,LT=new Set(["bostrat","www","api","views","app"]),cc=e=>Object.assign(new Error(e),{status:400}),MF=new Set(["npm","pnpm","yarn","bun"]),rw="package.json",CF=/[|;&`]|\$\(/,NF=new Set(["sh","bash","zsh","dash","env","exec","nohup","time"]),PF=/(^|\s)(-C|--cwd|--manifest-path|--dir)(=|\s)/,aw=e=>String(e).trim().split(/\s+/).filter(Boolean),HT=/^[A-Za-z_][A-Za-z0-9_]*=/;ew=e=>e==="/",jF=e=>e===".."||e.startsWith("../")||e.includes("/../")||e.endsWith("/..");FF=e=>uc.stat(e).then(t=>t.isDirectory(),()=>!1),qT=e=>uc.stat(e).then(t=>t.isFile(),()=>!1),md=e=>uc.realpath(e).catch(()=>Ot.resolve(e));jn=null,tw=null;lc=new Map,iw=Number(process.env.BOSTRAT_VIEW_JOB_TIMEOUT)||3e5,KT=12e3;fr=new Map,VF=12e4;nw=!1;XF=/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::(\d{2,5}))?(?:\/|\b)/g});function ga(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>ww?null:n}function QF(e,t){return e?.firstSeen==null||t?.ts==null||e.firstSeen<t.ts}async function yd(e,{bypassThrottle:t=!1}={}){let n=e?.workspace?.branch;if(!n)return;let r;try{r=await K(e)}catch{return}let o=ga(r);if(o==null)return;let s=(e.boxes||[]).find(d=>d.name===e.leadBox);if(await Zo(e.leadBox,s?.agent).catch(()=>!1))return;let a=Date.now();if(!t&&a-(hw.get(e.id)||0)<ZF)return;hw.set(e.id,a);let i;try{i=await Nn(e.cwd,{caller:"reconcile"})}catch{return}let c=await ua(e).catch(()=>[n]),l=(i||[]).find(d=>c.includes(d.headRefName));if(!l)return;let u=await _e(e.cwd).catch(()=>null);if(u){let{link:d,created:p}=await Bt({repo:u,number:l.number,trackId:e.id,url:l.url,headRef:l.headRefName||n,title:l.title,source:"reconciled"});if(!p&&!(d?.trackId===e.id&&await sr(u,l.number))){if(!QF(d,o))return;let f=await K(e).catch(()=>null);if(f&&ga(f)==null)return;await M(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:{ts:Date.now(),change:"pushed",number:l.number,url:l.url,title:l.title,branch:n,repo:u}});return}}await M(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:{ts:Date.now(),change:"opened",number:l.number,url:l.url,title:l.title,branch:n,...u?{repo:u}:{}}}).catch(()=>{}),hw.delete(e.id)}var ZF,hw,ww,fc=G(()=>{fe();Xo();$r();Cn();Ji();Qo();ZF=6e3,hw=new Map,ww=30*6e4});import gw from"node:os";import{execFile as eU}from"node:child_process";import{promisify as tU}from"node:util";async function bd(){if(process.platform!=="darwin")return gw.freemem();try{let{stdout:e}=await nU("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:gw.freemem()}catch{return gw.freemem()}}var nU,yw=G(()=>{nU=tU(eU)});import Ze from"node:fs/promises";import et from"node:path";import rE from"node:os";import{randomUUID as rU}from"node:crypto";import{execFile as oU}from"node:child_process";import{promisify as sU}from"node:util";import{chromium as aU}from"playwright-core";async function Wn(){return ns||(bw||=(async()=>{try{ns=JSON.parse(await Ze.readFile(sE,"utf8"))}catch{ns={mocks:[]}}finally{bw=null}return ns.mocks||=[],ns})(),bw)}async function Zt(){await It(sE,ns)}function lE(e,t){Hn(e,t.v,t.videoRel?.endsWith(".webm")?"webm":"mp4"),t.posterRel&&Hn(e,t.v,"png")}function vt(e,t,n={}){return M({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 Qt(e,t){let n=hc(e.cwd);return{html:et.join(n,`${e.id}.v${t}.html`),png:et.join(n,`${e.id}.v${t}.png`)}}function mc(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?et.join(e.cwd,r):null}function fn(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 vw(e){return e.length<24||e.readUInt32BE(12)!==1229472850?null:{width:e.readUInt32BE(16),height:e.readUInt32BE(20)}}function kd(e){return Buffer.isBuffer(e)&&e.length>24&&e.subarray(0,8).equals(fU)}function mU(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 hU(e){let t=Buffer.alloc(24),n=await Ze.open(e,"r");try{await n.read(t,0,24,0)}finally{await n.close()}return t}function wU({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 gU(e,t){return e.evaluate(async n=>{let r=new Image;await new Promise((w,m)=>{r.onload=w,r.onerror=()=>m(new Error("decode failed")),r.src=`data:image/png;base64,${n}`});let o=r.naturalWidth,s=r.naturalHeight;if(!o||!s||o*s>24e6)return null;let a=document.createElement("canvas");a.width=o,a.height=s;let i=a.getContext("2d",{willReadFrequently:!0});i.drawImage(r,0,0);let c=i.getImageData(0,0,o,s).data,l=[c[0],c[1],c[2]],u=o,d=s,p=-1,f=-1;for(let w=0;w<s;w++)for(let m=w*o*4,g=0;g<o;g++,m+=4)Math.abs(c[m]-l[0])+Math.abs(c[m+1]-l[1])+Math.abs(c[m+2]-l[2])>24&&(g<u&&(u=g),g>p&&(p=g),w<d&&(d=w),f=w);return p<0?null:{imgW:o,imgH:s,bg:l,bbox:{left:u,top:d,right:p,bottom:f}}},t.toString("base64"))}async function yU(e,t,{bg:n,crop:r}){let o=await e.evaluate(async({b64:s,bg:a,crop:i})=>{let c=new Image;await new Promise((d,p)=>{c.onload=d,c.onerror=()=>p(new Error("decode failed")),c.src=`data:image/png;base64,${s}`});let l=document.createElement("canvas");l.width=i.outW,l.height=i.outH;let u=l.getContext("2d");return u.fillStyle=`rgb(${a[0]},${a[1]},${a[2]})`,u.fillRect(0,0,i.outW,i.outH),u.drawImage(c,i.sx,i.sy,i.sw,i.sh,i.dx,i.dy,i.sw,i.sh),l.toDataURL("image/png").split(",")[1]},{b64:t.toString("base64"),bg:n,crop:r});return Buffer.from(o,"base64")}async function bU({htmlPath:e,outPath:t,width:n}){let r=Date.now(),o;try{o=await aU.launch({executablePath:aE,args:["--disable-gpu"],timeout:3e4})}catch(s){throw new jt("chromium failed to launch",s?.message||"")}try{let a=await(await o.newContext({viewport:{width:n,height:800},deviceScaleFactor:ya})).newPage();a.setDefaultTimeout(ba),await a.goto(`file://${e}`,{waitUntil:"load",timeout:ba}),await a.waitForTimeout(250);let i;for(let l=1;;l++)try{i=await a.screenshot({fullPage:!0,timeout:ba});break}catch(u){if(l>=3||!/captureScreenshot|Unable to capture/i.test(u?.message||""))throw u;await a.waitForTimeout(500)}try{let l=await gU(a,i),u=l&&wU({...l,pad:lU*ya,align:ya});u&&(i=await yU(a,i,{bg:l.bg,crop:u}))}catch{}if(i.length<iE)throw new jt(`capture produced a ${i.length}-byte image`);let c=vw(i);if(!c)throw new jt("output is not a PNG");return await Ze.writeFile(t,i),{width:Math.round(c.width/ya),height:Math.round(c.height/ya),dpr:ya,renderMs:Date.now()-r}}catch(s){throw s instanceof jt?s:new jt(/timeout/i.test(s?.message||"")?`render timed out after ${ba}ms`:"chromium render failed",s?.message||"")}finally{await o.close().catch(()=>{})}}async function nE({htmlPath:e,outPath:t,width:n}){let r=await Ze.mkdtemp(et.join(rE.tmpdir(),"bostrat-mock-profile-")),o=Date.now(),s="";try{try{s=(await xw(eE,["--headless","--no-remote","--profile",r,`--window-size=${n}`,"--screenshot",t,`file://${e}`],{env:{...process.env,MOZ_HEADLESS:"1"},timeout:ba,killSignal:"SIGKILL",maxBuffer:4194304})).stderr||""}catch(c){throw s=c?.stderr||"",c?.code==="ENOENT"?new jt(`firefox not found (${eE})`,""):new jt(c?.killed?`render timed out after ${ba}ms`:"firefox exited non-zero",s)}let a=await Ze.stat(t).catch(()=>null);if(!a||a.size<iE)throw new jt(`render produced ${a?`a ${a.size}-byte file`:"no file"} (silent no-op \u2014 another firefox holding the profile?)`,s);let i=vw(await hU(t));if(!i)throw new jt("output is not a PNG",s);return{width:i.width,height:i.height,dpr:1,renderMs:Date.now()-o}}finally{await Ze.rm(r,{recursive:!0,force:!0}).catch(()=>{})}}async function kU(e){if(iU==="firefox")return nE(e);try{return await bU(e)}catch(t){if(!/failed to launch/i.test(t?.message||""))throw t;try{return await nE(e)}catch(n){throw/not found/.test(n?.message||"")?new jt(`no browser installed \u2014 chromium missing at ${aE} 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 uE(e){return kw=kw.then(e,e),kw}async function dE(e,t){let n=await Wn(),r=n.mocks.find(o=>o.id===e);if(r){r.state="rendering",await Zt(),await vt(r,"rendering",{version:t});try{let o=await bd();if(o<uU)throw new jt(`box is low on memory (${Math.round(o/1e6)} MB available) \u2014 not spawning a browser`);let s=Qt(r,t),a=await xU({htmlPath:s.html,outPath:s.png,width:r.width});if(!n.mocks.some(i=>i.id===e)){await Ze.rm(s.png,{force:!0}).catch(()=>{});return}Sw(r,{v:t,source:"html",htmlRel:et.relative(r.cwd,s.html),pngRel:et.relative(r.cwd,s.png),width:a.width,height:a.height,dpr:a.dpr,renderMs:a.renderMs,createdAt:Date.now()}),await Zt(),await vt(r,"ready",{version:t,width:a.width,height:a.height,dpr:a.dpr}),Un(r),Hn(r,t,"png")}catch(o){if(!n.mocks.some(s=>s.id===e))return;r.state="error",r.error=o?.message||String(o),await Zt(),await vt(r,"error",{version:t,error:r.error}),Un(r)}}}function Sw(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 vU({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?cU:Number(r);if(!Number.isInteger(o)||o<320||o>4e3)throw new Error("invalid width (320-4000)");return o}async function wc({trackId:e,group:t}={}){let n=await Wn(),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 wr(e){let n=(await Wn()).mocks.find(r=>r.id===e);return n?{...n}:null}function pE({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&&!kd(t))throw new Error("image must be a PNG");if(n){let o=mU(n);if(!o)throw new Error("video must be an mp4 or webm (magic-byte check failed)");if(n.length>tE)throw new Error(`video must be ${tE/(1024*1024)} MB or smaller (got ${Math.round(n.length/(1024*1024))} MB)`);return o}return null}async function fE({trackId:e,name:t,html:n,image:r,video:o,cwd:s,width:a,group:i,box:c,agent:l,prompt:u}){let d=vU({trackId:e,name:t,cwd:s,width:a}),p=typeof n=="string"&&n.trim(),f=pE({html:n,image:r,video:o}),w=await Wn(),m={id:rU().slice(0,8),trackId:e,box:c||null,agent:l||null,name:t.trim(),prompt:u?String(u).slice(0,500):null,group:i?String(i).trim():null,cwd:s,width:d,height:null,dpr:null,state:"queued",source:p?"html":o?"video":"image",kind:o?"video":"image",version:1,readyVersion:null,versions:[],error:null,renderMs:null,createdAt:Date.now(),updatedAt:Date.now()};return await Ze.mkdir(hc(s),{recursive:!0}),w.mocks.push(m),p?(await Ze.writeFile(Qt(m,1).html,n),await Zt(),await vt(m,"created"),Un(m),Hn(m,1,"html"),uE(()=>dE(m.id,1))):o?(await hE(m,1,o,f),await Zt(),await vt(m,"created"),await vt(m,"ready",{version:1,width:m.width,height:m.height,dpr:m.dpr,durationS:m.versions[0]?.durationS??null}),Un(m),lE(m,m.versions[0])):(await wE(m,1,r),await Zt(),await vt(m,"created"),await vt(m,"ready",{version:1,width:m.width,height:m.height,dpr:m.dpr}),Un(m),Hn(m,1,"png")),{...m}}async function mE(e,{html:t,image:n,video:r,width:o}={}){let a=(await Wn()).mocks.find(u=>u.id===e);if(!a)throw new Error("mock not found");let i=typeof t=="string"&&t.trim(),c=pE({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 Ze.mkdir(hc(a.cwd),{recursive:!0}),i?(a.state="queued",await Ze.writeFile(Qt(a,l).html,t),await Zt(),await vt(a,"updated",{version:l}),Un(a),Hn(a,l,"html"),uE(()=>dE(a.id,l))):r?(await hE(a,l,r,c),await Zt(),await vt(a,"updated",{version:l}),await vt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr,durationS:fn(a)?.durationS??null}),Un(a),lE(a,a.versions.find(u=>u.v===l))):(await wE(a,l,n),await Zt(),await vt(a,"updated",{version:l}),await vt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr}),Un(a),Hn(a,l,"png")),{...a}}async function SU(e){try{let{stdout:t}=await xw(dU,["-v","error","-print_format","json","-show_format","-show_streams",e],{timeout:cE,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 AU(e,t){try{await xw(pU,["-y","-v","error","-i",e,"-frames:v","1","-f","image2",t],{timeout:cE,killSignal:"SIGKILL",maxBuffer:4*1024*1024});let n=await Ze.stat(t).catch(()=>null);return!!n&&n.size>0}catch{return!1}}async function hE(e,t,n,r){let o=hc(e.cwd),s=et.join(o,`${e.id}.v${t}.${r.ext}`),a=et.join(o,`${e.id}.v${t}.poster.png`);await Ze.writeFile(s,n);let i=await SU(s),c=await AU(s,a);Sw(e,{v:t,source:"video",htmlRel:null,pngRel:null,videoRel:et.relative(e.cwd,s),posterRel:c?et.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 wE(e,t,n){let r=vw(n);if(!r)throw new Error("image must be a PNG");let o=Qt(e,t);await Ze.writeFile(o.png,n),Sw(e,{v:t,source:"image",htmlRel:null,pngRel:et.relative(e.cwd,o.png),width:r.width,height:r.height,dpr:1,renderMs:null,createdAt:Date.now()}),e.width=r.width}async function gE(e){let t=await Wn(),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 vt(n,"picked",{version:n.readyVersion,siblings:r}),{mock:{...n},siblings:r}}async function yE(e){let t=await Wn(),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=Qt(r,o);await Ze.rm(s.html,{force:!0}).catch(()=>{}),await Ze.rm(s.png,{force:!0}).catch(()=>{})}for(let o of r.versions||[])for(let s of[o.videoRel,o.posterRel])s&&await Ze.rm(et.join(r.cwd,s),{force:!0}).catch(()=>{});return await Zt(),await vt(r,"deleted"),rn("mocks",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function bE(e){let n=(await Wn()).mocks.filter(i=>i.trackId===e.id);if(!n.length)return 0;let r=et.join(oE,"mock-archive",e.id),o=hc(e.cwd),s=et.join(r,".bostrat","mocks");await Ze.mkdir(s,{recursive:!0});let a=await Ze.readdir(o).catch(()=>[]);for(let i of a)await Ze.copyFile(et.join(o,i),et.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 Ze.stat(et.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(),Un(i)}return await Zt(),n.length}async function kE(e){let t=await Wn(),n=t.mocks.filter(r=>r.trackId===e);if(n.length){t.mocks=t.mocks.filter(r=>r.trackId!==e),await Zt();for(let r of n)rn("mocks",r.id).catch(()=>{})}return n.length}async function xE(){if(!He())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("mocks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Wn();for(let r of n.mocks){await Un(r);for(let o of r.versions||[])o.htmlRel&&await Hn(r,o.v,"html"),(o.pngRel||o.posterRel)&&await Hn(r,o.v,"png"),o.videoRel&&await Hn(r,o.v,o.videoRel.endsWith(".webm")?"webm":"mp4")}return{pushed:n.mocks.length,source:"plane"}}var xw,oE,sE,iU,aE,eE,cU,ya,lU,iE,ba,uU,tE,dU,pU,cE,jt,ns,bw,Un,Hn,hc,fU,xU,kw,ka=G(()=>{fe();Or();yw();Cr();xw=sU(oU),oE=process.env.BOSTRAT_STATE_DIR||et.join(process.env.HOME||rE.tmpdir(),".bostrat"),sE=et.join(oE,"mocks.json"),iU=process.env.BOSTRAT_MOCK_ENGINE||"chromium",aE=process.env.BOSTRAT_CHROMIUM_BIN||"/usr/bin/chromium",eE=process.env.BOSTRAT_FIREFOX_BIN||"firefox",cU=1300,ya=2,lU=32,iE=1500,ba=Number(process.env.BOSTRAT_MOCK_TIMEOUT_MS)||75e3,uU=700*1024*1024,tE=100*1024*1024,dU=process.env.BOSTRAT_FFPROBE_BIN||"ffprobe",pU=process.env.BOSTRAT_FFMPEG_BIN||"ffmpeg",cE=2e4,jt=class extends Error{constructor(t,n=""){super(n?`${t}
204
204
  ${n.trim().split(`
205
205
  `).slice(-6).join(`
206
- `)}`:t),this.name="MockRenderError"}},Go=null,nw=null;jn=e=>bt("mocks",{...e},{trackId:e.trackId}).catch(()=>{}),Ln=(e,t,n)=>{let r=(e.versions||[]).find(s=>s.v===t),o=n==="mp4"||n==="webm"?cc(e,r,"video"):r&&cc(e,r,n)||(n==="html"?Yt(e,t).html:null);return o?_r("mocks",e.id,t,n,o).catch(()=>{}):Promise.resolve()};lc=e=>et.join(e,".bostrat","mocks");ZF=Buffer.from([137,80,78,71,13,10,26,10]);aU=sU,rw=Promise.resolve()});import uU from"node:fs/promises";import pE from"node:path";import dU from"node:os";import{randomUUID as fE}from"node:crypto";async function mr(){return fr||(iw||=(async()=>{let e=!0;try{fr=JSON.parse(await uU.readFile(mE,"utf8"))}catch{fr={flows:[]},e=!1}finally{iw=null}if(fr.flows||=[],!e&&He()){let{records:t,source:n}=await st("flows").catch(()=>({records:[],source:"error"}));if(n==="plane"){for(let r of t)!r.deletedAt&&r.data?.id&&fr.flows.push(r.data);fr.flows.length&&await pa().catch(()=>{})}}return fr})(),iw)}async function pa(){await Et(mE,fr)}function cw(e,t,n={}){return M({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 hE({trackId:e,steps:t,prevSteps:n=[]}){if(!Array.isArray(t)||t.length<1||t.length>cE)throw new Error(`steps must be an array of 1-${cE}`);let r=await uc({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>uE)throw new Error(`${l}: caption over ${uE} chars`);let d=c.title==null?null:String(c.title).trim()||null;if(d&&d.length>dE)throw new Error(`${l}: title over ${dE} chars`);let p=String(c.mock??"").trim().replace(/^mock:/,"");if(!p)throw new Error(`${l}: mock (name or id) required`);let f=r.filter(x=>x.id===p);if(f.length||(f=r.filter(x=>x.name.toLowerCase()===p.toLowerCase())),!f.length)throw new Error(`${l}: no mock matching "${p}" in this Track \u2014 see \`bostrat-mock ls\``);if(f.length>1)throw new Error(`${l}: "${p}" is ambiguous (${f.map(x=>`mock:${x.id}`).join(", ")}) \u2014 use the id`);let w=f[0],m=null;if(c.v!=null&&(m=Number(c.v),!Number.isInteger(m)||!(w.versions||[]).some(x=>x.v===m)))throw new Error(`${l}: "${w.name}" has no captured v${c.v} to pin`);let g=o.findIndex(x=>x.mockId===w.id),y=g>=0?o.splice(g,1)[0].id:fE().slice(0,8);s.push({id:y,mockId:w.id,caption:u,title:d,v:m})}let a={};for(let i of s)i.mockId in a||(a[i.mockId]=r.find(c=>c.id===i.mockId)?.readyVersion??null);return{steps:s,resolved:a}}function fU(e){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");if(e.trim().length>lE)throw new Error(`name over ${lE} chars`);return e.trim()}async function wE({trackId:e}={}){let t=await mr();return(e?t.flows.filter(r=>r.trackId===e):t.flows).map(r=>({...r}))}async function mU(e){let n=(await mr()).flows.find(r=>r.id===e);return n?{...n}:null}async function gE(e){let t=await mU(e);if(!t)return null;let n=new Map((await uc({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=pn(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 yE({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=fU(t),i=await mr(),c=i.flows.find(f=>f.trackId===e&&f.name.toLowerCase()===a.toLowerCase());if(c)throw new Error(`flow "${c.name}" already exists in this Track (flow:${c.id}) \u2014 revise it with \`bostrat-flow update\``);let{steps:l,resolved:u}=await hE({trackId:e,steps:n}),d=Date.now(),p={id:fE().slice(0,8),trackId:e,box:o||null,agent:s||null,name:a,cwd:r,version:1,versions:[{v:1,steps:l,resolved:u,note:null,createdAt:d}],steps:l,createdAt:d,updatedAt:d};return i.flows.push(p),await pa(),await cw(p,"created"),hd(p),{...p}}async function bE(e,{steps:t,note:n}={}){let o=(await mr()).flows.find(i=>i.id===e);if(!o)throw new Error("flow not found");let{steps:s,resolved:a}=await hE({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 pa(),await cw(o,"updated",{version:o.version,...n?{note:String(n).slice(0,200)}:{}}),hd(o),{...o}}async function kE(e){let t=await mr(),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 pa(),await cw(r,"deleted"),tn("flows",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function xE(e){return(await mr()).flows.filter(n=>n.steps.some(r=>r.mockId===e)).map(n=>({...n}))}async function vE(e){let n=(await mr()).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(),hd(r);return n.length&&await pa(),n.length}async function SE(e){let t=await mr(),n=t.flows.filter(r=>r.trackId===e);if(n.length){t.flows=t.flows.filter(r=>r.trackId!==e),await pa();for(let r of n)tn("flows",r.id).catch(()=>{})}return n.length}async function TE(){if(!He())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("flows");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await mr();for(let r of n.flows)await hd(r);return{pushed:n.flows.length,source:"plane"}}var pU,mE,cE,lE,uE,dE,fr,iw,hd,lw=G(()=>{de();Er();da();Ir();pU=process.env.BOSTRAT_STATE_DIR||pE.join(process.env.HOME||dU.tmpdir(),".bostrat"),mE=pE.join(pU,"flows.json"),cE=20,lE=80,uE=500,dE=80,fr=null,iw=null;hd=e=>bt("flows",{...e},{trackId:e.trackId}).catch(()=>{})});import gr from"node:fs/promises";import yr from"node:path";import hU from"node:os";import{randomUUID as wU}from"node:crypto";function dc(e){return gU.filter(({re:t})=>t.test(e)).map(({label:t})=>t)}async function Un(){return hr||(uw||=(async()=>{let e=!0;try{hr=JSON.parse(await gr.readFile(EE,"utf8"))}catch{hr={runbooks:[]},e=!1}finally{uw=null}return hr.runbooks||=[],!e&&He()&&await yU().catch(()=>{}),hr})(),uw)}async function Vo(){await Et(EE,hr)}function gd(e){return pc(bt("runbooks",{...e},{trackId:e.trackId}))}async function yU(){let{records:e,source:t}=await st("runbooks");if(!(t!=="plane"||!e.length)){await gr.mkdir(wd,{recursive:!0});for(let n of e){if(n.deletedAt||!n.data?.id)continue;let r=n.data;for(let o of r.versions||[]){let s=await ti("runbooks",r.id,o.v,"md");typeof s=="string"&&await gr.writeFile(wr(r,o.v),s).catch(()=>{})}hr.runbooks.push(r)}hr.runbooks.length&&await Vo()}}function fa(e,t,n={}){return M({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 wr(e,t){return yr.join(wd,`${e.id}.v${t}.md`)}function _E(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 IE(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Buffer.byteLength(e,"utf8");if(t>AE)throw new Error(`runbook is ${Math.round(t/1024)} KB \u2014 over the ${AE/1024} KB cap; a doc that size belongs in the repo, not a runbook`);let n=dc(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 bU(e,t){if(e.trackDeletedAt)throw new Error(`runbook is orphaned (its Track was deleted) \u2014 cannot ${t} it`)}async function kU({trackId:e,status:t}={}){let n=await Un(),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 $E({trackId:e,status:t}={}){let n=await Un(),r=await kU({trackId:e,status:t});if(!He())return{runbooks:r,fleetDegraded:!1};let{records:o,source:s}=await st("runbooks");if(s!=="plane")return{runbooks:r,fleetDegraded:!0};let a=new Set(n.runbooks.map(c=>c.id)),i=o.filter(c=>!c.deletedAt&&c.data?.id&&!a.has(c.data.id)).map(c=>({...c.data,originNode:c.originNode||null,remote:!0})).filter(c=>(!e||c.trackId===e)&&(!t||c.status===t));return{runbooks:[...r,...i],fleetDegraded:!1}}async function dw(e){let t=await xU(e);if(t)return t;if(!He())return null;let{records:n,source:r}=await st("runbooks");if(r!=="plane")return null;let o=n.find(s=>!s.deletedAt&&s.data?.id===e);return o?{...o.data,originNode:o.originNode||null,remote:!0}:null}async function RE(e,t){let n=await ti("runbooks",e.id,t,"md");return typeof n=="string"?n:null}async function xU(e){let n=(await Un()).runbooks.find(r=>r.id===e);return n?{...n}:null}async function OE({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=IE(r),c=await Un(),l={id:wU().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 gr.mkdir(wd,{recursive:!0}),await gr.writeFile(wr(l,1),r),l.versions.push({v:1,mdRel:yr.relative(zo,wr(l,1)),bytes:i,note:null,createdAt:Date.now()}),c.runbooks.push(l),await Vo(),await fa(l,"created",{version:1}),gd(l),pc(_r("runbooks",l.id,1,"md",wr(l,1))),{...l}}async function ME(e,{md:t,note:n}={}){let o=(await Un()).runbooks.find(i=>i.id===e);if(!o)throw new Error("runbook not found");bU(o,"update");let s=IE(t),a=o.version+1;return o.version=a,o.updatedAt=Date.now(),await gr.mkdir(wd,{recursive:!0}),await gr.writeFile(wr(o,a),t),o.versions.push({v:a,mdRel:yr.relative(zo,wr(o,a)),bytes:s,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),await Vo(),await fa(o,"updated",{version:a,...n?{note:String(n).slice(0,200)}:{}}),gd(o),pc(_r("runbooks",o.id,a,"md",wr(o,a))),{...o}}async function CE(e,t){if(t!=="open"&&t!=="done")throw new Error('status must be "open" or "done"');let r=(await Un()).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 Vo(),await fa(r,t==="done"?"done":"reopened"),gd(r),{...r})}async function NE(e){let t=await Un(),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 gr.rm(yr.join(zo,o.mdRel),{force:!0}).catch(()=>{});return await Vo(),r.trackDeletedAt||await fa(r,"deleted"),pc(tn("runbooks",r.id)),{ok:!0,id:e,name:r.name}}async function PE(e){let n=(await Un()).runbooks.filter(r=>r.trackId===e&&!r.trackDeletedAt);for(let r of n)r.trackDeletedAt=Date.now(),r.updatedAt=Date.now(),await fa(r,"orphaned"),r.cwd=null,gd(r);return n.length&&await Vo(),n.length}async function DE(e){let t=await Un(),n=t.runbooks.filter(r=>r.trackId===e);for(let r of n){await fa(r,"deleted");for(let o of r.versions||[])await gr.rm(yr.join(zo,o.mdRel),{force:!0}).catch(()=>{});pc(tn("runbooks",r.id))}return n.length&&(t.runbooks=t.runbooks.filter(r=>r.trackId!==e),await Vo()),n.length}async function BE(){if(!He())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("runbooks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Un();for(let r of n.runbooks){await bt("runbooks",{...r},{trackId:r.trackId}).catch(()=>{});for(let o of r.versions||[])await _r("runbooks",r.id,o.v,"md",yr.join(zo,o.mdRel)).catch(()=>{})}return{pushed:n.runbooks.length,source:"plane"}}var zo,EE,wd,AE,gU,hr,uw,pc,yd=G(()=>{Er();de();Ir();zo=process.env.BOSTRAT_STATE_DIR||yr.join(process.env.HOME||hU.tmpdir(),".bostrat"),EE=yr.join(zo,"runbooks.json"),wd=yr.join(zo,"runbooks"),AE=256*1024,gU=[{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/}];hr=null,uw=null;pc=e=>Promise.resolve(e).catch(()=>{})});import pw from"node:fs/promises";import fc from"node:path";import{randomUUID as vU}from"node:crypto";function mw(e){let t=String(e||"").toLowerCase().replace(/^\./,"");return SU.has(t)?"image":TU.has(t)?"doc":null}function AU(e){let r=fc.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 FE(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>jE)throw new Error(`file too large \u2014 max ${Math.floor(jE/(1024*1024))} MB`);let r=AU(t),o=fc.extname(r).slice(1),s=mw(o);if(!s)throw new Error(`unsupported file type "${o||"unknown"}" \u2014 attach an image or a document`);let a=vU().slice(0,8),i=fw(e);await pw.mkdir(i,{recursive:!0});let c=`${a}-${r}`;return await pw.writeFile(fc.join(i,c),n,{mode:384}),await pw.chmod(fc.join(i,c),384).catch(()=>{}),{id:a,name:r,rel:`${LE}/${c}`,kind:s,size:n.length}}function UE(e){let t=e.map(r=>`\`${r}\``).join(", ");return`[Attached \u2014 please read ${e.length===1?"this file":`these ${e.length} files`}: ${t}]`}function hw(e){return e.role==="user"&&EU.test((e.text||"").trim())}var LE,fw,jE,SU,TU,EU,ww=G(()=>{LE=".bostrat/uploads",fw=e=>fc.join(e,LE),jE=Number(process.env.BOSTRAT_MAX_UPLOAD_BYTES)||24*1024*1024,SU=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","tif","tiff","heic","heif","avif","ico"]),TU=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"]);EU=/\[Attached — please read (?:this file|these \d+ files): [^\]]*\]$/});function Jo(e,t,n=Date.now()){return t?e.idleSince==null?(e.idleSince=n,!1):n-e.idleSince>=6500:(e.idleSince=null,!1)}var HE=G(()=>{});import{execFile as _U}from"node:child_process";import{promisify as IU}from"node:util";function gw(e){return`refs/bostrat/wip/${e}`}function OU(e,t=Date.now()){return`refs/bostrat/rescue/${e}-${t}`}function KE(e=process.env){let t=String(e.BOSTRAT_WIP_SYNC_MS??"").trim().toLowerCase();return t!=="0"&&t!=="off"&&t!=="false"}function MU(e=process.env){let t=Number(e.BOSTRAT_WIP_SYNC_MS);return Number.isFinite(t)&&t>0?t:RU}async function yw(e,{log:t=console,force:n=!1}={}){let{id:r,cwd:o}=e??{};if(!r||!o)return{pushed:!1,reason:"no-workspace"};try{await ro(o,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await ro(o,["remote","get-url","origin"])}catch{return qE.has(o)||(qE.add(o),t.log?.(`[wip-sync] ${r}: no origin remote \u2014 durable code fidelity is chat/memory-only for this Track`)),{pushed:!1,reason:"no-origin"}}try{let s=await Ws(o,"bostrat: wip snapshot"),{stdout:a}=await ro(o,["rev-parse",`${s}^{tree}`]),i=a.trim();if(!n&&bd.get(o)===i)return{pushed:!1,reason:"unchanged"};let c=gw(r);return await ro(o,["push","--force","origin",`${s}:${c}`],WE),bd.set(o,i),await M(e,{type:"code.pushed",actor:"orchestrator",boxId:e.leadBox??null,payload:{ref:c,sha:s,wip:!0,ts:Date.now()}}).catch(()=>{}),t.log?.(`[wip-sync] ${r}: pushed ${s.slice(0,7)} \u2192 ${c}`),{pushed:!0,sha:s,ref:c}}catch(s){return t.log?.(`[wip-sync] ${r}: push failed (will retry): ${String(s?.message||s).split(`
207
- `)[0]}`),{pushed:!1,reason:"push-failed"}}}async function bw(e,{log:t=console}={}){let{id:n,cwd:r}=e??{};if(!n||!r)return{pushed:!1,reason:"no-workspace"};try{await ro(r,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await ro(r,["remote","get-url","origin"])}catch{return{pushed:!1,reason:"no-origin"}}try{let o=await Ws(r,"bostrat: transfer rescue snapshot"),{stdout:s}=await ro(r,["rev-parse",`${o}^{tree}`]),a=s.trim();if(bd.get(r)===a)return{pushed:!1,reason:"unchanged"};let i=OU(n);return await ro(r,["push","origin",`${o}:${i}`],WE),bd.set(r,a),await M(e,{type:"code.pushed",actor:"orchestrator",boxId:e.leadBox??null,payload:{ref:i,sha:o,rescue:!0,ts:Date.now()}}).catch(()=>{}),t.log?.(`[wip-sync] ${n}: rescued stranded work ${o.slice(0,7)} \u2192 ${i}`),{pushed:!0,sha:o,ref:i}}catch(o){return t.log?.(`[wip-sync] ${n}: rescue push failed: ${String(o?.message||o).split(`
208
- `)[0]}`),{pushed:!1,reason:"push-failed"}}}function GE({listTracks:e,sweepMs:t=MU(),log:n=console}){let r=!1,o=async()=>{if(!r){r=!0;try{let a=await e()??[];for(let i of a)De(i)||i?.kind==="setup"||await yw(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 $U,RU,WE,ro,bd,qE,kw=G(()=>{gu();de();Gt();$U=IU(_U),RU=12e4,WE=6e4;ro=(e,t,n=15e3)=>$U("git",["-C",e,...t],{timeout:n,maxBuffer:4*1024*1024}),bd=new Map,qE=new Set});import CU from"node:fs";import xw from"node:fs/promises";import NU from"node:path";function jU(e=process.env){return!!(Re(e)&&e.BOSTRAT_PLANE_TOKEN)}async function zE(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(!jU(t))return{restored:!1,reason:"plane not configured"};let s=bs(e),a=NU.join(s,`${o}.ndjson`);try{if(CU.statSync(a).size>0)return{restored:!1,reason:"log not empty"}}catch{}let i=Re(t),c={authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`},l=[],u=0;for(;;){let p=new AbortController,f=setTimeout(()=>p.abort(),BU),w;try{w=await n(`${i}/v1/spine/${encodeURIComponent(o)}?after=${u}&limit=${PU}`,{headers:c,signal:p.signal})}finally{clearTimeout(f)}if(w.status===404)return{restored:!1,reason:"unknown to plane"};if(!w.ok)return{restored:!1,reason:`plane ${w.status}`};let m=await w.json();for(let g of m.events||[])l.push(JSON.stringify(g));if(l.length>DU)return{restored:!1,reason:"event count over safety cap"};if(m.next==null)break;u=m.next}if(!l.length)return{restored:!1,reason:"unknown to plane"};await xw.mkdir(s,{recursive:!0});let d=`${a}.pull-${process.pid}-${Date.now()}`;return await xw.writeFile(d,l.join(`
206
+ `)}`:t),this.name="MockRenderError"}},ns=null,bw=null;Un=e=>kt("mocks",{...e},{trackId:e.trackId}).catch(()=>{}),Hn=(e,t,n)=>{let r=(e.versions||[]).find(s=>s.v===t),o=n==="mp4"||n==="webm"?mc(e,r,"video"):r&&mc(e,r,n)||(n==="html"?Qt(e,t).html:null);return o?Mr("mocks",e.id,t,n,o).catch(()=>{}):Promise.resolve()};hc=e=>et.join(e,".bostrat","mocks");fU=Buffer.from([137,80,78,71,13,10,26,10]);xU=kU,kw=Promise.resolve()});import TU from"node:fs/promises";import EE from"node:path";import EU from"node:os";import{randomUUID as _E}from"node:crypto";async function yr(){return gr||(Aw||=(async()=>{let e=!0;try{gr=JSON.parse(await TU.readFile(IE,"utf8"))}catch{gr={flows:[]},e=!1}finally{Aw=null}if(gr.flows||=[],!e&&He()){let{records:t,source:n}=await st("flows").catch(()=>({records:[],source:"error"}));if(n==="plane"){for(let r of t)!r.deletedAt&&r.data?.id&&gr.flows.push(r.data);gr.flows.length&&await xa().catch(()=>{})}}return gr})(),Aw)}async function xa(){await It(IE,gr)}function Tw(e,t,n={}){return M({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 $E({trackId:e,steps:t,prevSteps:n=[]}){if(!Array.isArray(t)||t.length<1||t.length>vE)throw new Error(`steps must be an array of 1-${vE}`);let r=await wc({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>AE)throw new Error(`${l}: caption over ${AE} chars`);let d=c.title==null?null:String(c.title).trim()||null;if(d&&d.length>TE)throw new Error(`${l}: title over ${TE} chars`);let p=String(c.mock??"").trim().replace(/^mock:/,"");if(!p)throw new Error(`${l}: mock (name or id) required`);let f=r.filter(x=>x.id===p);if(f.length||(f=r.filter(x=>x.name.toLowerCase()===p.toLowerCase())),!f.length)throw new Error(`${l}: no mock matching "${p}" in this Track \u2014 see \`bostrat-mock ls\``);if(f.length>1)throw new Error(`${l}: "${p}" is ambiguous (${f.map(x=>`mock:${x.id}`).join(", ")}) \u2014 use the id`);let w=f[0],m=null;if(c.v!=null&&(m=Number(c.v),!Number.isInteger(m)||!(w.versions||[]).some(x=>x.v===m)))throw new Error(`${l}: "${w.name}" has no captured v${c.v} to pin`);let g=o.findIndex(x=>x.mockId===w.id),y=g>=0?o.splice(g,1)[0].id:_E().slice(0,8);s.push({id:y,mockId:w.id,caption:u,title:d,v:m})}let a={};for(let i of s)i.mockId in a||(a[i.mockId]=r.find(c=>c.id===i.mockId)?.readyVersion??null);return{steps:s,resolved:a}}function IU(e){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");if(e.trim().length>SE)throw new Error(`name over ${SE} chars`);return e.trim()}async function RE({trackId:e}={}){let t=await yr();return(e?t.flows.filter(r=>r.trackId===e):t.flows).map(r=>({...r}))}async function $U(e){let n=(await yr()).flows.find(r=>r.id===e);return n?{...n}:null}async function OE(e){let t=await $U(e);if(!t)return null;let n=new Map((await wc({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=fn(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 ME({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=IU(t),i=await yr(),c=i.flows.find(f=>f.trackId===e&&f.name.toLowerCase()===a.toLowerCase());if(c)throw new Error(`flow "${c.name}" already exists in this Track (flow:${c.id}) \u2014 revise it with \`bostrat-flow update\``);let{steps:l,resolved:u}=await $E({trackId:e,steps:n}),d=Date.now(),p={id:_E().slice(0,8),trackId:e,box:o||null,agent:s||null,name:a,cwd:r,version:1,versions:[{v:1,steps:l,resolved:u,note:null,createdAt:d}],steps:l,createdAt:d,updatedAt:d};return i.flows.push(p),await xa(),await Tw(p,"created"),xd(p),{...p}}async function CE(e,{steps:t,note:n}={}){let o=(await yr()).flows.find(i=>i.id===e);if(!o)throw new Error("flow not found");let{steps:s,resolved:a}=await $E({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 xa(),await Tw(o,"updated",{version:o.version,...n?{note:String(n).slice(0,200)}:{}}),xd(o),{...o}}async function NE(e){let t=await yr(),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 xa(),await Tw(r,"deleted"),rn("flows",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function PE(e){return(await yr()).flows.filter(n=>n.steps.some(r=>r.mockId===e)).map(n=>({...n}))}async function DE(e){let n=(await yr()).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(),xd(r);return n.length&&await xa(),n.length}async function BE(e){let t=await yr(),n=t.flows.filter(r=>r.trackId===e);if(n.length){t.flows=t.flows.filter(r=>r.trackId!==e),await xa();for(let r of n)rn("flows",r.id).catch(()=>{})}return n.length}async function jE(){if(!He())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("flows");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await yr();for(let r of n.flows)await xd(r);return{pushed:n.flows.length,source:"plane"}}var _U,IE,vE,SE,AE,TE,gr,Aw,xd,Ew=G(()=>{fe();Or();ka();Cr();_U=process.env.BOSTRAT_STATE_DIR||EE.join(process.env.HOME||EU.tmpdir(),".bostrat"),IE=EE.join(_U,"flows.json"),vE=20,SE=80,AE=500,TE=80,gr=null,Aw=null;xd=e=>kt("flows",{...e},{trackId:e.trackId}).catch(()=>{})});import xr from"node:fs/promises";import vr from"node:path";import RU from"node:os";import{randomUUID as OU}from"node:crypto";function gc(e){return MU.filter(({re:t})=>t.test(e)).map(({label:t})=>t)}async function qn(){return br||(_w||=(async()=>{let e=!0;try{br=JSON.parse(await xr.readFile(FE,"utf8"))}catch{br={runbooks:[]},e=!1}finally{_w=null}return br.runbooks||=[],!e&&He()&&await CU().catch(()=>{}),br})(),_w)}async function os(){await It(FE,br)}function Sd(e){return yc(kt("runbooks",{...e},{trackId:e.trackId}))}async function CU(){let{records:e,source:t}=await st("runbooks");if(!(t!=="plane"||!e.length)){await xr.mkdir(vd,{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 li("runbooks",r.id,o.v,"md");typeof s=="string"&&await xr.writeFile(kr(r,o.v),s).catch(()=>{})}br.runbooks.push(r)}br.runbooks.length&&await os()}}function va(e,t,n={}){return M({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 kr(e,t){return vr.join(vd,`${e.id}.v${t}.md`)}function UE(e,t=null){let n=e.versions||[];return t!=null?n.find(r=>r.v===Number(t))||null:n.length?n[n.length-1]:null}function HE(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Buffer.byteLength(e,"utf8");if(t>LE)throw new Error(`runbook is ${Math.round(t/1024)} KB \u2014 over the ${LE/1024} KB cap; a doc that size belongs in the repo, not a runbook`);let n=gc(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 NU(e,t){if(e.trackDeletedAt)throw new Error(`runbook is orphaned (its Track was deleted) \u2014 cannot ${t} it`)}async function PU({trackId:e,status:t}={}){let n=await qn(),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 WE({trackId:e,status:t}={}){let n=await qn(),r=await PU({trackId:e,status:t});if(!He())return{runbooks:r,fleetDegraded:!1};let{records:o,source:s}=await st("runbooks");if(s!=="plane")return{runbooks:r,fleetDegraded:!0};let a=new Set(n.runbooks.map(c=>c.id)),i=o.filter(c=>!c.deletedAt&&c.data?.id&&!a.has(c.data.id)).map(c=>({...c.data,originNode:c.originNode||null,remote:!0})).filter(c=>(!e||c.trackId===e)&&(!t||c.status===t));return{runbooks:[...r,...i],fleetDegraded:!1}}async function Iw(e){let t=await DU(e);if(t)return t;if(!He())return null;let{records:n,source:r}=await st("runbooks");if(r!=="plane")return null;let o=n.find(s=>!s.deletedAt&&s.data?.id===e);return o?{...o.data,originNode:o.originNode||null,remote:!0}:null}async function qE(e,t){let n=await li("runbooks",e.id,t,"md");return typeof n=="string"?n:null}async function DU(e){let n=(await qn()).runbooks.find(r=>r.id===e);return n?{...n}:null}async function KE({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=HE(r),c=await qn(),l={id:OU().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 xr.mkdir(vd,{recursive:!0}),await xr.writeFile(kr(l,1),r),l.versions.push({v:1,mdRel:vr.relative(rs,kr(l,1)),bytes:i,note:null,createdAt:Date.now()}),c.runbooks.push(l),await os(),await va(l,"created",{version:1}),Sd(l),yc(Mr("runbooks",l.id,1,"md",kr(l,1))),{...l}}async function GE(e,{md:t,note:n}={}){let o=(await qn()).runbooks.find(i=>i.id===e);if(!o)throw new Error("runbook not found");NU(o,"update");let s=HE(t),a=o.version+1;return o.version=a,o.updatedAt=Date.now(),await xr.mkdir(vd,{recursive:!0}),await xr.writeFile(kr(o,a),t),o.versions.push({v:a,mdRel:vr.relative(rs,kr(o,a)),bytes:s,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),await os(),await va(o,"updated",{version:a,...n?{note:String(n).slice(0,200)}:{}}),Sd(o),yc(Mr("runbooks",o.id,a,"md",kr(o,a))),{...o}}async function zE(e,t){if(t!=="open"&&t!=="done")throw new Error('status must be "open" or "done"');let r=(await qn()).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 os(),await va(r,t==="done"?"done":"reopened"),Sd(r),{...r})}async function VE(e){let t=await qn(),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 xr.rm(vr.join(rs,o.mdRel),{force:!0}).catch(()=>{});return await os(),r.trackDeletedAt||await va(r,"deleted"),yc(rn("runbooks",r.id)),{ok:!0,id:e,name:r.name}}async function JE(e){let n=(await qn()).runbooks.filter(r=>r.trackId===e&&!r.trackDeletedAt);for(let r of n)r.trackDeletedAt=Date.now(),r.updatedAt=Date.now(),await va(r,"orphaned"),r.cwd=null,Sd(r);return n.length&&await os(),n.length}async function YE(e){let t=await qn(),n=t.runbooks.filter(r=>r.trackId===e);for(let r of n){await va(r,"deleted");for(let o of r.versions||[])await xr.rm(vr.join(rs,o.mdRel),{force:!0}).catch(()=>{});yc(rn("runbooks",r.id))}return n.length&&(t.runbooks=t.runbooks.filter(r=>r.trackId!==e),await os()),n.length}async function XE(){if(!He())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("runbooks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await qn();for(let r of n.runbooks){await kt("runbooks",{...r},{trackId:r.trackId}).catch(()=>{});for(let o of r.versions||[])await Mr("runbooks",r.id,o.v,"md",vr.join(rs,o.mdRel)).catch(()=>{})}return{pushed:n.runbooks.length,source:"plane"}}var rs,FE,vd,LE,MU,br,_w,yc,Ad=G(()=>{Or();fe();Cr();rs=process.env.BOSTRAT_STATE_DIR||vr.join(process.env.HOME||RU.tmpdir(),".bostrat"),FE=vr.join(rs,"runbooks.json"),vd=vr.join(rs,"runbooks"),LE=256*1024,MU=[{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/}];br=null,_w=null;yc=e=>Promise.resolve(e).catch(()=>{})});import $w from"node:fs/promises";import bc from"node:path";import{randomUUID as BU}from"node:crypto";function Ow(e){let t=String(e||"").toLowerCase().replace(/^\./,"");return jU.has(t)?"image":LU.has(t)?"doc":null}function FU(e){let r=bc.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 e_(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>ZE)throw new Error(`file too large \u2014 max ${Math.floor(ZE/(1024*1024))} MB`);let r=FU(t),o=bc.extname(r).slice(1),s=Ow(o);if(!s)throw new Error(`unsupported file type "${o||"unknown"}" \u2014 attach an image or a document`);let a=BU().slice(0,8),i=Rw(e);await $w.mkdir(i,{recursive:!0});let c=`${a}-${r}`;return await $w.writeFile(bc.join(i,c),n,{mode:384}),await $w.chmod(bc.join(i,c),384).catch(()=>{}),{id:a,name:r,rel:`${QE}/${c}`,kind:s,size:n.length}}function t_(e){let t=e.map(r=>`\`${r}\``).join(", ");return`[Attached \u2014 please read ${e.length===1?"this file":`these ${e.length} files`}: ${t}]`}function Mw(e){return e.role==="user"&&UU.test((e.text||"").trim())}var QE,Rw,ZE,jU,LU,UU,Cw=G(()=>{QE=".bostrat/uploads",Rw=e=>bc.join(e,QE),ZE=Number(process.env.BOSTRAT_MAX_UPLOAD_BYTES)||24*1024*1024,jU=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","tif","tiff","heic","heif","avif","ico"]),LU=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"]);UU=/\[Attached — please read (?:this file|these \d+ files): [^\]]*\]$/});function ss(e,t,n=Date.now()){return t?e.idleSince==null?(e.idleSince=n,!1):n-e.idleSince>=6500:(e.idleSince=null,!1)}var n_=G(()=>{});import{execFile as HU}from"node:child_process";import{promisify as WU}from"node:util";function Nw(e){return`refs/bostrat/wip/${e}`}function GU(e,t=Date.now()){return`refs/bostrat/rescue/${e}-${t}`}function s_(e=process.env){let t=String(e.BOSTRAT_WIP_SYNC_MS??"").trim().toLowerCase();return t!=="0"&&t!=="off"&&t!=="false"}function zU(e=process.env){let t=Number(e.BOSTRAT_WIP_SYNC_MS);return Number.isFinite(t)&&t>0?t:KU}function a_(e){let t=e?.workspace;return t?.kind==="multi"?(Array.isArray(t.repos)?t.repos:[]).filter(n=>n?.dir).map(n=>({dir:n.dir,name:n.name??null,repo:n.repo??null})):e?.cwd?[{dir:e.cwd,name:null,repo:t?.repo??null}]:[]}async function VU(e,{log:t=console,force:n=!1,checkout:r=null}={}){let o=e?.id,s=r?.dir??e?.cwd;if(!o||!s)return{pushed:!1,reason:"no-workspace"};let a=r?.name?`${o}/${r.name}`:o;try{await co(s,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await co(s,["remote","get-url","origin"])}catch{return r_.has(s)||(r_.add(s),t.log?.(`[wip-sync] ${a}: no origin remote \u2014 durable code fidelity is chat/memory-only for this checkout`)),{pushed:!1,reason:"no-origin"}}try{let i=await ta(s,"bostrat: wip snapshot"),{stdout:c}=await co(s,["rev-parse",`${i}^{tree}`]),l=c.trim();if(!n&&Td.get(s)===l)return{pushed:!1,reason:"unchanged"};let u=Nw(o);return await co(s,["push","--force","origin",`${i}:${u}`],o_),Td.set(s,l),await M(e,{type:"code.pushed",actor:"orchestrator",boxId:e.leadBox??null,payload:{ref:u,sha:i,wip:!0,...i_(r),ts:Date.now()}}).catch(()=>{}),t.log?.(`[wip-sync] ${a}: pushed ${i.slice(0,7)} \u2192 ${u}`),{pushed:!0,sha:i,ref:u}}catch(i){return t.log?.(`[wip-sync] ${a}: push failed (will retry): ${String(i?.message||i).split(`
207
+ `)[0]}`),{pushed:!1,reason:"push-failed"}}}async function Pw(e,{log:t=console,force:n=!1}={}){let r=[],o=[];for(let s of a_(e)){let a=await VU(e,{log:t,force:n,checkout:s});a.pushed?r.push({name:s.name,repo:s.repo,ref:a.ref,sha:a.sha}):o.push({name:s.name,repo:s.repo,reason:a.reason})}return{pushed:r,skipped:o}}async function JU(e,{log:t=console,checkout:n=null,ts:r=Date.now()}={}){let o=e?.id,s=n?.dir??e?.cwd;if(!o||!s)return{pushed:!1,reason:"no-workspace"};let a=n?.name?`${o}/${n.name}`:o;try{await co(s,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await co(s,["remote","get-url","origin"])}catch{return{pushed:!1,reason:"no-origin"}}try{let i=await ta(s,"bostrat: transfer rescue snapshot"),{stdout:c}=await co(s,["rev-parse",`${i}^{tree}`]),l=c.trim();if(Td.get(s)===l)return{pushed:!1,reason:"unchanged"};let u=GU(o,r);return await co(s,["push","origin",`${i}:${u}`],o_),Td.set(s,l),await M(e,{type:"code.pushed",actor:"orchestrator",boxId:e.leadBox??null,payload:{ref:u,sha:i,rescue:!0,...i_(n),ts:Date.now()}}).catch(()=>{}),t.log?.(`[wip-sync] ${a}: rescued stranded work ${i.slice(0,7)} \u2192 ${u}`),{pushed:!0,sha:i,ref:u}}catch(i){return t.log?.(`[wip-sync] ${a}: rescue push failed: ${String(i?.message||i).split(`
208
+ `)[0]}`),{pushed:!1,reason:"push-failed"}}}async function Dw(e,{log:t=console,ts:n=Date.now()}={}){let r=[],o=[];for(let s of a_(e)){let a=await JU(e,{log:t,checkout:s,ts:n});a.pushed?r.push({name:s.name,repo:s.repo,ref:a.ref,sha:a.sha}):o.push({name:s.name,repo:s.repo,reason:a.reason})}return{pushed:r,skipped:o}}function c_({listTracks:e,sweepMs:t=zU(),log:n=console}){let r=!1,o=async()=>{if(!r){r=!0;try{let a=await e()??[];for(let i of a)je(i)||i?.kind==="setup"||await Pw(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 qU,KU,o_,co,Td,r_,i_,Bw=G(()=>{Su();fe();Jt();qU=WU(HU),KU=12e4,o_=6e4;co=(e,t,n=15e3)=>qU("git",["-C",e,...t],{timeout:n,maxBuffer:4*1024*1024}),Td=new Map,r_=new Set,i_=e=>e?.name||e?.repo?{name:e.name??null,repo:e.repo??null}:{}});import YU from"node:fs";import jw from"node:fs/promises";import XU from"node:path";function t4(e=process.env){return!!(Oe(e)&&e.BOSTRAT_PLANE_TOKEN)}async function l_(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(!t4(t))return{restored:!1,reason:"plane not configured"};let s=Os(e),a=XU.join(s,`${o}.ndjson`);try{if(YU.statSync(a).size>0)return{restored:!1,reason:"log not empty"}}catch{}let i=Oe(t),c={authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`},l=[],u=0;for(;;){let p=new AbortController,f=setTimeout(()=>p.abort(),e4),w;try{w=await n(`${i}/v1/spine/${encodeURIComponent(o)}?after=${u}&limit=${ZU}`,{headers:c,signal:p.signal})}finally{clearTimeout(f)}if(w.status===404)return{restored:!1,reason:"unknown to plane"};if(!w.ok)return{restored:!1,reason:`plane ${w.status}`};let m=await w.json();for(let g of m.events||[])l.push(JSON.stringify(g));if(l.length>QU)return{restored:!1,reason:"event count over safety cap"};if(m.next==null)break;u=m.next}if(!l.length)return{restored:!1,reason:"unknown to plane"};await jw.mkdir(s,{recursive:!0});let d=`${a}.pull-${process.pid}-${Date.now()}`;return await jw.writeFile(d,l.join(`
209
209
  `)+`
210
- `),await xw.rename(d,a),r.log?.(`[spine-pull] rehydrated ${o}: ${l.length} event(s) \u2192 ${a}`),{restored:!0,rows:l.length}}var PU,DU,BU,VE=G(()=>{pt();de();PU=1e3,DU=5e5,BU=3e4});function JE(e,t=Date.now()){let n=e.find(s=>s.reconcile||s.ciFix);if(n?.reconcile)return{status:"working",since:n.reconcile.delegatedAt,summary:"reconciling the branch"};if(n?.ciFix)return{status:"working",since:n.ciFix.delegatedAt,summary:"repairing failed checks"};let r=e.find(s=>s.reconcileAwait||s.ciFixAwait);if(r?.reconcileAwait)return{status:"waiting",since:r.reconcileAwait.since,summary:"fix pushed \u2014 waiting for mergeability"};if(r?.ciFixAwait)return{status:"waiting",since:r.ciFixAwait.since,summary:"fix pushed \u2014 waiting for CI"};let o=e.filter(s=>s.autoMerge||s.armedAt);return o.length?{status:"waiting",since:Math.min(...o.map(s=>s.autoMerge?.armedAt||s.armedAt||t)),count:o.length,summary:o.length===1?"auto-merge armed \u2014 lands when checks pass":`auto-merge armed on ${o.length} PRs`}:null}function YE(e){let t=(e||[]).filter(n=>!LU.has(n.state)&&!n.ciFix&&!n.reconcile&&!n.ciFixAwait&&!n.reconcileAwait&&!n.autoMerge&&!n.armedAt);return t.length?{count:t.length,since:Math.min(...t.map(n=>n.announcedAt||n.firstSeen||Date.now())),summary:t.length===1?`PR #${t[0].number} is open \u2014 review, merge or arm it`:`${t.length} open PRs waiting on you`}:null}function XE({archivedAt:e=null,archiving:t=!1,prompted:n=!1,openActions:r=0,openActionSince:o=null,loopAttention:s=!1,prDecisions:a=null,operation:i=null,phase:c=null,working:l=!1,workingSince:u=null,pending:d=null,completedTurnAt:p=null,live:f=!1,now:w=Date.now()}={}){return e&&!t?fn("archived","lifecycle",e):n||r>0||s?fn("needs-you",n?"pane":s?"loop":"obligations",o||w,{count:r||(n||s?1:null)}):t?fn("archiving","lifecycle",e||w):a?.count?fn("needs-you","pr",a.since,{count:a.count,summary:a.summary??null}):i?.status==="working"?fn("working","operation",i.since,{summary:i.summary??null,count:i.count??null}):(l||n)&&c?.phase?fn("working","agent-phase",c.at,{summary:c.summary??null}):l?fn("working","pane",u||w):i?.status==="waiting"?fn("waiting","operation",i.since,{summary:i.summary??null,count:i.count??null}):d?.count?fn("waiting",d.source||"pending",d.since,{summary:d.summary??null,count:d.count}):p&&f?fn("settled","obligations",p,{summary:"no open actions"}):fn("idle","fallback",p||w)}var fn,LU,ZE=G(()=>{fn=(e,t,n,r={})=>({kind:e,source:t,since:n||0,...r});LU=new Set(["merged","closed","lost"])});function FU(e,t){let n=0;for(let o of e||[]){if(o?.type!=="track.obligations.changed")continue;let s=Number(o.payload?.open);n=Number.isFinite(s)&&s>0?Math.floor(s):0}let r=Number(t?.openActions)||0;return r===n?null:{open:r,since:r?t.openActionSince??null:null}}async function UU(e,t,n){let r=FU(t,n);return r?M(e,{type:"track.obligations.changed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),open:r.open,since:r.since}}).catch(()=>null):null}async function vw(e){if(kd.has(e.id))return kd.get(e.id);let t=await K(e).catch(()=>[]),n=[];try{n=_n(t)}catch{}let r=ou(n),o=n.filter(f=>f?.kind==="followup-offer"&&f.status==="open"),s=new Set(t.filter(f=>f.type==="prompt.answered").map(f=>f.payload?.promptId)),a=t.filter(f=>f.type==="prompt.raised"&&f.payload?.promptId&&!s.has(f.payload.promptId)),i=[...r,...o,...a.map(f=>({ts:f.payload?.ts??f.ts}))],c=null;for(let f of t){if(f.type!=="track.phase.changed")continue;let w=f.payload||{};c=w.phase?{phase:w.phase,summary:w.summary??null,scope:w.scope??null,phaseId:w.phaseId??null,at:w.ts??f.ts}:null}let l=n.flatMap(f=>f?.kind==="job-dock"?f.jobs||[]:[]).filter(f=>f?.status==="running"),u=t.reduce((f,w)=>w.type==="turn.agent"?Math.max(f,w.payload?.ts??w.ts??0):f,0)||null,d=t.reduce((f,w)=>w.type==="turn.user"?Math.max(f,w.payload?.ts??w.ts??0):f,0)||null,p={openActions:i.length,openActionSince:i.length?Math.min(...i.map(f=>f.ts||Date.now())):null,phase:c,completedTurnAt:u,currentTurnAt:d,runningJobs:l.length,runningJobsSince:l.length?Math.min(...l.map(f=>f.startedTs||Date.now())):null};return kd.set(e.id,p),!De(e)&&e.kind!=="setup"&&UU(e,t,p),p}function QE({trackOf:e,debounceMs:t=HU,log:n=console}={}){if(typeof e!="function")throw new Error("watchObligations: trackOf(id) is required");let r=o=>{let s=o?.trackId;if(!s)return;clearTimeout(mc.get(s));let a=setTimeout(()=>{mc.delete(s),Promise.resolve(e(s)).then(i=>i&&!De(i)&&i.kind!=="setup"?vw(i):null).catch(i=>n.warn?.(`[obligations] fold ${s} failed: ${i?.message||i}`))},t);a.unref?.(),mc.set(s,a)};return Je.on("event",r),()=>{Je.off("event",r);for(let o of mc.values())clearTimeout(o);mc.clear()}}var kd,HU,mc,Sw=G(()=>{de();su();Gt();kd=new Map;Je.on("event",e=>{e?.trackId&&kd.delete(e.trackId)});HU=750,mc=new Map});import{randomUUID as qU}from"node:crypto";async function vd(e,t,n={}){let r={operationId:qU(),kind:t,startedAt:Date.now(),...n};return xd.set(e.id,r),await M(e,{type:"track.operation.changed",actor:"orchestrator",source:"orchestrator",payload:{ts:r.startedAt,state:"started",...r}}).catch(()=>{}),r}async function Tw(e,t,n="completed",r=null){xd.get(e.id)?.operationId===t?.operationId&&xd.delete(e.id),await M(e,{type:"track.operation.changed",actor:"orchestrator",source:"orchestrator",payload:{ts:Date.now(),state:"finished",operationId:t?.operationId,kind:t?.kind,outcome:n,...r?{error:String(r)}:{}}}).catch(()=>{})}var xd,e_,Aw=G(()=>{de();xd=new Map;e_=e=>xd.get(e)||null});var C_={};Dp(C_,{HANDOFF_LATEST_REL:()=>Yo,KNOWN_AGENTS:()=>Ac,TRACK_NAME_MAX:()=>jw,addTrackRepo:()=>ng,adoptTrack:()=>kg,agentAvailability:()=>_d,announceNodeUpdate:()=>qn,answerFullscreenOffer:()=>fg,answerPrompt:()=>$d,archiveTrack:()=>Zo,archiveTrackForMergedPr:()=>ar,augmentFirstPromptAfterHandoff:()=>d_,buildAgentCmd:()=>Uw,canResumeSubtask:()=>R_,cancelQueued:()=>Ic,cancelQueuedToDraft:()=>Jw,cancelStopJob:()=>$c,cancelSubtask:()=>Ld,changedRepos:()=>Ko,commitTransferOut:()=>Bd,createSetupTrack:()=>sg,createTrack:()=>Md,deleteTrack:()=>ig,demoteTransferredTracks:()=>bg,ensureLeadEpochs:()=>ka,forceMergeSubtask:()=>Tg,getHandoffJob:()=>Ta,getSubtaskJob:()=>Q4,getTrack:()=>se,getTransferOutJob:()=>wg,healDeadLead:()=>Sc,interruptLead:()=>Od,isArchiving:()=>U4,isHandoffNoteEcho:()=>Nw,isInterruptEcho:()=>Pw,isModelSwitchEcho:()=>Dw,leadCliDead:()=>lg,listSubtaskJobs:()=>es,listTracks:()=>we,matchTranscriptsToBoxes:()=>m_,mergeNotifyMessage:()=>E_,navigatePrompt:()=>zw,notifyTrackForMergedPr:()=>ir,notifyTrackForResolvedPr:()=>Cd,offerFollowupsForMergedPr:()=>Qo,pendingOffers:()=>Kw,queueGauges:()=>Vw,queueShipCompleteNotify:()=>Xw,queuedMessages:()=>Xo,rawTrack:()=>Ww,reapArchivedOrphans:()=>pg,reconcileDemotedTracks:()=>dg,reconcileHandoffOutcome:()=>__,reconcileInterruptedHandoffs:()=>hg,reconcileInterruptedSubtasks:()=>xg,reconcileNodeUpdateNotices:()=>qw,reconcileSubtaskOutcome:()=>$_,refreshStandingInstructions:()=>og,refuseIfTransferred:()=>yg,rehydrateLead:()=>Oc,removeTrackRepo:()=>rg,renameTrack:()=>ug,reposOf:()=>Bt,resolveTrackBox:()=>Xi,resolveTrackBoxByHookToken:()=>_c,restartLead:()=>Pd,resumeAgentCmd:()=>Hw,sayToLead:()=>Dt,sendOptionsForAgent:()=>En,setTrackDraft:()=>eg,setTrackModel:()=>tg,startLeadHandoff:()=>Dd,startSpinUpView:()=>Zw,startSubtask:()=>Sg,startTransferOut:()=>gg,stopJobActive:()=>g_,subtaskMessages:()=>Gw,trackMessages:()=>Id,unarchiveTrack:()=>Nd});import ee from"node:fs/promises";import oe from"node:path";import{randomUUID as Ad}from"node:crypto";import{execFile as WU}from"node:child_process";import{promisify as KU}from"node:util";function Uw(e,{skipPermissions:t=!0}={}){let n=Ed[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 Hw(e,t,{skipPermissions:n=!0,cwd:r=null,peerName:o=null}={}){let s=Ed[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&&!sn(r,t)){let c=o&&je(o)?` --name ${o}`:"";return`${s.base} --session-id ${t}${c}${i}`}return`${s.base} --resume ${t}${i}`}case"cursor":return`${s.base} --continue${i}`;case"codex":return`${s.base} resume --last${i}`;default:return`${s.base}${i}`}}function Sa(e){let t=Ed[e];if(t)return process.env[t.envVar]||t.base}async function _d({maxAgeMs:e=6e4}={}){if(oo.value&&Date.now()-oo.at<e)return oo.value;let t=oo.value,n=await Promise.all(Ac.map(async r=>{let o=await Ll(Sa(r),{retries:[]});return o===As?[r,t?.[r]??!0]:[r,o===jl]}));return oo.value=Object.fromEntries(n),oo.at=Date.now(),oo.value}async function Ec(e,t=!0){let n=Uw(e,{skipPermissions:t});if(await Ll(n)===Ts){oo.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.":ff[r]?`Install it on this node: ${ff[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 d_(e,t=Yo){return`${e.trim()}
210
+ `),await jw.rename(d,a),r.log?.(`[spine-pull] rehydrated ${o}: ${l.length} event(s) \u2192 ${a}`),{restored:!0,rows:l.length}}var ZU,QU,e4,u_=G(()=>{ft();fe();ZU=1e3,QU=5e5,e4=3e4});function d_(e,t=Date.now()){let n=e.find(s=>s.reconcile||s.ciFix);if(n?.reconcile)return{status:"working",since:n.reconcile.delegatedAt,summary:"reconciling the branch"};if(n?.ciFix)return{status:"working",since:n.ciFix.delegatedAt,summary:"repairing failed checks"};let r=e.find(s=>s.reconcileAwait||s.ciFixAwait);if(r?.reconcileAwait)return{status:"waiting",since:r.reconcileAwait.since,summary:"fix pushed \u2014 waiting for mergeability"};if(r?.ciFixAwait)return{status:"waiting",since:r.ciFixAwait.since,summary:"fix pushed \u2014 waiting for CI"};let o=e.filter(s=>s.autoMerge||s.armedAt);return o.length?{status:"waiting",since:Math.min(...o.map(s=>s.autoMerge?.armedAt||s.armedAt||t)),count:o.length,summary:o.length===1?"auto-merge armed \u2014 lands when checks pass":`auto-merge armed on ${o.length} PRs`}:null}function p_(e){let t=(e||[]).filter(n=>!n4.has(n.state)&&!n.ciFix&&!n.reconcile&&!n.ciFixAwait&&!n.reconcileAwait&&!n.autoMerge&&!n.armedAt);return t.length?{count:t.length,since:Math.min(...t.map(n=>n.announcedAt||n.firstSeen||Date.now())),summary:t.length===1?`PR #${t[0].number} is open \u2014 review, merge or arm it`:`${t.length} open PRs waiting on you`}:null}function f_({archivedAt:e=null,archiving:t=!1,prompted:n=!1,openActions:r=0,openActionSince:o=null,loopAttention:s=!1,prDecisions:a=null,operation:i=null,phase:c=null,working:l=!1,workingSince:u=null,pending:d=null,completedTurnAt:p=null,live:f=!1,now:w=Date.now()}={}){return e&&!t?mn("archived","lifecycle",e):n||r>0||s?mn("needs-you",n?"pane":s?"loop":"obligations",o||w,{count:r||(n||s?1:null)}):t?mn("archiving","lifecycle",e||w):a?.count?mn("needs-you","pr",a.since,{count:a.count,summary:a.summary??null}):i?.status==="working"?mn("working","operation",i.since,{summary:i.summary??null,count:i.count??null}):(l||n)&&c?.phase?mn("working","agent-phase",c.at,{summary:c.summary??null}):l?mn("working","pane",u||w):i?.status==="waiting"?mn("waiting","operation",i.since,{summary:i.summary??null,count:i.count??null}):d?.count?mn("waiting",d.source||"pending",d.since,{summary:d.summary??null,count:d.count}):p&&f?mn("settled","obligations",p,{summary:"no open actions"}):mn("idle","fallback",p||w)}var mn,n4,m_=G(()=>{mn=(e,t,n,r={})=>({kind:e,source:t,since:n||0,...r});n4=new Set(["merged","closed","lost"])});function r4(e,t){let n=0;for(let o of e||[]){if(o?.type!=="track.obligations.changed")continue;let s=Number(o.payload?.open);n=Number.isFinite(s)&&s>0?Math.floor(s):0}let r=Number(t?.openActions)||0;return r===n?null:{open:r,since:r?t.openActionSince??null:null}}async function o4(e,t,n){let r=r4(t,n);return r?M(e,{type:"track.obligations.changed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),open:r.open,since:r.since}}).catch(()=>null):null}async function Lw(e){if(Ed.has(e.id))return Ed.get(e.id);let t=await K(e).catch(()=>[]),n=[];try{n=Rn(t)}catch{}let r=lu(n),o=n.filter(f=>f?.kind==="followup-offer"&&f.status==="open"),s=new Set(t.filter(f=>f.type==="prompt.answered").map(f=>f.payload?.promptId)),a=t.filter(f=>f.type==="prompt.raised"&&f.payload?.promptId&&!s.has(f.payload.promptId)),i=[...r,...o,...a.map(f=>({ts:f.payload?.ts??f.ts}))],c=null;for(let f of t){if(f.type!=="track.phase.changed")continue;let w=f.payload||{};c=w.phase?{phase:w.phase,summary:w.summary??null,scope:w.scope??null,phaseId:w.phaseId??null,at:w.ts??f.ts}:null}let l=n.flatMap(f=>f?.kind==="job-dock"?f.jobs||[]:[]).filter(f=>f?.status==="running"),u=t.reduce((f,w)=>w.type==="turn.agent"?Math.max(f,w.payload?.ts??w.ts??0):f,0)||null,d=t.reduce((f,w)=>w.type==="turn.user"?Math.max(f,w.payload?.ts??w.ts??0):f,0)||null,p={openActions:i.length,openActionSince:i.length?Math.min(...i.map(f=>f.ts||Date.now())):null,phase:c,completedTurnAt:u,currentTurnAt:d,runningJobs:l.length,runningJobsSince:l.length?Math.min(...l.map(f=>f.startedTs||Date.now())):null};return Ed.set(e.id,p),!je(e)&&e.kind!=="setup"&&o4(e,t,p),p}function h_({trackOf:e,debounceMs:t=s4,log:n=console}={}){if(typeof e!="function")throw new Error("watchObligations: trackOf(id) is required");let r=o=>{let s=o?.trackId;if(!s)return;clearTimeout(kc.get(s));let a=setTimeout(()=>{kc.delete(s),Promise.resolve(e(s)).then(i=>i&&!je(i)&&i.kind!=="setup"?Lw(i):null).catch(i=>n.warn?.(`[obligations] fold ${s} failed: ${i?.message||i}`))},t);a.unref?.(),kc.set(s,a)};return Je.on("event",r),()=>{Je.off("event",r);for(let o of kc.values())clearTimeout(o);kc.clear()}}var Ed,s4,kc,Fw=G(()=>{fe();uu();Jt();Ed=new Map;Je.on("event",e=>{e?.trackId&&Ed.delete(e.trackId)});s4=750,kc=new Map});import{randomUUID as a4}from"node:crypto";async function Id(e,t,n={}){let r={operationId:a4(),kind:t,startedAt:Date.now(),...n};return _d.set(e.id,r),await M(e,{type:"track.operation.changed",actor:"orchestrator",source:"orchestrator",payload:{ts:r.startedAt,state:"started",...r}}).catch(()=>{}),r}async function Uw(e,t,n="completed",r=null){_d.get(e.id)?.operationId===t?.operationId&&_d.delete(e.id),await M(e,{type:"track.operation.changed",actor:"orchestrator",source:"orchestrator",payload:{ts:Date.now(),state:"finished",operationId:t?.operationId,kind:t?.kind,outcome:n,...r?{error:String(r)}:{}}}).catch(()=>{})}var _d,w_,Hw=G(()=>{fe();_d=new Map;w_=e=>_d.get(e)||null});var V_={};Zp(V_,{HANDOFF_LATEST_REL:()=>uo,KNOWN_AGENTS:()=>Mc,TRACK_NAME_MAX:()=>eg,addTrackRepo:()=>qd,adoptTrack:()=>Bg,agentAvailability:()=>Ld,announceNodeUpdate:()=>Gn,answerFullscreenOffer:()=>Rg,answerPrompt:()=>Ud,archiveTrack:()=>us,archiveTrackForMergedPr:()=>ur,augmentFirstPromptAfterHandoff:()=>E_,buildAgentCmd:()=>tg,canResumeSubtask:()=>K_,cancelQueued:()=>Nc,cancelQueuedToDraft:()=>lg,cancelStopJob:()=>Oa,cancelSubtask:()=>tp,changedRepos:()=>ts,commitTransferOut:()=>Zd,createSetupTrack:()=>vg,createTrack:()=>Gd,deleteTrack:()=>Ag,demoteTransferredTracks:()=>Dg,ensureLeadEpochs:()=>is,forceMergeSubtask:()=>Fg,getHandoffJob:()=>Ca,getReshapeJob:()=>yg,getSubtaskJob:()=>b2,getTrack:()=>ce,getTransferOutJob:()=>Ng,healDeadLead:()=>Rc,interruptLead:()=>Wd,isArchiving:()=>s2,isHandoffNoteEcho:()=>Jw,isInterruptEcho:()=>Yw,isModelSwitchEcho:()=>Xw,leadCliDead:()=>Eg,listSubtaskJobs:()=>ps,listTracks:()=>he,matchTranscriptsToBoxes:()=>$_,mergeNotifyMessage:()=>U_,navigatePrompt:()=>ig,notifyTrackForMergedPr:()=>dr,notifyTrackForResolvedPr:()=>zd,offerFollowupsForMergedPr:()=>ds,pendingOffers:()=>sg,queueGauges:()=>cg,queueShipCompleteNotify:()=>dg,queuedMessages:()=>as,rawTrack:()=>og,reapArchivedOrphans:()=>$g,reconcileDemotedTracks:()=>Ig,reconcileHandoffOutcome:()=>H_,reconcileInterruptedHandoffs:()=>Mg,reconcileInterruptedReshapes:()=>kg,reconcileInterruptedSubtasks:()=>jg,reconcileNodeUpdateNotices:()=>rg,reconcileSubtaskOutcome:()=>q_,refreshStandingInstructions:()=>xg,refuseIfTransferred:()=>Xd,rehydrateLead:()=>Pc,removeTrackRepo:()=>Kd,renameTrack:()=>_g,reposOf:()=>Nt,reshapeTrack:()=>bg,resolveTrackBox:()=>rc,resolveTrackBoxByHookToken:()=>Cc,restartLead:()=>Jd,resumeAgentCmd:()=>jd,sayToLead:()=>Ft,sendOptionsForAgent:()=>$n,setTrackDraft:()=>mg,setTrackModel:()=>hg,startLeadHandoff:()=>Yd,startSpinUpView:()=>pg,startSubtask:()=>Lg,startTransferOut:()=>Pg,stopJobActive:()=>M_,subtaskMessages:()=>ag,trackMessages:()=>Fd,unarchiveTrack:()=>Vd});import V from"node:fs/promises";import z from"node:path";import{randomUUID as Pd}from"node:crypto";import{execFile as i4}from"node:child_process";import{promisify as c4}from"node:util";function tg(e,{skipPermissions:t=!0,model:n=null}={}){let r=Bd[e];if(!r)throw new Error(`unknown agent "${e}"`);let o=process.env[r.envVar];if(o)return o;let s=t&&r.skipFlag?`${r.base} ${r.skipFlag}`:r.base;if(n&&n!=="default"){let a=nh(e).find(i=>i.alias===n);if(!a)throw new Error(`unknown ${e} launch model "${n}"`);s+=` --model ${a.alias}`}return s}function jd(e,t,{skipPermissions:n=!0,cwd:r=null,peerName:o=null}={}){let s=Bd[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&&!an(r,t)){let c=o&&De(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 ls(e){let t=Bd[e];if(t)return process.env[t.envVar]||t.base}async function Ld({maxAgeMs:e=6e4}={}){if(lo.value&&Date.now()-lo.at<e)return lo.value;let t=lo.value,n=await Promise.all(Mc.map(async r=>{let o=await ql(ls(r),{retries:[]});return o===Bs?[r,t?.[r]??!0]:[r,o===Wl]}));return lo.value=Object.fromEntries(n),lo.at=Date.now(),lo.value}async function Ra(e,t=!0,n=null){let r=tg(e,{skipPermissions:t,model:n});if(await ql(r)===Ds){lo.at=0;let o=r.split(/\s+/)[0],s=process.env.FLY_APP_NAME?"This Fly node's image predates CLI parity \u2014 update the node image (Links page \u2192 Fly card \u2192 Update) or re-provision.":If[o]?`Install it on this node: ${If[o]}`:"Its CLI must be installed and on PATH first.";throw new Error(`agent "${e}" isn't available on this box (command not found: ${o}). ${s}`)}return r}function E_(e,t=uo){return`${e.trim()}
211
211
 
212
- (Read ${t} for handoff context from the prior lead \u2014 you are now the lead; none of the prior chat is in your context. Then respond to the user above.)`}function Nw(e){return e.role==="user"&&VU.test((e.text||"").trim())}async function Q(){return Xt||(Ew||=(async()=>{try{Xt=JSON.parse(await ee.readFile(l_,"utf8"))}catch{Xt={tracks:[]}}finally{Ew=null}return Xt})(),Ew)}async function ce(){await Et(l_,Xt)}function XU(e,t){let n=JSON.stringify({trackId:e,...t})+`
213
- `;return _w=_w.then(()=>ee.mkdir(Hn,{recursive:!0})).then(()=>ee.appendFile(GU,n)).catch(()=>{}),_w}async function qn({current:e,latest:t,min:n=null,installKind:r=null,required:o=!1,status:s="available",policy:a=null,error:i=null,reason:c=null}={}){if(!t)return{announced:0};if(s==="available"){let d=null;try{d=JSON.parse(await ee.readFile(Iw,"utf8"))}catch{}if(d?.latest===t&&d?.current===e)return{announced:0,deduped:!0}}let l=await Q(),u=0;for(let d of l.tracks)De(d)||!d.leadBox||($e(d,"node-update",{status:s,current:e??null,latest:t,...n?{min:n}:{},...r?{installKind:r}:{},...a?{policy:a}:{},...i?{error:String(i).slice(0,400)}:{},...c?{reason:c}:{},required:o===!0}),u++);if(await ce().catch(()=>{}),s==="available")try{await ee.mkdir(oe.dirname(Iw),{recursive:!0}),await ee.writeFile(Iw,JSON.stringify({current:e,latest:t,at:Date.now()}))}catch{}return{announced:u}}async function qw({current:e,installKind:t=null,policy:n=null}={}){if(!e)return{reconciled:!1,announced:0,targets:[]};let r=await Q(),o=0,s=new Set;for(let a of r.tracks){if(a.archivedAt||a.transferredTo||!a.leadBox)continue;let i=new Map;for(let c of a.events||[])c.type==="node-update"&&c.latest&&i.set(c.latest,c);for(let[c,l]of i)["done","failed","rolled-back"].includes(l.status)||ZU(e,c)||($e(a,"node-update",{status:"done",current:l.current??null,latest:c,...t?{installKind:t}:{},...n?{policy:n}:{},reason:"version-reconciled",installed:e,required:!1}),o++,s.add(c))}return o&&await ce().catch(()=>{}),{reconciled:o>0,announced:o,targets:[...s]}}function ZU(e,t){let n=String(e).split(".").map(Number),r=String(t).split(".").map(Number);if(n.some(Number.isNaN)||r.some(Number.isNaN))return!0;for(let o=0;o<Math.max(n.length,r.length);o++){let s=(n[o]||0)-(r[o]||0);if(s)return s<0}return!1}function p_(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=>QU.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 f_(e,t,n,{kind:r}={}){let o=await ke(t);if(!o)throw new Error(`box "${t}" is not running`);let s=Sa(o.agent),a=Qi({text:n,producer:Zi({kind:r,orchestration:!0}),kind:r||"orchestration",provider:o.agent}),i=he(await Q(),e)||null,c=Date.now(),l=null;try{l=await Cr({cwd:o.cwd,sessionId:o.sessionId,sessionName:t,agent:o.agent,agentCmd:s})}catch(g){throw tc(a,{ms:Date.now()-c,outcome:g?.code==="cli-not-running"?"cli-not-running":"blocked"}),await Nn(i,a,aa(g)),g}tc(a,{ms:Date.now()-c,outcome:l||"up"});let u=En(o.agent,n);a.paste=!!u.paste;try{await ot(t,n,{...u,kind:r||"orchestration"})}catch(g){throw await Nn(i,a,aa(g)),g}let d={},p=await Ti({sessionName:t,agent:o.agent,agentCmd:s,text:n,trackId:e,flow:"orchestration",stats:d});a.verify=d,await Nn(i,a,p?d.verdict==="unverified"?"unverified":"delivered":"unsubmitted"),await ie({flow:"orchestration",phase:"sent",submitted:p,trackId:e,sessionName:t,agent:o.agent,kind:r||"orchestration",promptHead:n.slice(0,160)});let f=await Q(),w=he(f,e);if(!w)return;let m=w.boxes.find(g=>g.name===t);$e(w,"orchestration-prompt",{box:t,agent:m?.agent||o.agent,boxRole:m?.role,prompt:n,kind:r||"orchestration",deliveryId:a.id}),await ce()}async function e4(e){let t=oe.join(bs(e),`${e.id}.ndjson`),n;try{n=await ee.stat(t)}catch{return null}let r=t_.get(e.id);if(r&&r.mtimeMs===n.mtimeMs)return r.at;let o=null;for(let s of await K(e)){if(s.type!=="turn.agent")continue;let a=s.payload?.ts??s.ts;a&&(!o||a>o)&&(o=a)}return t_.set(e.id,{mtimeMs:n.mtimeMs,at:o}),o}async function t4(e,t){let n=t.find(r=>r.name===e.leadBox);return n?.state!=="live"?{working:!1,prompted:!1}:oh(n.name,n.agent)}async function Nt(e,t=null,n=null){let r=t??new Map((await nn()).map(b=>[b.name,b])),o=!!e.transferredTo,s=e.boxes.map(b=>{let O=o?null:r.get(b.name),$=so.has(b.state)?b.state:O?b.role==="lead"?"live":b.state:"stopped";return{...b,state:$,cwd:O?.cwd||b.cwd,agent:O?.agent||b.agent,sessionId:O?.sessionId||b.sessionId}}),[a,{working:i,prompted:c},l,u]=await Promise.all([e4(e),t4(e,s),vw(e),n??un().catch(()=>[])]),d=vc.has(e.id),p=(u||[]).filter(b=>b.trackId===e.id&&!["merged","closed","lost"].includes(b.state)),f=e_(e.id),w=f&&{status:"waiting",since:f.startedAt,summary:f.summary??null,count:f.count??null}||JE(p),m=s.find(b=>b.name===e.leadBox)?.state==="live",g=m?Xo(e.id).filter(b=>b.kind!=="ship-notify"&&b.kind!=="prompt-answer"):[],y=m&&l.runningJobs?{source:"jobs",count:l.runningJobs,since:l.runningJobsSince,summary:l.runningJobs===1?"a background job is still running":`${l.runningJobs} background jobs are still running`}:g.length?{source:"queue",count:g.length,since:Math.min(...g.map(b=>b.ts||Date.now())),summary:"a queued message is about to send"}:null,x=XE({archivedAt:e.archivedAt,archiving:d,prompted:c,openActions:l.openActions,openActionSince:l.openActionSince,prDecisions:YE(p),operation:w,phase:l.phase,working:i,workingSince:l.currentTurnAt,pending:y,completedTurnAt:l.completedTurnAt||a,live:m});return{...e,boxes:s,lastResponseAt:a,working:i,prompted:c,archiving:d,status:x}}function m_(e,t,n){let r=[...e].sort((l,u)=>l.createdAt-u.createdAt),o=[...t].sort((l,u)=>l.birthMs-u.birthMs),s=new Set,a=[];for(let l of r)l.sessionId&&n(l.sessionId)&&!s.has(l.sessionId)?s.add(l.sessionId):a.push(l);let i=new Map(r.map((l,u)=>[l,u])),c=[];for(let l of a){if(l.sessionId&&n(l.sessionId)){c.push({box:l.name,sessionId:null});continue}if(!l.sessionId||l.pinned)continue;let u=i.get(l),d=l.createdAt-n4,p=r[u+1]?.createdAt??1/0,f=o.find(w=>!s.has(w.id)&&w.birthMs>=d&&w.birthMs<p);f&&(s.add(f.id),c.push({box:l.name,sessionId:f.id}))}return c}async function h_(e){let t=new Map;for(let r of e.tracks)for(let o of r.boxes)o.agent==="claude"&&o.cwd&&(t.has(o.cwd)||t.set(o.cwd,[]),t.get(o.cwd).push({track:r,box:o}));let n=!1;for(let[r,o]of t){let s=o.map(p=>p.box.sessionId),a=Nk(r),i=new Set(a.map(p=>p.id)),c=s.every(p=>p&&i.has(p)),l=new Set(s).size===s.length;if(c&&l)continue;let u=o.map(p=>p.box),d=m_(u,a,p=>i.has(p));for(let p of d){let f=u.find(w=>w.name===p.box);f&&(f.sessionId=p.sessionId),await Sk(p.box,p.sessionId),n=!0}}return n}async function we(){let e=await Q();await h_(e)&&await ce();let t=new Map((await nn()).map(r=>[r.name,r])),n=await un().catch(()=>[]);return Promise.all(e.tracks.map(r=>Nt(r,t,n)))}async function Xi(e,t){let n=await Q();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 _c(e){let t=Ha(e);if(!t)return null;let n=await Q();for(let r of n.tracks||[])for(let o of r.boxes||[])if(o.hookTokenHash&&db(o.hookTokenHash,t))return{track:r,box:o};return null}async function Ww(e){return he(await Q(),e)??null}async function se(e){let t=await Q(),n=he(t,e);return n?(await h_(t)&&await ce(),Nt(n)):null}async function Kw(e){let t=await K(e).catch(()=>[]),n;try{n=_n(t)}catch{return[]}let r=ou(n).map(s=>({kind:s.kind,id:s.offerId??s.proposalId??s.id,ts:s.ts??null})),o=[];try{o=J0(t)}catch{o=[]}return r.concat(o.map(s=>({kind:"pr-open",id:`${s.repo??""}#${s.number}`,ts:null})))}function Pw(e){if(e.role!=="user")return!1;let t=(e.text||"").trim();return(r4[e.agent]||[]).some(n=>n.test(t))}function Dw(e){let t=(e.text||"").trim();return t?o4.some(n=>n.test(t)):!1}async function Id(e,t={}){let n=await se(e);if(!n)return null;let r=new Set([...n.events.filter(R=>R.type==="orchestration-prompt"&&R.prompt).map(R=>String(R.prompt).trim()),...n.events.filter(R=>R.type==="said"&&R.text).map(R=>String(R.text).trim())]),o=Ta(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=Gh(n.id),c=!!(i&&!i.finishedAt),l=c&&i.startedAt&&i.box?[{box:i.box,from:i.startedAt,to:Date.now()+1e12}]:[],u=[...MA(n),...l],p={windows:[...yx(n),...bx(n,cu),...a,...u]},w=(await Promise.all(n.boxes.map(R=>gm(R,t)))).flat(),m=w.map(R=>{let D={kind:"message",...R};if(D.role==="assistant"&&(D.text||"").trim()&&D.tools?.length){let ue=Ur(D.agent).cliTools,Le=D.tools.filter(Me=>!ue.has(Me));return{...D,tools:Le.length?Le:void 0}}return D}).map(R=>{if(R.role!=="user")return R;let D=B0(R);return D?D.kind==="suppress"?null:{...R,note:D,text:L0(D)}:R}).filter(Boolean).filter(R=>!(R.role==="user"&&r.has((R.text||"").trim()))).filter(R=>!Pw(R)).filter(R=>!Dw(R)).filter(R=>!Nw(R)).filter(R=>!hw(R)).filter(R=>R.role!=="assistant"||!!(R.text||"").trim()||!!R.images?.length).filter(R=>!kx(R,p)),g=m.filter(R=>R.failed&&R.text===_o);if(g.length){let R=new Map;for(let D of g){if(!R.has(D.box)){let Me=[...(await Be(D.box,{lines:Ze}).catch(()=>"")).matchAll(/^\s*■\s+(.+?)\s*$/gm)].map(Ht=>Ht[1]);R.set(D.box,Me.length?Me[Me.length-1]:null)}let ue=R.get(D.box);ue&&(D.text=`\u25A0 ${ue}`)}}let y=await Promise.all(n.boxes.map(R=>nv(R,t)));await aA(n,y.flat());let{agentTurnBoxes:x}=await oA(n,m);for(let R of n.boxes)x.has(R.name)&&R.cwd&&_l(R.cwd);await Yv(n),await LA(n,m).catch(()=>{});for(let R of n.boxes)R.agent==="codex"&&R.state==="live"&&await cA(n,R),R.agent==="cursor"&&R.state==="live"&&await fA(n,R);let b=await Promise.all(n.boxes.map(R=>tv(R,t)));await sA(n,b.flat().filter(R=>!$w(R.box,R.ts,u)));let O=await K(n),$=c&&i.viewId?i.viewId:null,C=lS(O),L=_n(O).filter(R=>!(R.kind==="message"&&(Pw(R)||Dw(R)||Nw(R)||hw(R)))&&!(R.kind==="view-card"&&$&&R.viewId===$)),q=uS(L,C),I=L.filter(R=>!(R.kind==="message"&&R.role==="assistant"&&!q.has(R)&&$w(R.box,R.ts,C))),_=Qf(O,I).map(R=>({kind:"command-batch",id:R.id,ts:R.pending?R.ts:(R.anchorTs??R.ts)-1,anchorTs:R.anchorTs,anchorBox:R.anchorBox,agent:R.agent,boxRole:R.boxRole,commands:R.commands,pending:R.pending})).filter(R=>!$w(R.anchorBox,R.anchorTs??R.ts,u)),F=z0(V0([...I,..._].filter(R=>R.ts!=null).sort((R,D)=>R.ts-D.ts))),V=a4(n),A=V.size?F.filter(R=>R.kind==="event"||!V.has(R.box??R.anchorBox)):F,E=n.boxes.find(R=>R.name===n.leadBox)||null,N=E?await di(E.cwd,E.sessionId,{fallbackNewest:!1}):null;if(!N&&E){let R=[...O].reverse().find(D=>D.type==="context.usage"&&D.boxId===E.name);R?.payload?.window&&(N={pct:R.payload.pct??(R.payload.occupancy!=null?R.payload.occupancy/R.payload.window:null),occupancy:R.payload.occupancy??null,window:R.payload.window,windowKnown:!0,model:R.payload.model||null})}let H=[...w].reverse().find(R=>R.role==="assistant"&&R.model),z=H?.model||null,fe=[...n.events||[]].reverse().find(R=>R.type==="model-change"),me=N?.model||z;fe&&(!H?.ts||fe.at>=H.ts)&&(me=fe.to);let Se=E?await Be(E.name,{lines:Ze}).catch(()=>""):"",Ae=E&&Wr(E.agent,Se)?await on(E.name).catch(()=>Se):Se,W=E?$n(E,Ae):null;if(W&&E){let R=hu(E,W,Ae);if(R){let D=gv(E.name,W.promptId);D.action!=="give-up"&&(D.action==="send"&&(We(E.name,R.keys,{kind:"auto-reject"}).catch(()=>{}),D.first&&M(n,{type:"prompt.autoRejected",actor:"system",source:"pane",boxId:E.name,provider:E.agent,payload:{ts:Date.now(),promptId:W.promptId,rule:R.id}}).catch(()=>{})),W=null)}}!W&&E&&!Cs(E.agent,Se)&&!Xo(n.id).length&&(W=Yf(A,{leadBoxId:E.name,provider:E.agent,isAnswered:R=>O.some(D=>D.type==="prompt.answered"&&D.payload?.promptId===R)})),W&&Xv(n,E,W);let te=A.filter(R=>!(R.kind==="message"&&R.role==="assistant"&&R.ask&&!String(R.text||"").trim()&&!R.images?.length)),J=!!E&&qu(E.name,E.agent,Se)&&!W;E&&!E.readyAt&&(J||W||Se&&Ns(E.agent,Se))&&(E.readyAt=Date.now(),await ce());let ye=!!E&&!E.readyAt&&Date.now()-(n.createdAt||0)<s4;if(n.kind==="setup"&&n.setup?.provider&&!n.setup.connectedAt&&E&&Ns(E.agent,Se)&&!W){let R=await Q(),D=he(R,n.id);D?.setup&&!D.setup.connectedAt&&(D.setup.connectedAt=Date.now(),n.setup.connectedAt=D.setup.connectedAt,await M(D,{type:"provider.connected",actor:"system",source:"pane",boxId:E.name,provider:E.agent,payload:{provider:E.agent,ts:D.setup.connectedAt}}).catch(()=>{}),await ce())}let Ce=s?{running:!0,step:o.step,toAgent:o.toAgent||null}:null,Ne=null;if(c){let R=Date.now()-i.startedAt;if(i.viewId&&!J){let D=ld(n.id);D&&($e(n,"view-spinup",{box:i.box,startedAt:i.startedAt,endedAt:D.finishedAt}),await ce())}else if(W||R>RA&&!J&&!i.viewId||R>Kh){let D=W?"needs-input":R>Kh?"timeout":"no-view";ld(n.id,{error:D})&&await M(n,{type:"view.spinup.failed",actor:"orchestrator",source:"orchestrator",boxId:i.box,provider:E?.agent||null,payload:{ts:i.startedAt,name:i.name,reason:D}}).catch(()=>{})}else Ne={running:!0,step:i.step,name:i.name}}return{trackId:n.id,leadBox:n.leadBox,items:te,context:N?{pct:N.pct,occupancy:N.occupancy,window:N.window,windowKnown:N.windowKnown,model:N.model}:null,models:{current:me,options:qv(E?.agent)},pendingPrompt:W,working:J,stopping:g_(n.id),leadStarting:ye,handoff:Ce,view:Ne,queued:Xo(n.id).filter(R=>R.kind!=="ship-notify"&&R.kind!=="prompt-answer"),draft:n.draft||null,draftRev:n.draftRev||0}}function a4(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 Gw(e,t){let n=await se(e);if(!n)return null;let r=es(e).find(d=>d.id===t)||null;if(!r)return null;let o=r.box||null;if(!o)return{items:[],working:!1,box:null,agent:r.agent,task:r.task};let s=await K(n),a=_n(s).filter(d=>d.box===o&&!(d.kind==="message"&&d.role==="assistant"&&d.ask&&!String(d.text||"").trim()&&!d.images?.length)),i=Qf(s.filter(d=>d.boxId===o),a.filter(d=>d.kind==="message")).map(d=>({kind:"command-batch",id:d.id,ts:d.pending?d.ts:(d.anchorTs??d.ts)-1,anchorTs:d.anchorTs,anchorBox:d.anchorBox,agent:d.agent,boxRole:d.boxRole,commands:d.commands,pending:d.pending})),c=[...a,...i].filter(d=>d.ts!=null).sort((d,p)=>d.ts-p.ts),l=n.boxes.find(d=>d.name===o)||null,u=!1;if(l&&l.state==="live"){let d=await Be(o,{lines:Ze}).catch(()=>"");u=qu(o,l.agent||r.agent,d)}return{items:c,working:u,box:o,agent:r.agent,task:r.task}}function i4(e,t){if(e==null)return[];if(!Array.isArray(e))throw new Error("custom answer must be a list of strings");return e.slice(0,Math.max(1,t)).map(n=>{if(n==null||n==="")return"";if(typeof n!="string")throw new Error("custom answer must be text");let r=n.replace(/\s+/g," ").trim();if(/[\x00-\x1f\x7f]/.test(r))throw new Error("custom answer can't contain control characters");if(r.length>n_)throw new Error(`custom answer is too long (max ${n_} characters)`);return r})}function c4(e,t){let n=String(e||"").replace(/\s+/g," ").trim(),r=String(t||"").replace(/\s+/g," ").trim();return!n||!r?!1:n===r||r.startsWith(n)||n.startsWith(r.slice(0,24))}async function $d(e,t={}){let n=hc.get(e);n&&await n.catch(()=>{});let r=l4(e,t);hc.set(e,r);try{return await r}finally{hc.get(e)===r&&hc.delete(e)}}async function l4(e,{promptId:t,answers:n,text:r,custom:o}={}){let s=he(await Q(),e);if(!s)throw new Error(`track "${e}" not found`);$c(e,"prompt-answer");let a=s.boxes.find(y=>y.name===s.leadBox);if(!a)throw new Error(`track "${e}" has no lead box`);if(!await ke(s.leadBox))throw new Error(`lead box "${s.leadBox}" is not running`);let c=await Am(a);if(c||(c=await u4(s,a)),!c)throw new Error("no pending prompt to answer");if(t&&t!==c.promptId)throw new Error("prompt changed since it was shown \u2014 reload and answer the current prompt");let l=i4(o,c.questions?.length??1);if(l.some(Boolean)&&!c.custom)throw new Error("custom answer isn't available for this prompt \u2014 pick one of its options");let u=(n||[]).some(y=>Array.isArray(y)&&y.length>0);if(c.custom&&!u&&!l.some(Boolean)&&c.answerMode!=="text")throw new Error("no answer selected \u2014 pick an option or type your own");l.some(Boolean)&&(n=(c.questions||[]).map((y,x)=>l[x]&&!y.multiSelect?[]:Array.isArray(n?.[x])?n[x]:[]));let d;if(c.answerMode==="text"){let y=typeof r=="string"?r.trim():"";if(!y)throw new Error("this prompt needs a code \u2014 paste it into the card");if(/\s/.test(y)||y.length>2048)throw new Error("that doesn't look like a sign-in code \u2014 paste the code exactly as shown");await ot(s.leadBox,y,{enter:!0,kind:"answer-prompt"}),d={mode:"text-input",value:"\u2039code\u203A",count:1,redacted:!0}}else if(c.answerMode==="esc")await We(s.leadBox,["Escape"],{kind:"answer-prompt"}),d={mode:"keys",value:"Escape",count:1};else if(c.answerMode==="say"){let y=q0(c,n||[],typeof r=="string"?r:"",l);if(!y)throw new Error("no answer selected \u2014 pick an option or reply in chat");await Dt(s.id,y,{kind:"prompt-answer"}),d={mode:"say",value:y,count:1}}else if(l[0]&&c.provider==="claude"){let y=fv(c,n||[],l[0]);await mf(s.leadBox,[...y.pre,{text:y.text}],{kind:"answer-prompt"});let x=!1;for(let O of[150,300,600]){await br(O);let $=await on(s.leadBox).catch(()=>""),C=$n(a,$);if(C?.customText&&c4(C.customText,y.text)){x=!0;break}}if(!x)throw new Error("custom answer didn't take \u2014 the widget moved; reload and answer again");await mf(s.leadBox,y.post,{kind:"answer-prompt"});let b=O=>O.map($=>$.key).join(" ");d={mode:"keys+text",value:`${b(y.pre)} \u2039text\u203A ${b(y.post)}`.trim(),count:y.pre.length+1+y.post.length}}else if(c.provider==="claude"||c.answerMode==="keys"){let y=Em(c,n||[]);await We(s.leadBox,y,{kind:"answer-prompt"}),d={mode:"keys",value:y.join(" "),count:y.length}}else{let y=c0(c,n||[]);await ot(s.leadBox,y,{enter:!0,kind:"answer-prompt"}),d={mode:"text",value:y,count:1}}if(c.answerMode==="say"){let y=c.questions||[];for(let x=0;x<y.length;x++){let b=y[x],O=new Set(Array.isArray(n?.[x])?n[x]:[]),$=[...O].map(L=>b.options?.[L]).filter(Boolean).map(L=>({label:L.label,description:L.description||""}));l[x]&&$.push({label:l[x],description:"",custom:!0});let C=(b.options||[]).map((L,q)=>O.has(q)?null:L?.label).filter(Boolean);Um(s,a,c,{...d,groupId:c.groupId||c.promptId,questionIndex:x,questionTotal:c.questionTotal??y.length,header:b.header||"",question:b.question||"",multiSelect:!!b.multiSelect,chosen:$,rejected:C})}return await ie({flow:"prompt",phase:"answered",sessionName:s.leadBox,agent:a.agent,provider:c.provider,promptId:c.promptId,...d}).catch(()=>{}),{ok:!0,promptId:c.promptId,sent:d.count}}let p=c.questions?.[0]||{},f=new Set(Array.isArray(n?.[0])?n[0]:[]),w=[...f].map(y=>p.options?.[y]).filter(Boolean).map(y=>({label:y.label,description:y.description||""}));l[0]&&w.push({label:l[0],description:"",custom:!0});let m=(p.options||[]).map((y,x)=>f.has(x)?null:y?.label).filter(Boolean),g=c.review?"review":/^claude:model-confirm:/.test(c.promptId||"")?"model-confirm":/^claude:resume-confirm:/.test(c.promptId||"")?"resume-confirm":void 0;return d={...d,groupId:c.groupId||c.promptId,questionIndex:c.questionIndex??0,questionTotal:c.questionTotal??1,header:p.header||"",question:p.question||"",multiSelect:!!p.multiSelect,chosen:w,rejected:m,...g?{control:g}:{}},await ie({flow:"prompt",phase:"answered",sessionName:s.leadBox,agent:a.agent,provider:c.provider,promptId:c.promptId,...d}).catch(()=>{}),Um(s,a,c,d),{ok:!0,promptId:c.promptId,sent:d.count}}async function u4(e,t){if(!t)return null;let n=await K(e).catch(()=>[]);return Yf(_n(n),{leadBoxId:t.name,provider:t.agent,isAnswered:r=>n.some(o=>o.type==="prompt.answered"&&o.payload?.promptId===r)})}async function zw(e,{promptId:t,questionIndex:n}={}){let r=he(await Q(),e);if(!r)throw new Error(`track "${e}" not found`);let o=r.boxes.find(l=>l.name===r.leadBox);if(!o)throw new Error(`track "${e}" has no lead box`);if(!await ke(r.leadBox))throw new Error(`lead box "${r.leadBox}" is not running`);let a=await Am(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=mv(a,n);return c.length?(await We(r.leadBox,c,{kind:"navigate-prompt"}),await ie({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 Rd(e){let t=ya.get(e);return t||(t={items:[],timer:null,flushing:!1,idleSince:null},ya.set(e,t)),t}function Xo(e){return(ya.get(e)?.items??[]).map(({delivery:t,...n})=>({...n}))}function Vw(e=Date.now()){let t=0,n=0;for(let r of ya.values())for(let o of r.items){t+=1;let s=e-(o.delivery?.queuedAt??o.ts??e);s>n&&(n=s)}return{queueDepth:t,queueOldestAgeMs:n}}function p4(e,t,n){let r=t.filter(o=>o.delivery&&!o.delivery.settled);r.length&&(async()=>{let o=he(await Q(),e)||null;for(let s of r)await Nn(o,s.delivery,`dropped:${n}`)})().catch(()=>{})}function Ic(e,t="cancel"){let n=ya.get(e);if(!n)return[];let r=n.items.splice(0);return n.idleSince=null,n.timer&&(clearInterval(n.timer),n.timer=null),p4(e,r,t),r}async function Jw(e){let t=Ic(e),n=t.filter(o=>o.text&&!o.kind).map(o=>o.text),r=null;if(n.length){let o=he(await Q(),e);if(o)return r=ba(o,n),await ce(),{removed:t,restored:r,draftRev:o.draftRev||0}}return{removed:t,restored:r,draftRev:null}}function Yw(e){let t=Rd(e);t.timer||(t.timer=setInterval(()=>f4(e).catch(()=>{}),d4))}async function f4(e){let t=ya.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=he(await Q(),e);if(!n||n.archivedAt){Ic(e,"archived");return}let r=l=>{for(let u of t.items)xA(u.delivery,l)},o=Ta(e);if(o&&!o.finishedAt&&o.step!=="done"&&!o.error){Jo(t,!1),r("handoff");return}let s=await ke(n.leadBox),a=n.boxes.find(l=>l.name===n.leadBox);if(s&&await lg(s)&&(s=await Sc(n,a,"queue")?await ke(n.leadBox):null,await ce()),!s){Jo(t,!1),r("noSession");return}if(Po(a?.agent)){Jo(t,!1),r("cap");return}let i=await Be(n.leadBox,{lines:Ze}).catch(()=>"");if(gi(a?.agent,i)){Jo(t,!1),r("busy");return}if(Wr(a?.agent,i)){let l=await on(n.leadBox).catch(()=>i);if($n(a,l)){Jo(t,!1),r("prompt");return}}if(!Jo(t,!0)){r("grace");return}let c=t.items.shift();t.idleSince=null,c.delivery&&(c.delivery.dequeuedAt=Date.now());try{await Bw(n,a,s,c.text,c.kind??null,c.attachments??null,c.delivery??null)}catch(l){if(l?.code!=="cli-not-running")throw c.delivery&&await Nn(n,c.delivery,aa(l)),l;t.items.unshift(c),c.delivery&&(c.delivery.requeued+=1,c.delivery.dequeuedAt=null,await ec(n,c.delivery,{position:1,reason:"requeue"})),await Sc(n,a,"queue-gate")}await ce()}finally{t.flushing=!1}}}async function w_(e,t,n,r){let o=Po(t?.agent);if(!o)return;if(!r&&typeof n=="string"&&n.trim()&&(ba(e,[n]),await ce()),Cv(e.id,o))try{await M(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 m4(e,t){let n=await Be(e.leadBox,{lines:Ze}).catch(()=>"");if(!Wr(t?.agent,n))return!1;let r=await on(e.leadBox).catch(()=>n);return!!$n(t,r)}async function Bw(e,t,n,r,o=null,s=null,a=null){a||(a=Qi({text:r,producer:Zi({kind:o}),kind:o,provider:t?.agent??null,attachments:Array.isArray(s)?s.length:0})),a.provider??=t?.agent??null,await w_(e,t,r,o);let i=bc.get(e.id)||0,c=r,l=!1,u=e.pendingHandoffHydrate||null;e.pendingHandoffHydrate&&(c=d_(r,e.pendingHandoffHydrate.artifact||Yo),delete e.pendingHandoffHydrate,l=!0);let d=Array.isArray(s)?s.filter(m=>m&&m.rel):[];if(d.length){let m=UE(d.map(g=>g.rel));c=c.trim()?`${c.trim()}
212
+ (Read ${t} for handoff context from the prior lead \u2014 you are now the lead; none of the prior chat is in your context. Then respond to the user above.)`}function Jw(e){return e.role==="user"&&d4.test((e.text||"").trim())}async function Q(){return Mt||(Ww||=(async()=>{try{Mt=JSON.parse(await V.readFile(T_,"utf8"))}catch{Mt={tracks:[]}}finally{Ww=null}return Mt})(),Ww)}async function ae(){await It(T_,Mt)}function m4(e,t){let n=JSON.stringify({trackId:e,...t})+`
213
+ `;return qw=qw.then(()=>V.mkdir(Kn,{recursive:!0})).then(()=>V.appendFile(l4,n)).catch(()=>{}),qw}async function Gn({current:e,latest:t,min:n=null,installKind:r=null,required:o=!1,status:s="available",policy:a=null,error:i=null,reason:c=null}={}){if(!t)return{announced:0};if(s==="available"){let d=null;try{d=JSON.parse(await V.readFile(Kw,"utf8"))}catch{}if(d?.latest===t&&d?.current===e)return{announced:0,deduped:!0}}let l=await Q(),u=0;for(let d of l.tracks)je(d)||!d.leadBox||(Se(d,"node-update",{status:s,current:e??null,latest:t,...n?{min:n}:{},...r?{installKind:r}:{},...a?{policy:a}:{},...i?{error:String(i).slice(0,400)}:{},...c?{reason:c}:{},required:o===!0}),u++);if(await ae().catch(()=>{}),s==="available")try{await V.mkdir(z.dirname(Kw),{recursive:!0}),await V.writeFile(Kw,JSON.stringify({current:e,latest:t,at:Date.now()}))}catch{}return{announced:u}}async function rg({current:e,installKind:t=null,policy:n=null}={}){if(!e)return{reconciled:!1,announced:0,targets:[]};let r=await Q(),o=0,s=new Set;for(let a of r.tracks){if(a.archivedAt||a.transferredTo||!a.leadBox)continue;let i=new Map;for(let c of a.events||[])c.type==="node-update"&&c.latest&&i.set(c.latest,c);for(let[c,l]of i)["done","failed","rolled-back"].includes(l.status)||h4(e,c)||(Se(a,"node-update",{status:"done",current:l.current??null,latest:c,...t?{installKind:t}:{},...n?{policy:n}:{},reason:"version-reconciled",installed:e,required:!1}),o++,s.add(c))}return o&&await ae().catch(()=>{}),{reconciled:o>0,announced:o,targets:[...s]}}function h4(e,t){let n=String(e).split(".").map(Number),r=String(t).split(".").map(Number);if(n.some(Number.isNaN)||r.some(Number.isNaN))return!0;for(let o=0;o<Math.max(n.length,r.length);o++){let s=(n[o]||0)-(r[o]||0);if(s)return s<0}return!1}function __(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=>w4.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 I_(e,t,n,{kind:r}={}){let o=await be(t);if(!o)throw new Error(`box "${t}" is not running`);let s=ls(o.agent),a=sc({text:n,producer:oc({kind:r,orchestration:!0}),kind:r||"orchestration",provider:o.agent}),i=de(await Q(),e)||null,c=Date.now(),l=null;try{l=await tr({cwd:o.cwd,sessionId:o.sessionId,sessionName:t,agent:o.agent,agentCmd:s})}catch(g){throw ic(a,{ms:Date.now()-c,outcome:g?.code==="cli-not-running"?"cli-not-running":"blocked"}),await Bn(i,a,ha(g)),g}ic(a,{ms:Date.now()-c,outcome:l||"up"});let u=$n(o.agent,n);a.paste=!!u.paste;try{await ot(t,n,{...u,kind:r||"orchestration"})}catch(g){throw await Bn(i,a,ha(g)),g}let d={},p=await Oi({sessionName:t,agent:o.agent,agentCmd:s,text:n,trackId:e,flow:"orchestration",stats:d});a.verify=d,await Bn(i,a,p?d.verdict==="unverified"?"unverified":"delivered":"unsubmitted"),await ue({flow:"orchestration",phase:"sent",submitted:p,trackId:e,sessionName:t,agent:o.agent,kind:r||"orchestration",promptHead:n.slice(0,160)});let f=await Q(),w=de(f,e);if(!w)return;let m=w.boxes.find(g=>g.name===t);Se(w,"orchestration-prompt",{box:t,agent:m?.agent||o.agent,boxRole:m?.role,prompt:n,kind:r||"orchestration",deliveryId:a.id}),await ae()}async function g4(e){let t=z.join(Os(e),`${e.id}.ndjson`),n;try{n=await V.stat(t)}catch{return null}let r=g_.get(e.id);if(r&&r.mtimeMs===n.mtimeMs)return r.at;let o=null;for(let s of await K(e)){if(s.type!=="turn.agent")continue;let a=s.payload?.ts??s.ts;a&&(!o||a>o)&&(o=a)}return g_.set(e.id,{mtimeMs:n.mtimeMs,at:o}),o}async function y4(e,t){let n=t.find(r=>r.name===e.leadBox);return n?.state!=="live"?{working:!1,prompted:!1}:kh(n.name,n.agent)}async function Lt(e,t=null,n=null){let r=t??new Map((await on()).map(b=>[b.name,b])),o=!!e.transferredTo,s=e.boxes.map(b=>{let R=o?null:r.get(b.name),_=Sr.has(b.state)?b.state:R?b.role==="lead"?"live":b.state:"stopped";return{...b,state:_,cwd:R?.cwd||b.cwd,agent:R?.agent||b.agent,sessionId:R?.sessionId||b.sessionId}}),[a,{working:i,prompted:c},l,u]=await Promise.all([g4(e),y4(e,s),Lw(e),n??dn().catch(()=>[])]),d=$c.has(e.id),p=(u||[]).filter(b=>b.trackId===e.id&&!["merged","closed","lost"].includes(b.state)),f=w_(e.id),w=f&&{status:"waiting",since:f.startedAt,summary:f.summary??null,count:f.count??null}||d_(p),m=s.find(b=>b.name===e.leadBox)?.state==="live",g=m?as(e.id).filter(b=>b.kind!=="ship-notify"&&b.kind!=="prompt-answer"):[],y=m&&l.runningJobs?{source:"jobs",count:l.runningJobs,since:l.runningJobsSince,summary:l.runningJobs===1?"a background job is still running":`${l.runningJobs} background jobs are still running`}:g.length?{source:"queue",count:g.length,since:Math.min(...g.map(b=>b.ts||Date.now())),summary:"a queued message is about to send"}:null,x=f_({archivedAt:e.archivedAt,archiving:d,prompted:c,openActions:l.openActions,openActionSince:l.openActionSince,prDecisions:p_(p),operation:w,phase:l.phase,working:i,workingSince:l.currentTurnAt,pending:y,completedTurnAt:l.completedTurnAt||a,live:m});return{...e,boxes:s,lastResponseAt:a,working:i,prompted:c,archiving:d,status:x}}function $_(e,t,n){let r=[...e].sort((l,u)=>l.createdAt-u.createdAt),o=[...t].sort((l,u)=>l.birthMs-u.birthMs),s=new Set,a=[];for(let l of r)l.sessionId&&n(l.sessionId)&&!s.has(l.sessionId)?s.add(l.sessionId):a.push(l);let i=new Map(r.map((l,u)=>[l,u])),c=[];for(let l of a){if(l.sessionId&&n(l.sessionId)){c.push({box:l.name,sessionId:null});continue}if(!l.sessionId||l.pinned)continue;let u=i.get(l),d=l.createdAt-b4,p=r[u+1]?.createdAt??1/0,f=o.find(w=>!s.has(w.id)&&w.birthMs>=d&&w.birthMs<p);f&&(s.add(f.id),c.push({box:l.name,sessionId:f.id}))}return c}async function R_(e){let t=new Map;for(let r of e.tracks)for(let o of r.boxes)o.agent==="claude"&&o.cwd&&(t.has(o.cwd)||t.set(o.cwd,[]),t.get(o.cwd).push({track:r,box:o}));let n=!1;for(let[r,o]of t){let s=o.map(p=>p.box.sessionId),a=Yk(r),i=new Set(a.map(p=>p.id)),c=s.every(p=>p&&i.has(p)),l=new Set(s).size===s.length;if(c&&l)continue;let u=o.map(p=>p.box),d=$_(u,a,p=>i.has(p));for(let p of d){let f=u.find(w=>w.name===p.box);f&&(f.sessionId=p.sessionId),await Lk(p.box,p.sessionId),n=!0}}return n}async function he(){let e=await Q();await R_(e)&&await ae();let t=new Map((await on()).map(r=>[r.name,r])),n=await dn().catch(()=>[]);return Promise.all(e.tracks.map(r=>Lt(r,t,n)))}async function rc(e,t){let n=await Q();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 Cc(e){let t=To(e);if(!t)return null;let n=await Q();for(let r of n.tracks||[])for(let o of r.boxes||[])if(o.hookTokenHash&&_b(o.hookTokenHash,t))return{track:r,box:o};return null}async function og(e){return de(await Q(),e)??null}async function ce(e){let t=await Q(),n=de(t,e);return n?(await R_(t)&&await ae(),Lt(n)):null}async function sg(e){let t=await K(e).catch(()=>[]),n;try{n=Rn(t)}catch{return[]}let r=lu(n).map(s=>({kind:s.kind,id:s.offerId??s.proposalId??s.id,ts:s.ts??null})),o=[];try{o=dx(t)}catch{o=[]}return r.concat(o.map(s=>({kind:"pr-open",id:`${s.repo??""}#${s.number}`,ts:null})))}function Yw(e){if(e.role!=="user")return!1;let t=(e.text||"").trim();return(k4[e.agent]||[]).some(n=>n.test(t))}function Xw(e){let t=(e.text||"").trim();return t?x4.some(n=>n.test(t)):!1}async function Fd(e,t={}){let n=await ce(e);if(!n)return null;let r=new Set([...n.events.filter(O=>O.type==="orchestration-prompt"&&O.prompt).map(O=>String(O.prompt).trim()),...n.events.filter(O=>O.type==="said"&&O.text).map(O=>String(O.text).trim())]),o=Ca(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=cw(n.id),c=!!(i&&!i.finishedAt),l=c&&i.startedAt&&i.box?[{box:i.box,from:i.startedAt,to:Date.now()+1e12}]:[],u=[...zT(n),...l],p={windows:[...Nx(n),...Px(n,fu),...a,...u]},w=(await Promise.all(n.boxes.map(O=>Om(O,t)))).flat(),m=w.map(O=>{let D={kind:"message",...O};if(D.role==="assistant"&&(D.text||"").trim()&&D.tools?.length){let pe=Kr(D.agent).cliTools,Le=D.tools.filter(Ce=>!pe.has(Ce));return{...D,tools:Le.length?Le:void 0}}return D}).map(O=>{if(O.role!=="user")return O;let D=Q0(O);return D?D.kind==="suppress"?null:{...O,note:D,text:tx(D)}:O}).filter(Boolean).filter(O=>!(O.role==="user"&&r.has((O.text||"").trim()))).filter(O=>!Yw(O)).filter(O=>!Xw(O)).filter(O=>!Jw(O)).filter(O=>!Mw(O)).filter(O=>O.role!=="assistant"||!!(O.text||"").trim()||!!O.images?.length).filter(O=>!Dx(O,p)),g=m.filter(O=>O.failed&&O.text===Co);if(g.length){let O=new Map;for(let D of g){if(!O.has(D.box)){let Ce=[...(await Pe(D.box,{lines:Ye}).catch(()=>"")).matchAll(/^\s*■\s+(.+?)\s*$/gm)].map(Kt=>Kt[1]);O.set(D.box,Ce.length?Ce[Ce.length-1]:null)}let pe=O.get(D.box);pe&&(D.text=`\u25A0 ${pe}`)}}let y=await Promise.all(n.boxes.map(O=>bv(O,t)));await xT(n,y.flat());let{agentTurnBoxes:x}=await bT(n,m);for(let O of n.boxes)x.has(O.name)&&O.cwd&&Ol(O.cwd);await dS(n),await QT(n,m).catch(()=>{});for(let O of n.boxes)O.agent==="codex"&&O.state==="live"&&await ST(n,O),O.agent==="cursor"&&O.state==="live"&&await IT(n,O);let b=await Promise.all(n.boxes.map(O=>yv(O,t)));await kT(n,b.flat().filter(O=>!Gw(O.box,O.ts,u)));let R=await K(n),_=c&&i.viewId?i.viewId:null,C=AS(R),U=Rn(R).filter(O=>!(O.kind==="message"&&(Yw(O)||Xw(O)||Jw(O)||Mw(O)))&&!(O.kind==="view-card"&&_&&O.viewId===_)),B=TS(U,C),T=U.filter(O=>!(O.kind==="message"&&O.role==="assistant"&&!B.has(O)&&Gw(O.box,O.ts,C))),$=mm(R,T).map(O=>({kind:"command-batch",id:O.id,ts:O.pending?O.ts:(O.anchorTs??O.ts)-1,anchorTs:O.anchorTs,anchorBox:O.anchorBox,agent:O.agent,boxRole:O.boxRole,commands:O.commands,pending:O.pending})).filter(O=>!Gw(O.anchorBox,O.anchorTs??O.ts,u)),L=lx(ux([...T,...$].filter(O=>O.ts!=null).sort((O,D)=>O.ts-D.ts))),J=S4(n),A=J.size?L.filter(O=>O.kind==="event"||!J.has(O.box??O.anchorBox)):L,S=n.boxes.find(O=>O.name===n.leadBox)||null,N=S?await bi(S.cwd,S.sessionId,{fallbackNewest:!1}):null;if(!N&&S){let O=[...R].reverse().find(D=>D.type==="context.usage"&&D.boxId===S.name);O?.payload?.window&&(N={pct:O.payload.pct??(O.payload.occupancy!=null?O.payload.occupancy/O.payload.window:null),occupancy:O.payload.occupancy??null,window:O.payload.window,windowKnown:!0,model:O.payload.model||null})}let H=[...w].reverse().find(O=>O.role==="assistant"&&O.model),q=H?.model||null,re=[...n.events||[]].reverse().find(O=>O.type==="model-change"),we=N?.model||q;re&&(!H?.ts||re.at>=H.ts)&&(we=re.to);let Re=S?await Pe(S.name,{lines:Ye}).catch(()=>""):"",Ee=S&&Vr(S.agent,Re)?await sn(S.name).catch(()=>Re):Re,Z=S?Mn(S,Ee):null;if(Z&&S){let O=vu(S,Z,Ee);if(O){let D=Nv(S.name,Z.promptId);D.action!=="give-up"&&(D.action==="send"&&(qe(S.name,O.keys,{kind:"auto-reject"}).catch(()=>{}),D.first&&M(n,{type:"prompt.autoRejected",actor:"system",source:"pane",boxId:S.name,provider:S.agent,payload:{ts:Date.now(),promptId:Z.promptId,rule:O.id}}).catch(()=>{})),Z=null)}}!Z&&S&&!Ks(S.agent,Re)&&!as(n.id).length&&(Z=dm(A,{leadBoxId:S.name,provider:S.agent,isAnswered:O=>R.some(D=>D.type==="prompt.answered"&&D.payload?.promptId===O)})),Z&&pS(n,S,Z);let ye=A.filter(O=>!(O.kind==="message"&&O.role==="assistant"&&O.ask&&!String(O.text||"").trim()&&!O.images?.length)),Y=!!S&&Ju(S.name,S.agent,Re)&&!Z;S&&!S.readyAt&&(Y||Z||Re&&Po(S.agent,Re))&&(S.readyAt=Date.now(),await ae());let ie=!!S&&!S.readyAt&&Date.now()-(n.createdAt||0)<v4;if(n.kind==="setup"&&n.setup?.provider&&!n.setup.connectedAt&&S&&Po(S.agent,Re)&&!Z){let O=await Q(),D=de(O,n.id);D?.setup&&!D.setup.connectedAt&&(D.setup.connectedAt=Date.now(),n.setup.connectedAt=D.setup.connectedAt,await M(D,{type:"provider.connected",actor:"system",source:"pane",boxId:S.name,provider:S.agent,payload:{provider:S.agent,ts:D.setup.connectedAt}}).catch(()=>{}),await ae())}let ve=s?{running:!0,step:o.step,toAgent:o.toAgent||null}:null,Ne=null;if(c){let O=Date.now()-i.startedAt;if(i.viewId&&!Y){let D=hd(n.id);D&&(Se(n,"view-spinup",{box:i.box,startedAt:i.startedAt,endedAt:D.finishedAt}),await ae())}else if(Z||O>KT&&!Y&&!i.viewId||O>iw){let D=Z?"needs-input":O>iw?"timeout":"no-view";hd(n.id,{error:D})&&await M(n,{type:"view.spinup.failed",actor:"orchestrator",source:"orchestrator",boxId:i.box,provider:S?.agent||null,payload:{ts:i.startedAt,name:i.name,reason:D}}).catch(()=>{})}else Ne={running:!0,step:i.step,name:i.name}}return{trackId:n.id,leadBox:n.leadBox,items:ye,context:N?{pct:N.pct,occupancy:N.occupancy,window:N.window,windowKnown:N.windowKnown,model:N.model}:null,models:{current:we,options:nh(S?.agent)},pendingPrompt:Z,working:Y,stopping:M_(n.id),leadStarting:ie,handoff:ve,view:Ne,queued:as(n.id).filter(O=>O.kind!=="ship-notify"&&O.kind!=="prompt-answer"),draft:n.draft||null,draftRev:n.draftRev||0}}function S4(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 ag(e,t){let n=await ce(e);if(!n)return null;let r=ps(e).find(d=>d.id===t)||null;if(!r)return null;let o=r.box||null;if(!o)return{items:[],working:!1,box:null,agent:r.agent,task:r.task};let s=await K(n),a=Rn(s).filter(d=>d.box===o&&!(d.kind==="message"&&d.role==="assistant"&&d.ask&&!String(d.text||"").trim()&&!d.images?.length)),i=mm(s.filter(d=>d.boxId===o),a.filter(d=>d.kind==="message")).map(d=>({kind:"command-batch",id:d.id,ts:d.pending?d.ts:(d.anchorTs??d.ts)-1,anchorTs:d.anchorTs,anchorBox:d.anchorBox,agent:d.agent,boxRole:d.boxRole,commands:d.commands,pending:d.pending})),c=[...a,...i].filter(d=>d.ts!=null).sort((d,p)=>d.ts-p.ts),l=n.boxes.find(d=>d.name===o)||null,u=!1;if(l&&l.state==="live"){let d=await Pe(o,{lines:Ye}).catch(()=>"");u=Ju(o,l.agent||r.agent,d)}return{items:c,working:u,box:o,agent:r.agent,task:r.task}}function A4(e,t){if(e==null)return[];if(!Array.isArray(e))throw new Error("custom answer must be a list of strings");return e.slice(0,Math.max(1,t)).map(n=>{if(n==null||n==="")return"";if(typeof n!="string")throw new Error("custom answer must be text");let r=n.replace(/\s+/g," ").trim();if(/[\x00-\x1f\x7f]/.test(r))throw new Error("custom answer can't contain control characters");if(r.length>y_)throw new Error(`custom answer is too long (max ${y_} characters)`);return r})}function T4(e,t){let n=String(e||"").replace(/\s+/g," ").trim(),r=String(t||"").replace(/\s+/g," ").trim();return!n||!r?!1:n===r||r.startsWith(n)||n.startsWith(r.slice(0,24))}async function Ud(e,t={}){let n=xc.get(e);n&&await n.catch(()=>{});let r=E4(e,t);xc.set(e,r);try{return await r}finally{xc.get(e)===r&&xc.delete(e)}}async function E4(e,{promptId:t,answers:n,text:r,custom:o}={}){let s=de(await Q(),e);if(!s)throw new Error(`track "${e}" not found`);Oa(e,"prompt-answer");let a=s.boxes.find(y=>y.name===s.leadBox);if(!a)throw new Error(`track "${e}" has no lead box`);if(!await be(s.leadBox))throw new Error(`lead box "${s.leadBox}" is not running`);let c=await Lm(a);if(c||(c=await _4(s,a)),!c)throw new Error("no pending prompt to answer");if(t&&t!==c.promptId)throw new Error("prompt changed since it was shown \u2014 reload and answer the current prompt");let l=A4(o,c.questions?.length??1);if(l.some(Boolean)&&!c.custom)throw new Error("custom answer isn't available for this prompt \u2014 pick one of its options");let u=(n||[]).some(y=>Array.isArray(y)&&y.length>0);if(c.custom&&!u&&!l.some(Boolean)&&c.answerMode!=="text")throw new Error("no answer selected \u2014 pick an option or type your own");l.some(Boolean)&&(n=(c.questions||[]).map((y,x)=>l[x]&&!y.multiSelect?[]:Array.isArray(n?.[x])?n[x]:[]));let d;if(c.answerMode==="text"){let y=typeof r=="string"?r.trim():"";if(!y)throw new Error("this prompt needs a code \u2014 paste it into the card");if(/\s/.test(y)||y.length>2048)throw new Error("that doesn't look like a sign-in code \u2014 paste the code exactly as shown");await ot(s.leadBox,y,{enter:!0,kind:"answer-prompt"}),d={mode:"text-input",value:"\u2039code\u203A",count:1,redacted:!0}}else if(c.answerMode==="esc")await qe(s.leadBox,["Escape"],{kind:"answer-prompt"}),d={mode:"keys",value:"Escape",count:1};else if(c.answerMode==="say"){let y=sx(c,n||[],typeof r=="string"?r:"",l);if(!y)throw new Error("no answer selected \u2014 pick an option or reply in chat");await Ft(s.id,y,{kind:"prompt-answer"}),d={mode:"say",value:y,count:1}}else if(l[0]&&c.provider==="claude"){let y=Rv(c,n||[],l[0]);await $f(s.leadBox,[...y.pre,{text:y.text}],{kind:"answer-prompt"});let x=!1;for(let R of[150,300,600]){await Ar(R);let _=await sn(s.leadBox).catch(()=>""),C=Mn(a,_);if(C?.customText&&T4(C.customText,y.text)){x=!0;break}}if(!x)throw new Error("custom answer didn't take \u2014 the widget moved; reload and answer again");await $f(s.leadBox,y.post,{kind:"answer-prompt"});let b=R=>R.map(_=>_.key).join(" ");d={mode:"keys+text",value:`${b(y.pre)} \u2039text\u203A ${b(y.post)}`.trim(),count:y.pre.length+1+y.post.length}}else if(c.provider==="claude"||c.answerMode==="keys"){let y=Fm(c,n||[]);await qe(s.leadBox,y,{kind:"answer-prompt"}),d={mode:"keys",value:y.join(" "),count:y.length}}else{let y=A0(c,n||[]);await ot(s.leadBox,y,{enter:!0,kind:"answer-prompt"}),d={mode:"text",value:y,count:1}}if(c.answerMode==="say"){let y=c.questions||[];for(let x=0;x<y.length;x++){let b=y[x],R=new Set(Array.isArray(n?.[x])?n[x]:[]),_=[...R].map(U=>b.options?.[U]).filter(Boolean).map(U=>({label:U.label,description:U.description||""}));l[x]&&_.push({label:l[x],description:"",custom:!0});let C=(b.options||[]).map((U,B)=>R.has(B)?null:U?.label).filter(Boolean);rh(s,a,c,{...d,groupId:c.groupId||c.promptId,questionIndex:x,questionTotal:c.questionTotal??y.length,header:b.header||"",question:b.question||"",multiSelect:!!b.multiSelect,chosen:_,rejected:C})}return await ue({flow:"prompt",phase:"answered",sessionName:s.leadBox,agent:a.agent,provider:c.provider,promptId:c.promptId,...d}).catch(()=>{}),{ok:!0,promptId:c.promptId,sent:d.count}}let p=c.questions?.[0]||{},f=new Set(Array.isArray(n?.[0])?n[0]:[]),w=[...f].map(y=>p.options?.[y]).filter(Boolean).map(y=>({label:y.label,description:y.description||""}));l[0]&&w.push({label:l[0],description:"",custom:!0});let m=(p.options||[]).map((y,x)=>f.has(x)?null:y?.label).filter(Boolean),g=c.review?"review":/^claude:model-confirm:/.test(c.promptId||"")?"model-confirm":/^claude:resume-confirm:/.test(c.promptId||"")?"resume-confirm":void 0;return d={...d,groupId:c.groupId||c.promptId,questionIndex:c.questionIndex??0,questionTotal:c.questionTotal??1,header:p.header||"",question:p.question||"",multiSelect:!!p.multiSelect,chosen:w,rejected:m,...g?{control:g}:{}},await ue({flow:"prompt",phase:"answered",sessionName:s.leadBox,agent:a.agent,provider:c.provider,promptId:c.promptId,...d}).catch(()=>{}),rh(s,a,c,d),{ok:!0,promptId:c.promptId,sent:d.count}}async function _4(e,t){if(!t)return null;let n=await K(e).catch(()=>[]);return dm(Rn(n),{leadBoxId:t.name,provider:t.agent,isAnswered:r=>n.some(o=>o.type==="prompt.answered"&&o.payload?.promptId===r)})}async function ig(e,{promptId:t,questionIndex:n}={}){let r=de(await Q(),e);if(!r)throw new Error(`track "${e}" not found`);let o=r.boxes.find(l=>l.name===r.leadBox);if(!o)throw new Error(`track "${e}" has no lead box`);if(!await be(r.leadBox))throw new Error(`lead box "${r.leadBox}" is not running`);let a=await Lm(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=Ov(a,n);return c.length?(await qe(r.leadBox,c,{kind:"navigate-prompt"}),await ue({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 Hd(e){let t=_a.get(e);return t||(t={items:[],timer:null,flushing:!1,idleSince:null},_a.set(e,t)),t}function as(e){return(_a.get(e)?.items??[]).map(({delivery:t,...n})=>({...n}))}function cg(e=Date.now()){let t=0,n=0;for(let r of _a.values())for(let o of r.items){t+=1;let s=e-(o.delivery?.queuedAt??o.ts??e);s>n&&(n=s)}return{queueDepth:t,queueOldestAgeMs:n}}function $4(e,t,n){let r=t.filter(o=>o.delivery&&!o.delivery.settled);r.length&&(async()=>{let o=de(await Q(),e)||null;for(let s of r)await Bn(o,s.delivery,`dropped:${n}`)})().catch(()=>{})}function Nc(e,t="cancel"){let n=_a.get(e);if(!n)return[];let r=n.items.splice(0);return n.idleSince=null,n.timer&&(clearInterval(n.timer),n.timer=null),$4(e,r,t),r}async function lg(e){let t=Nc(e),n=t.filter(o=>o.text&&!o.kind).map(o=>o.text),r=null;if(n.length){let o=de(await Q(),e);if(o)return r=Ia(o,n),await ae(),{removed:t,restored:r,draftRev:o.draftRev||0}}return{removed:t,restored:r,draftRev:null}}function ug(e){let t=Hd(e);t.timer||(t.timer=setInterval(()=>R4(e).catch(()=>{}),I4))}async function R4(e){let t=_a.get(e);if(!(!t||t.flushing)){if(!t.items.length){t.timer&&(clearInterval(t.timer),t.timer=null);return}t.flushing=!0;try{let n=de(await Q(),e);if(!n||n.archivedAt){Nc(e,"archived");return}let r=l=>{for(let u of t.items)DT(u.delivery,l)},o=Ca(e);if(o&&!o.finishedAt&&o.step!=="done"&&!o.error){ss(t,!1),r("handoff");return}let s=await be(n.leadBox),a=n.boxes.find(l=>l.name===n.leadBox);if(s&&await Eg(s)&&(s=await Rc(n,a,"queue")?await be(n.leadBox):null,await ae()),!s){ss(t,!1),r("noSession");return}if(Jr(a?.agent)){ss(t,!1),r("cap");return}let i=await Pe(n.leadBox,{lines:Ye}).catch(()=>"");if(Ti(a?.agent,i)){ss(t,!1),r("busy");return}if(Vr(a?.agent,i)){let l=await sn(n.leadBox).catch(()=>i);if(Mn(a,l)){ss(t,!1),r("prompt");return}}if(!ss(t,!0)){r("grace");return}let c=t.items.shift();t.idleSince=null,c.delivery&&(c.delivery.dequeuedAt=Date.now());try{await Zw(n,a,s,c.text,c.kind??null,c.attachments??null,c.delivery??null)}catch(l){if(l?.code!=="cli-not-running")throw c.delivery&&await Bn(n,c.delivery,ha(l)),l;t.items.unshift(c),c.delivery&&(c.delivery.requeued+=1,c.delivery.dequeuedAt=null,await ac(n,c.delivery,{position:1,reason:"requeue"})),await Rc(n,a,"queue-gate")}await ae()}finally{t.flushing=!1}}}async function O_(e,t,n,r){let o=Jr(t?.agent);if(!o)return;if(!r&&typeof n=="string"&&n.trim()&&(Ia(e,[n]),await ae()),Jv(e.id,o))try{await M(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 O4(e,t){let n=await Pe(e.leadBox,{lines:Ye}).catch(()=>"");if(!Vr(t?.agent,n))return!1;let r=await sn(e.leadBox).catch(()=>n);return!!Mn(t,r)}async function Zw(e,t,n,r,o=null,s=null,a=null){a||(a=sc({text:r,producer:oc({kind:o}),kind:o,provider:t?.agent??null,attachments:Array.isArray(s)?s.length:0})),a.provider??=t?.agent??null,await O_(e,t,r,o);let i=Ec.get(e.id)||0,c=r,l=!1,u=e.pendingHandoffHydrate||null;e.pendingHandoffHydrate&&(c=E_(r,e.pendingHandoffHydrate.artifact||uo),delete e.pendingHandoffHydrate,l=!0);let d=Array.isArray(s)?s.filter(m=>m&&m.rel):[];if(d.length){let m=t_(d.map(g=>g.rel));c=c.trim()?`${c.trim()}
214
214
 
215
- ${m}`:m}let p=$e(e,"said",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,text:r,deliveryId:a.id,...o?{kind:o}:{},...d.length?{attachments:d}:{}});o||ga(e,null);try{let m=Date.now(),g=null;try{g=await Cr({cwd:n.cwd,sessionId:n.sessionId,sessionName:e.leadBox,agent:n.agent,agentCmd:Sa(n.agent),bailOnDialog:!0})}catch(x){throw tc(a,{ms:Date.now()-m,outcome:x?.code==="cli-not-running"?"cli-not-running":"blocked"}),x}if(tc(a,{ms:Date.now()-m,outcome:g||"up"}),(bc.get(e.id)||0)!==i){!o&&r.trim()&&(ba(e,[r]),await ce());let x=new Error("delivery stopped \u2014 the message was handed back as the draft");throw x.interrupted=!0,x}if(await m4(e,t)){let x=Rd(e.id);a.requeued+=1,a.dequeuedAt=null;let b={id:a.id,text:r,ts:Date.now(),...o?{kind:o}:{},...d.length?{attachments:d}:{},delivery:a};x.items.unshift(b),Yw(e.id),await ec(e,a,{position:1,reason:"prompt"});let O=new Error("lead is blocked on a prompt \u2014 message queued");throw O.requeued={id:b.id,position:x.items.length},O}let y=En(t?.agent,c);a.paste=!!y.paste,await ot(e.leadBox,c,{...y,kind:l?"lead-handoff-first-prompt":"say"})}catch(m){if(u&&!e.pendingHandoffHydrate&&(e.pendingHandoffHydrate=u),$e(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:p.at,text:r,...m?.interrupted?{reason:"interrupted"}:{},...m?.requeued?{reason:"requeued"}:{}}),m?.requeued)return{queued:!0,...m.requeued};throw m?.code!=="cli-not-running"&&await Nn(e,a,aa(m)),m}let f={},w=await R4(e,t,c,f);a.verify=f,w?await Nn(e,a,f.verdict==="unverified"?"unverified":"delivered"):(await y_(e.leadBox,t?.agent,c.length+8,c).catch(()=>{}),$e(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:p.at,text:r,reason:"unsubmitted"}),o||ba(e,[r]),await Nn(e,a,"unsubmitted")),l&&await ie({flow:"lead-handoff",phase:"first-prompt",trackId:e.id,sessionName:e.leadBox,agent:t?.agent,userTextLen:r.length})}function Xw(e,{actions:t}={}){let n=Rd(e),r=dS(t),o=Qi({text:r,producer:Zi({kind:"ship-notify"}),kind:"ship-notify"});n.items.push({id:o.id,text:r,ts:Date.now(),kind:"ship-notify",delivery:o}),Yw(e),(async()=>{let s=he(await Q(),e);s&&(o.provider=s.boxes.find(a=>a.name===s.leadBox)?.agent??null,await ec(s,o,{position:n.items.length,reason:"queue"}))})().catch(()=>{})}async function h4(e,t,n,r){await We(e.leadBox,["Escape"],{kind:"dismiss-prompt"});let o="",s=!1;for(let c of[250,400,600,900]){if(await br(c),o=await Be(e.leadBox,{lines:Ze}).catch(()=>""),!Wr(t?.agent,o)){s=!0;break}let l=await on(e.leadBox).catch(()=>o);if(!$n(t,l)){s=!0;break}}let a=n.questions?.[0]||{},i={groupId:n.groupId||n.promptId,questionIndex:n.questionIndex??0,questionTotal:n.questionTotal??1,header:a.header||"",question:a.question||"",multiSelect:!!a.multiSelect,options:(a.options||[]).map(c=>c?.label).filter(Boolean),via:"send",deliveryId:r?.id??null,gone:s};return ie({flow:"prompt",phase:"dismissed",sessionName:e.leadBox,agent:t?.agent,provider:n.provider,promptId:n.promptId,...i}).catch(()=>{}),s&&Zv(e,t,n,i),{gone:s,pane:o}}async function Dt(e,t,{kind:n=null,attachments:r=null,producer:o=null,dismissPrompt:s=!1}={}){let a=Array.isArray(r)?r.filter(d=>d&&typeof d.rel=="string"):[];if((typeof t!="string"||!Hs(t))&&!a.length)throw new Error("text (string) or an attachment required");let i=he(await Q(),e);if(!i)throw new Error(`track "${e}" not found`);if(i.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it before driving it`);yg(i);let c=i.boxes.find(d=>d.name===i.leadBox),l=Hs(t),u=Qi({text:l,producer:Zi({kind:n,producer:o}),kind:n,provider:c?.agent??null,attachments:a.length});try{return await w4(e,i,c,l,{kind:n,atts:a,d:u,dismissPrompt:s})}catch(d){throw await Nn(i,u,aa(d)),d}}async function w4(e,t,n,r,{kind:o,atts:s,d:a,dismissPrompt:i=!1}){await w_(t,n,r,o),$c(e,"say");let c=await ke(t.leadBox);if(c&&await lg(c)?await Sc(t,n,"say")?(await ce(),c=await ke(t.leadBox)):c=null:!c&&await Oc(t)&&(await ce(),c=await ke(t.leadBox)),!c)throw new Error(`lead box "${t.leadBox}" is not running`);let l=hc.get(e);l&&await l.catch(()=>{});let u=Rd(e),d=await Be(t.leadBox,{lines:Ze}).catch(()=>""),p=u.items.length>0?"queue":gi(n?.agent,d)?"busy":null,f=p!=null,w=i&&!o;if((!f||p==="queue"&&w)&&Wr(n?.agent,d)){let g=await on(t.leadBox).catch(()=>d),y=$n(n,g);if(f||(f=!!y,f&&(p="prompt")),y&&w&&y.dismissable){let x=await h4(t,n,y,a);x.gone&&p==="prompt"&&(d=x.pane,f=gi(n?.agent,d),p=f?"busy":null)}}if(f){let g={id:a.id,text:r,ts:Date.now(),...o?{kind:o}:{},...s.length?{attachments:s}:{},delivery:a};return u.items.push(g),Yw(e),o||ga(t,null),await ce(),await ec(t,a,{position:u.items.length,reason:p}),{ok:!0,leadBox:t.leadBox,queued:!0,id:g.id,position:u.items.length,deliveryId:a.id}}let m;try{m=await Bw(t,n,c,r,o,s,a)}catch(g){if(g?.code!=="cli-not-running"||!await Sc(t,n,"say-gate")||(await ce(),c=await ke(t.leadBox),!c))throw g;m=await Bw(t,n,c,r,o,s,a)}return await ce(),m?.queued?{ok:!0,leadBox:t.leadBox,queued:!0,id:m.id,position:m.position,deliveryId:a.id}:{ok:!0,leadBox:t.leadBox,deliveryId:a.id}}async function Zw(e,{hint:t}={}){let n=he(await Q(),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=Gh(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";OA(n.id,{name:s,box:n.leadBox});let a=String(t||"").trim()?`${r_}
215
+ ${m}`:m}let p=Se(e,"said",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,text:r,deliveryId:a.id,...o?{kind:o}:{},...d.length?{attachments:d}:{}});o||Ea(e,null);try{let m=Date.now(),g=null;try{g=await tr({cwd:n.cwd,sessionId:n.sessionId,sessionName:e.leadBox,agent:n.agent,agentCmd:ls(n.agent),bailOnDialog:!0})}catch(x){throw ic(a,{ms:Date.now()-m,outcome:x?.code==="cli-not-running"?"cli-not-running":"blocked"}),x}if(ic(a,{ms:Date.now()-m,outcome:g||"up"}),(Ec.get(e.id)||0)!==i){!o&&r.trim()&&(Ia(e,[r]),await ae());let x=new Error("delivery stopped \u2014 the message was handed back as the draft");throw x.interrupted=!0,x}if(await O4(e,t)){let x=Hd(e.id);a.requeued+=1,a.dequeuedAt=null;let b={id:a.id,text:r,ts:Date.now(),...o?{kind:o}:{},...d.length?{attachments:d}:{},delivery:a};x.items.unshift(b),ug(e.id),await ac(e,a,{position:1,reason:"prompt"});let R=new Error("lead is blocked on a prompt \u2014 message queued");throw R.requeued={id:b.id,position:x.items.length},R}let y=$n(t?.agent,c);a.paste=!!y.paste,await ot(e.leadBox,c,{...y,kind:l?"lead-handoff-first-prompt":"say"})}catch(m){if(u&&!e.pendingHandoffHydrate&&(e.pendingHandoffHydrate=u),Se(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:p.at,text:r,...m?.interrupted?{reason:"interrupted"}:{},...m?.requeued?{reason:"requeued"}:{}}),m?.requeued)return{queued:!0,...m.requeued};throw m?.code!=="cli-not-running"&&await Bn(e,a,ha(m)),m}let f={},w=await z4(e,t,c,f);a.verify=f,w?await Bn(e,a,f.verdict==="unverified"?"unverified":"delivered"):(await C_(e.leadBox,t?.agent,c.length+8,c).catch(()=>{}),Se(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:p.at,text:r,reason:"unsubmitted"}),o||Ia(e,[r]),await Bn(e,a,"unsubmitted")),l&&await ue({flow:"lead-handoff",phase:"first-prompt",trackId:e.id,sessionName:e.leadBox,agent:t?.agent,userTextLen:r.length})}function dg(e,{actions:t}={}){let n=Hd(e),r=ES(t),o=sc({text:r,producer:oc({kind:"ship-notify"}),kind:"ship-notify"});n.items.push({id:o.id,text:r,ts:Date.now(),kind:"ship-notify",delivery:o}),ug(e),(async()=>{let s=de(await Q(),e);s&&(o.provider=s.boxes.find(a=>a.name===s.leadBox)?.agent??null,await ac(s,o,{position:n.items.length,reason:"queue"}))})().catch(()=>{})}async function M4(e,t,n,r){await qe(e.leadBox,["Escape"],{kind:"dismiss-prompt"});let o="",s=!1;for(let c of[250,400,600,900]){if(await Ar(c),o=await Pe(e.leadBox,{lines:Ye}).catch(()=>""),!Vr(t?.agent,o)){s=!0;break}let l=await sn(e.leadBox).catch(()=>o);if(!Mn(t,l)){s=!0;break}}let a=n.questions?.[0]||{},i={groupId:n.groupId||n.promptId,questionIndex:n.questionIndex??0,questionTotal:n.questionTotal??1,header:a.header||"",question:a.question||"",multiSelect:!!a.multiSelect,options:(a.options||[]).map(c=>c?.label).filter(Boolean),via:"send",deliveryId:r?.id??null,gone:s};return ue({flow:"prompt",phase:"dismissed",sessionName:e.leadBox,agent:t?.agent,provider:n.provider,promptId:n.promptId,...i}).catch(()=>{}),s&&fS(e,t,n,i),{gone:s,pane:o}}async function Ft(e,t,{kind:n=null,attachments:r=null,producer:o=null,dismissPrompt:s=!1}={}){let a=Array.isArray(r)?r.filter(d=>d&&typeof d.rel=="string"):[];if((typeof t!="string"||!Qs(t))&&!a.length)throw new Error("text (string) or an attachment required");let i=de(await Q(),e);if(!i)throw new Error(`track "${e}" not found`);if(i.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it before driving it`);Xd(i);let c=i.boxes.find(d=>d.name===i.leadBox),l=Qs(t),u=sc({text:l,producer:oc({kind:n,producer:o}),kind:n,provider:c?.agent??null,attachments:a.length});try{return await C4(e,i,c,l,{kind:n,atts:a,d:u,dismissPrompt:s})}catch(d){throw await Bn(i,u,ha(d)),d}}async function C4(e,t,n,r,{kind:o,atts:s,d:a,dismissPrompt:i=!1}){await O_(t,n,r,o),Oa(e,"say");let c=await be(t.leadBox);if(c&&await Eg(c)?await Rc(t,n,"say")?(await ae(),c=await be(t.leadBox)):c=null:!c&&await Pc(t)&&(await ae(),c=await be(t.leadBox)),!c)throw new Error(`lead box "${t.leadBox}" is not running`);let l=xc.get(e);l&&await l.catch(()=>{});let u=Hd(e),d=await Pe(t.leadBox,{lines:Ye}).catch(()=>""),p=u.items.length>0?"queue":Ti(n?.agent,d)?"busy":null,f=p!=null,w=i&&!o;if((!f||p==="queue"&&w)&&Vr(n?.agent,d)){let g=await sn(t.leadBox).catch(()=>d),y=Mn(n,g);if(f||(f=!!y,f&&(p="prompt")),y&&w&&y.dismissable){let x=await M4(t,n,y,a);x.gone&&p==="prompt"&&(d=x.pane,f=Ti(n?.agent,d),p=f?"busy":null)}}if(f){let g={id:a.id,text:r,ts:Date.now(),...o?{kind:o}:{},...s.length?{attachments:s}:{},delivery:a};return u.items.push(g),ug(e),o||Ea(t,null),await ae(),await ac(t,a,{position:u.items.length,reason:p}),{ok:!0,leadBox:t.leadBox,queued:!0,id:g.id,position:u.items.length,deliveryId:a.id}}let m;try{m=await Zw(t,n,c,r,o,s,a)}catch(g){if(g?.code!=="cli-not-running"||!await Rc(t,n,"say-gate")||(await ae(),c=await be(t.leadBox),!c))throw g;m=await Zw(t,n,c,r,o,s,a)}return await ae(),m?.queued?{ok:!0,leadBox:t.leadBox,queued:!0,id:m.id,position:m.position,deliveryId:a.id}:{ok:!0,leadBox:t.leadBox,deliveryId:a.id}}async function pg(e,{hint:t}={}){let n=de(await Q(),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=cw(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";GT(n.id,{name:s,box:n.leadBox});let a=String(t||"").trim()?`${b_}
216
216
 
217
- What to preview: ${String(t).trim()}`:r_;try{await Dt(e,a,{kind:"spin-up-view"})}catch(i){throw ld(n.id,{error:"drive-failed"}),i}return{ok:!0,running:!0}}async function Od(e){let t=he(await Q(),e);if(!t)throw new Error(`track "${e}" not found`);if(t.archivedAt)throw new Error(`track "${e}" is archived`);bc.set(e,(bc.get(e)||0)+1);let n=Ic(e,"interrupt"),r=n.filter(i=>i.text&&!i.kind).map(i=>i.text),o=wa.get(e);if(o&&!o.canceled){o.clicks++;let i=null;return r.length&&(i=ba(t,r),await ce()),{ok:!0,interrupted:!0,stopped:!1,stopping:!0,dropped:n.length,restored:i,draftRev:t.draftRev||0}}let s=v4(e,{droppedCount:n.length,droppedTexts:r});await Promise.race([s.settled,br(g4)]);let a=he(await Q(),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 g_(e){let t=wa.get(e);return!!t&&!t.canceled}function $c(e,t){let n=wa.get(e);n&&!n.canceled&&(n.canceled=!0,n.cancelReason=t||null)}function Qw(e){$c(e,"track-ended"),bc.delete(e),Ic(e,"track-ended")}function v4(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}),wa.set(e,r),(async()=>{let s=he(await Q(),e),a=s?.boxes.find(g=>g.name===s.leadBox),i=s?await ke(s.leadBox):null,c=!1,l=!1;if(i){e:for(let g=0;g<y4&&!r.canceled;g++){await We(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.escSends++;for(let y of b4){await br(y);let x=await Be(s.leadBox,{lines:Ze}).catch(()=>"");if(!Cs(a?.agent,x)){c=!0;break e}}}if(!c){l=!0;for(let g=0;g<x4&&!r.canceled&&(await br(k4),!r.canceled);g++){let y=await Be(s.leadBox,{lines:Ze}).catch(()=>"");if(!Cs(a?.agent,y)){c=!0;break}await We(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.bgSends++}}}let u=he(await Q(),e)||s,d=u?.boxes.find(g=>g.name===u.leadBox)||a,p=null,f=null;u&&d&&i&&c&&!r.canceled&&(p=await E4(u,d).catch(()=>null),p||(f=await $4(u,d).catch(()=>null)));let w=u&&i&&!r.canceled?await T4(u).catch(()=>null):null,m=[p||f,...r.queuedTexts].filter(Boolean);u&&m.length&&(r.restored=ba(u,m),await ce()),r.result=i?r.canceled?"canceled":c?l?"stopped-late":"stopped":"gave-up":"no-session",await S4(u||s,d,{ts:r.startedAt,result:r.result,dropped:t,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!p,lostRestored:!!f,queuedRestored:r.queuedTexts.length,shipDismissed:!!w,durationMs:Date.now()-r.startedAt,...r.cancelReason?{cancelReason:r.cancelReason}:{}}),await ie({flow:"interrupt",phase:r.result==="gave-up"?"failed":"done",trackId:e,sessionName:u?.leadBox,agent:d?.agent,result:r.result,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!p,lostRestored:!!f,queuedRestored:r.queuedTexts.length,shipDismissed:!!w}).catch(()=>{})})().catch(()=>{}).finally(()=>{r.result||(r.result=r.canceled?"canceled":"gave-up"),wa.get(e)===r&&wa.delete(e),o()}),r}async function S4(e,t,n){await M(e,{type:"turn.interrupted",actor:"user",source:"orchestrator",boxId:e.leadBox,provider:t?.agent||null,payload:n}).catch(()=>{})}async function T4(e){let t=ca(await K(e));if(!t?.offerId)return null;let n=t.offerType==="exists";return await M(e,{type:n?"pr.exists.answered":"pr.offer.answered",actor:"user",source:"orchestrator",boxId:t.box,payload:{ts:Date.now(),offerId:t.offerId,...n?{choice:"dismiss"}:{action:"dismiss",actions:null},reason:"interrupt"}}),t.offerId}async function E4(e,t){if(t?.agent!=="claude")return null;let n=[...e.events||[]].reverse().find(r=>r.type==="said"&&r.text);if(!n)return null;for(let r of A4){await br(r);let o=await Be(e.leadBox,{lines:Ze}).catch(()=>""),s=xi(t.agent,o);if(s&&Xl(n.text,s))return await y_(e.leadBox,t.agent,n.text.length+8),$e(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:n.at,text:n.text}),n.text}return null}async function $4(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>_4||n.some(s=>s.type==="unsaid"&&s.saidTs===r.at)||!Fe(r.text))return null;for(let s of I4){await br(s);let a;try{a=await gm(t,{})}catch{return null}if(g0(a,r))return null;let i=await Be(e.leadBox,{lines:Ze}).catch(()=>"");if(xi(t.agent,i))return null}return $e(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:r.at,text:r.text,reason:"lost"}),r.text}async function R4(e,t,n,r=null){return Ti({sessionName:e.leadBox,agent:t?.agent,agentCmd:Sa(t?.agent),text:n,trackId:e.id,flow:"say",stats:r})}async function y_(e,t,n,r=null){for(let o=0;o<3;o++){await Es(e,n,{kind:"unsend-wipe"}).catch(()=>{}),await br(200);let s=await Be(e,{lines:Ze}).catch(()=>""),a=xi(t,s);if(!a||r&&!Xl(r,a)&&!(t==="codex"&&Uf(r,a)))return!0;n=a.length+8}return!1}function ga(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 ba(e,t){let n=[],r=o=>n.some(s=>Fe(s).includes(Fe(o)));for(let o of[e.draft?.text,...t])o&&o.trim()&&!r(o)&&n.push(o);return n.length?ga(e,n.join(`
217
+ What to preview: ${String(t).trim()}`:b_;try{await Ft(e,a,{kind:"spin-up-view"})}catch(i){throw hd(n.id,{error:"drive-failed"}),i}return{ok:!0,running:!0}}async function Wd(e){let t=de(await Q(),e);if(!t)throw new Error(`track "${e}" not found`);if(t.archivedAt)throw new Error(`track "${e}" is archived`);Ec.set(e,(Ec.get(e)||0)+1);let n=Nc(e,"interrupt"),r=n.filter(i=>i.text&&!i.kind).map(i=>i.text),o=Ta.get(e);if(o&&!o.canceled){o.clicks++;let i=null;return r.length&&(i=Ia(t,r),await ae()),{ok:!0,interrupted:!0,stopped:!1,stopping:!0,dropped:n.length,restored:i,draftRev:t.draftRev||0}}let s=L4(e,{droppedCount:n.length,droppedTexts:r});await Promise.race([s.settled,Ar(N4)]);let a=de(await Q(),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 M_(e){let t=Ta.get(e);return!!t&&!t.canceled}function Oa(e,t){let n=Ta.get(e);n&&!n.canceled&&(n.canceled=!0,n.cancelReason=t||null)}function fg(e){Oa(e,"track-ended"),Ec.delete(e),Nc(e,"track-ended")}function L4(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}),Ta.set(e,r),(async()=>{let s=de(await Q(),e),a=s?.boxes.find(g=>g.name===s.leadBox),i=s?await be(s.leadBox):null,c=!1,l=!1;if(i){e:for(let g=0;g<P4&&!r.canceled;g++){await qe(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.escSends++;for(let y of D4){await Ar(y);let x=await Pe(s.leadBox,{lines:Ye}).catch(()=>"");if(!Ks(a?.agent,x)){c=!0;break e}}}if(!c){l=!0;for(let g=0;g<j4&&!r.canceled&&(await Ar(B4),!r.canceled);g++){let y=await Pe(s.leadBox,{lines:Ye}).catch(()=>"");if(!Ks(a?.agent,y)){c=!0;break}await qe(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.bgSends++}}}let u=de(await Q(),e)||s,d=u?.boxes.find(g=>g.name===u.leadBox)||a,p=null,f=null;u&&d&&i&&c&&!r.canceled&&(p=await W4(u,d).catch(()=>null),p||(f=await G4(u,d).catch(()=>null)));let w=u&&i&&!r.canceled?await U4(u).catch(()=>null):null,m=[p||f,...r.queuedTexts].filter(Boolean);u&&m.length&&(r.restored=Ia(u,m),await ae()),r.result=i?r.canceled?"canceled":c?l?"stopped-late":"stopped":"gave-up":"no-session",await F4(u||s,d,{ts:r.startedAt,result:r.result,dropped:t,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!p,lostRestored:!!f,queuedRestored:r.queuedTexts.length,shipDismissed:!!w,durationMs:Date.now()-r.startedAt,...r.cancelReason?{cancelReason:r.cancelReason}:{}}),await ue({flow:"interrupt",phase:r.result==="gave-up"?"failed":"done",trackId:e,sessionName:u?.leadBox,agent:d?.agent,result:r.result,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!p,lostRestored:!!f,queuedRestored:r.queuedTexts.length,shipDismissed:!!w}).catch(()=>{})})().catch(()=>{}).finally(()=>{r.result||(r.result=r.canceled?"canceled":"gave-up"),Ta.get(e)===r&&Ta.delete(e),o()}),r}async function F4(e,t,n){await M(e,{type:"turn.interrupted",actor:"user",source:"orchestrator",boxId:e.leadBox,provider:t?.agent||null,payload:n}).catch(()=>{})}async function U4(e){let t=ga(await K(e));if(!t?.offerId)return null;let n=t.offerType==="exists";return await M(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 W4(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 H4){await Ar(r);let o=await Pe(e.leadBox,{lines:Ye}).catch(()=>""),s=Ii(t.agent,o);if(s&&nu(n.text,s))return await C_(e.leadBox,t.agent,n.text.length+8),Se(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:n.at,text:n.text}),n.text}return null}async function G4(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>q4||n.some(s=>s.type==="unsaid"&&s.saidTs===r.at)||!Fe(r.text))return null;for(let s of K4){await Ar(s);let a;try{a=await Om(t,{})}catch{return null}if(C0(a,r))return null;let i=await Pe(e.leadBox,{lines:Ye}).catch(()=>"");if(Ii(t.agent,i))return null}return Se(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:r.at,text:r.text,reason:"lost"}),r.text}async function z4(e,t,n,r=null){return Oi({sessionName:e.leadBox,agent:t?.agent,agentCmd:ls(t?.agent),text:n,trackId:e.id,flow:"say",stats:r})}async function C_(e,t,n,r=null){for(let o=0;o<3;o++){await js(e,n,{kind:"unsend-wipe"}).catch(()=>{}),await Ar(200);let s=await Pe(e,{lines:Ye}).catch(()=>""),a=Ii(t,s);if(!a||r&&!nu(r,a)&&!(t==="codex"&&nm(r,a)))return!0;n=a.length+8}return!1}function Ea(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 Ia(e,t){let n=[],r=o=>n.some(s=>Fe(s).includes(Fe(o)));for(let o of[e.draft?.text,...t])o&&o.trim()&&!r(o)&&n.push(o);return n.length?Ea(e,n.join(`
218
218
 
219
- `),{source:"restore"})?.text??null:null}function M4(e,t){let n=Fe(t);if(!n)return!1;if(Xo(e.id).some(o=>Fe(o.text)===n))return!0;let r=e.events||[];for(let o=r.length-1;o>=0;o--){let s=r[o];if(typeof s.at=="number"&&Date.now()-s.at>O4)break;if(!(s.type!=="said"||!s.text||Fe(s.text)!==n))return!r.some(a=>a.type==="unsaid"&&a.saidTs===s.at)}return!1}async function eg(e,t,{rev:n=null}={}){if(typeof t!="string")throw new Error("text (string) required");let r=he(await Q(),e);if(!r)throw new Error(`track "${e}" not found`);let o=t,s=Hs(t);if(typeof n=="number"&&n<(r.draftRev||0)&&s&&M4(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;Fe(o).includes(Fe(i))?ga(r,o):ga(r,`${i}
219
+ `),{source:"restore"})?.text??null:null}function J4(e,t){let n=Fe(t);if(!n)return!1;if(as(e.id).some(o=>Fe(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>V4)break;if(!(s.type!=="said"||!s.text||Fe(s.text)!==n))return!r.some(a=>a.type==="unsaid"&&a.saidTs===s.at)}return!1}async function mg(e,t,{rev:n=null}={}){if(typeof t!="string")throw new Error("text (string) required");let r=de(await Q(),e);if(!r)throw new Error(`track "${e}" not found`);let o=t,s=Qs(t);if(typeof n=="number"&&n<(r.draftRev||0)&&s&&J4(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;Fe(o).includes(Fe(i))?Ea(r,o):Ea(r,`${i}
220
220
 
221
- ${o}`,{source:"restore"})}else ga(r,o);return await ce(),{ok:!0,draft:r.draft||null,rev:r.draftRev||0}}async function tg(e,t){if(typeof t!="string"||!t.trim())throw new Error("model (string) required");let n=t.trim(),r=he(await Q(),e);if(!r)throw new Error(`track "${e}" not found`);let o=await ke(r.leadBox);if(!o)throw new Error(`lead box "${r.leadBox}" is not running`);let a=r.boxes.find(d=>d.name===r.leadBox)?.agent||o.agent||"claude",i=Wv(a,n),l=[...r.events||[]].reverse().find(d=>d.type==="model-change")?.to??null;l||(l=(await di(o.cwd,o.sessionId,{fallbackNewest:!1}).catch(()=>null))?.model??null),await Cr({cwd:o.cwd,sessionId:o.sessionId,sessionName:r.leadBox,agent:o.agent,agentCmd:Sa(o.agent)});let u=await Kv(a,r.leadBox,i);return $e(r,"model-change",{to:n,from:l,box:r.leadBox,agent:a,verified:!!u.verified}),await ce(),{ok:!0,requested:n,leadBox:r.leadBox,...u}}async function b_(e){for(let t of e){if(!t||!await qs(t))continue;let n=await xv(t).catch(()=>null);if(!n)continue;if((await ee.stat(oe.join(n,".git")).catch(()=>null))?.isDirectory())return n}return null}function Bt(e){let t=e;return t?t.kind==="multi"?Array.isArray(t.repos)?t.repos.filter(Boolean):[]:t.base?[{name:oe.basename(t.base),dir:t.dir??null,base:t.base,baseRef:t.baseRef??null,repo:t.repo??null}]:[]:[]}async function Ko(e){let t=[];for(let n of Bt(e?.workspace)){if(!n?.dir)continue;let r=await Oi(n.dir,{ignorePlumbing:!0}).catch(()=>!1),o=await Mi(n.dir,n.baseRef).catch(()=>0);(r||o>0)&&t.push({...n,dirty:r,ahead:o})}return t}async function k_(e){let t=e;typeof t=="string"&&!oe.isAbsolute(t)&&/^[^/\s]+\/[^/\s]+$/.test(t)&&(t=await ws(t)??await bl(t));let n=await b_([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 C4(e,t,n,r){let o=`track/${vg(t)}-${e}`,s=[];try{await ee.mkdir(n,{recursive:!0});let a=new Set([".bostrat"]);for(let i of r){let c=await k_(i);if(s.some(f=>f.base===c))throw new Error(`repo tagged twice: ${i}`);let l=await _e(c).catch(()=>null),u=oe.basename(c);a.has(u)&&l&&(u=l.replace("/","-"));for(let f=2;a.has(u);f++)u=`${oe.basename(c)}-${f}`;a.add(u);let d=oe.join(n,u),p=await Gs(c);await Ks(c,d,o,p),s.push({name:u,dir:d,base:c,baseRef:p,repo:l})}return await Rc(n,s,o),{dir:n,kind:"multi",branch:o,repos:s}}catch(a){for(let i of s)await Ot(i.base,i.dir).catch(()=>{});throw await ee.rm(n,{recursive:!0,force:!0}).catch(()=>{}),a}}async function ng(e,t){let n=await Q(),r=he(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 k_(typeof t=="string"?t.trim():t);if((o.repos??[]).some(p=>p?.base===s))throw new Error(`repo already tagged: ${t}`);let a=await _e(s).catch(()=>null),i=new Set([".bostrat",...(o.repos??[]).map(p=>p?.name).filter(Boolean)]),c=oe.basename(s);i.has(c)&&a&&(c=a.replace("/","-"));for(let p=2;i.has(c);p++)c=`${oe.basename(s)}-${p}`;let l=oe.join(o.dir,c),u=await Gs(s);await vv(s,o.branch)?await wu(s,l,o.branch):await Ks(s,l,o.branch,u);let d={name:c,dir:l,base:s,baseRef:u,repo:a};return o.repos=[...(o.repos??[]).filter(Boolean),d],await Rc(o.dir,o.repos,o.branch),$e(r,"retagged",{action:"add",repo:a??s,name:c,workspace:x_(o)}),await ce(),d}async function rg(e,t){let n=await Q(),r=he(n,e);if(!r)throw new Error(`track "${e}" not found`);let o=r.workspace;if(o?.kind!=="multi")throw new Error("live re-tagging needs a multi-repo Track");let s=(o.repos??[]).find(c=>c&&(c.name===t||c.repo===t||c.base===t));if(!s)throw new Error(`repo "${t}" is not tagged on this Track`);if((o.repos??[]).filter(Boolean).length<=1)throw new Error("can't untag the last repo \u2014 archive or delete the Track instead");for(let c of Pt.values())if(c.trackId===e&&!c.finishedAt)throw new Error("a subtask is still running on this Track \u2014 wait for it to merge back before untagging");let a=await Oi(s.dir,{ignorePlumbing:!0}).catch(()=>!1),i=await Mi(s.dir,s.baseRef).catch(()=>0);if(a||i>0)throw new Error(`"${s.name}" has work (${a?"uncommitted changes":`${i} commit${i===1?"":"s"} ahead of ${s.baseRef??"base"}`}) \u2014 ship or discard it first`);return await Ot(s.base,s.dir).catch(()=>{}),await ee.rm(s.dir,{recursive:!0,force:!0}).catch(()=>{}),o.repos=(o.repos??[]).filter(c=>c&&c!==s),await Rc(o.dir,o.repos,o.branch),$e(r,"retagged",{action:"remove",repo:s.repo??s.base,name:s.name,workspace:x_(o)}),await ce(),{removed:s.name}}async function N4(e,t,{repo:n,repos:r,cwd:o}={}){await ee.mkdir(gc,{recursive:!0});let s=oe.join(gc,e),a=Array.isArray(r)?r.map(c=>typeof c=="string"?c.trim():"").filter(Boolean):[];if(a.length>=2)return C4(e,t,s,a);a.length===1&&!n&&(n=a[0]),typeof n=="string"&&!oe.isAbsolute(n)&&/^[^/\s]+\/[^/\s]+$/.test(n)&&(n=await ws(n)??await bl(n));let i=await b_([n,o,zU]);if(i){let c=`track/${vg(t)}-${e}`;try{let l=await Gs(i);await Ks(i,s,c,l),await xc(s);let u=await _e(i).catch(()=>null);return{dir:s,base:i,branch:c,kind:"worktree",baseRef:l,repo:u}}catch{await ee.rm(s,{recursive:!0,force:!0}).catch(()=>{})}}return await ee.mkdir(s,{recursive:!0}),await Cm(s),await xc(s),{dir:s,base:null,branch:null,kind:"repo"}}async function xc(e){try{await ee.writeFile(oe.join(e,"AGENTS.md"),wc,{flag:"wx"})}catch{return}await j4(e,["/AGENTS.md"])}function B4(e,t){let n=e.map(r=>`- \`${r.name}/\`${r.repo?` \u2014 github.com/${r.repo}`:""}${r.baseRef?` (forked from ${r.baseRef})`:""}`).join(`
222
- `);return`${D4}
221
+ ${o}`,{source:"restore"})}else Ea(r,o);return await ae(),{ok:!0,draft:r.draft||null,rev:r.draftRev||0}}async function hg(e,t){if(typeof t!="string"||!t.trim())throw new Error("model (string) required");let n=t.trim(),r=de(await Q(),e);if(!r)throw new Error(`track "${e}" not found`);let o=await be(r.leadBox);if(!o)throw new Error(`lead box "${r.leadBox}" is not running`);let a=r.boxes.find(d=>d.name===r.leadBox)?.agent||o.agent||"claude",i=sS(a,n),l=[...r.events||[]].reverse().find(d=>d.type==="model-change")?.to??null;l||(l=(await bi(o.cwd,o.sessionId,{fallbackNewest:!1}).catch(()=>null))?.model??null),await tr({cwd:o.cwd,sessionId:o.sessionId,sessionName:r.leadBox,agent:o.agent,agentCmd:ls(o.agent)});let u=await aS(a,r.leadBox,i);return Se(r,"model-change",{to:n,from:l,box:r.leadBox,agent:a,verified:!!u.verified}),await ae(),{ok:!0,requested:n,leadBox:r.leadBox,...u}}async function N_(e){for(let t of e){if(!t||!await ea(t))continue;let n=await jv(t).catch(()=>null);if(!n)continue;if((await V.stat(z.join(n,".git")).catch(()=>null))?.isDirectory())return n}return null}function Nt(e){let t=e;return t?t.kind==="multi"?Array.isArray(t.repos)?t.repos.filter(Boolean):[]:t.base?[{name:z.basename(t.base),dir:t.dir??null,base:t.base,baseRef:t.baseRef??null,repo:t.repo??null}]:[]:[]}async function ts(e){let t=[];for(let n of Nt(e?.workspace)){if(!n?.dir)continue;let r=await Uo(n.dir,{ignorePlumbing:!0}).catch(()=>!1),o=await Ho(n.dir,n.baseRef).catch(()=>0);(r||o>0)&&t.push({...n,dirty:r,ahead:o})}return t}async function wg(e){let t=e;typeof t=="string"&&!z.isAbsolute(t)&&/^[^/\s]+\/[^/\s]+$/.test(t)&&(t=await Is(t)??await Sl(t));let n=await N_([t]);if(!n)throw new Error(`tagged repo "${e}" is not a usable base (need a primary checkout or a synced owner/name)`);return n}async function Y4(e,t,n,r){let o=`track/${ep(t)}-${e}`,s=[];try{await V.mkdir(n,{recursive:!0});let a=new Set([".bostrat"]);for(let i of r){let c=await wg(i);if(s.some(f=>f.base===c))throw new Error(`repo tagged twice: ${i}`);let l=await _e(c).catch(()=>null),u=z.basename(c);a.has(u)&&l&&(u=l.replace("/","-"));for(let f=2;a.has(u);f++)u=`${z.basename(c)}-${f}`;a.add(u);let d=z.join(n,u),p=await qo(c);await Wo(c,d,o,p),s.push({name:u,dir:d,base:c,baseRef:p,repo:l})}return await Ma(n,s,o),{dir:n,kind:"multi",branch:o,repos:s}}catch(a){for(let i of s)await xt(i.base,i.dir).catch(()=>{});throw await V.rm(n,{recursive:!0,force:!0}).catch(()=>{}),a}}async function qd(e,t){let n=await Q(),r=de(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error("track is archived \u2014 unarchive it first");let o=r.workspace;if(o?.kind!=="multi")throw new Error("live re-tagging needs a multi-repo Track \u2014 a single-repo Track's workspace IS its repo checkout; create the Track with multiple repos tagged instead");let s=await wg(typeof t=="string"?t.trim():t);if((o.repos??[]).some(p=>p?.base===s))throw new Error(`repo already tagged: ${t}`);let a=await _e(s).catch(()=>null),i=new Set([".bostrat",...(o.repos??[]).map(p=>p?.name).filter(Boolean)]),c=z.basename(s);i.has(c)&&a&&(c=a.replace("/","-"));for(let p=2;i.has(c);p++)c=`${z.basename(s)}-${p}`;let l=z.join(o.dir,c),u=await qo(s);await zm(s,o.branch)?await ji(s,l,o.branch):await Wo(s,l,o.branch,u);let d={name:c,dir:l,base:s,baseRef:u,repo:a};return o.repos=[...(o.repos??[]).filter(Boolean),d],await Ma(o.dir,o.repos,o.branch),Se(r,"retagged",{action:"add",repo:a??s,name:c,workspace:gg(o)}),await ae(),d}async function Kd(e,t){let n=await Q(),r=de(n,e);if(!r)throw new Error(`track "${e}" not found`);let o=r.workspace;if(o?.kind!=="multi")throw new Error("live re-tagging needs a multi-repo Track");let s=(o.repos??[]).find(c=>c&&(c.name===t||c.repo===t||c.base===t));if(!s)throw new Error(`repo "${t}" is not tagged on this Track`);if((o.repos??[]).filter(Boolean).length<=1)throw new Error("can't untag the last repo \u2014 archive or delete the Track instead");for(let c of Ct.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 Uo(s.dir,{ignorePlumbing:!0}).catch(()=>!1),i=await Ho(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 xt(s.base,s.dir).catch(()=>{}),await V.rm(s.dir,{recursive:!0,force:!0}).catch(()=>{}),o.repos=(o.repos??[]).filter(c=>c&&c!==s),await Ma(o.dir,o.repos,o.branch),Se(r,"retagged",{action:"remove",repo:s.repo??s.base,name:s.name,workspace:gg(o)}),await ae(),{removed:s.name}}async function Od(e,t){let n=await Q(),r=de(n,e);r&&(r.reshape={...r.reshape||{},...t},await ae())}async function X4(e){let t=await V.readdir(e).catch(()=>[]);for(let n of t)if(!(n===".git"||n===".bostrat")){if(n==="AGENTS.md"){let r=await V.readFile(z.join(e,n),"utf8").catch(()=>"");if(Sc(r))continue}return!0}try{let{stdout:n}=await Dd("git",["-C",e,"rev-list","--count","HEAD"]);if(Number(n.trim())>1)return!0}catch{}return!1}function k_(e,t,n){let r=z.basename(e);n.has(r)&&t&&(r=t.replace("/","-"));for(let o=2;n.has(r);o++)r=`${z.basename(e)}-${o}`;return n.add(r),r}async function P_(e,{added:t=[]}={}){let{shape:n,dir:r,staging:o,sub:s,base:a,scratch:i}=e;for(let l of t)await xt(l.base,l.dir).catch(()=>{});let c=async(l,u)=>{await hn(l)&&!await hn(u)&&await V.rename(l,u)};if(n==="worktree"&&s){let l=z.join(r,s);await hn(l)&&(await c(z.join(r,".bostrat"),z.join(l,".bostrat")),await Md(a,l,o))}if(n==="repo"&&i){let l=z.join(r,i);await hn(l)&&(await hn(o)&&await V.rm(o,{recursive:!0,force:!0}),await V.rename(l,o))}return await hn(o)?(await hn(r)&&(await c(z.join(r,".bostrat"),z.join(o,".bostrat")),await V.rm(r,{recursive:!0,force:!0})),n==="worktree"?await Md(a,o,r):await V.rename(o,r),!0):!1}async function bg(e,t,{skipPermissions:n=!0}={}){let r=await Q(),o=de(r,e);if(!o)throw ht(`track "${e}" not found`,404);if(o.archivedAt)throw ht("track is archived \u2014 unarchive it first");try{Xd(o)}catch(g){throw Object.assign(g,{status:409})}if(o.kind==="setup")throw ht("setup boxes have no repos to reshape");if(String(o.name||"").startsWith("\u21BB"))throw ht("this Track's repos are the loop's \u2014 propose-update the loop instead");let s=Qw.get(e);if(s&&!s.finishedAt)throw ht("a reshape is already running for this Track");let a=cs.get(e);if(a&&!a.finishedAt)throw ht("a lead handoff is running \u2014 retry when it settles");let i=Nd.get(e);if(i&&!i.finishedAt)throw ht("a node transfer is running \u2014 retry when it settles");if($d.has(e))throw ht("an adopt is running for this Track \u2014 retry when it settles");for(let g of Ct.values())if(g.trackId===e&&!g.finishedAt)throw ht("a subtask is still running on this Track \u2014 wait for it to merge back before reshaping");let c=(Array.isArray(t)?t:[]).map(g=>typeof g=="string"?g.trim():"").filter(Boolean);if(!c.length)throw ht("repos (non-empty list of paths or owner/name slugs) required",400);let l=[];for(let g of c){let y;try{y=await wg(g)}catch(x){throw ht(x?.message||String(x),400)}if(l.some(x=>x.base===y))throw ht(`repo tagged twice: ${g}`,400);l.push({sel:g,base:y,slug:await _e(y).catch(()=>null)})}let u=o.workspace;if(u?.kind==="multi"){let g=(u.repos??[]).filter(Boolean),y=g.filter(R=>!l.some(_=>_.base===R.base)),x=l.filter(R=>!g.some(_=>_.base===R.base));if(!y.length&&!x.length)return{trackId:e,step:"done",inPlace:!0,added:[],removed:[],startedAt:Date.now(),finishedAt:Date.now(),error:null};for(let R of y){let _=await Uo(R.dir,{ignorePlumbing:!0}).catch(()=>!1),C=await Ho(R.dir,R.baseRef).catch(()=>0);if(_||C>0)throw ht(`"${R.name}" has work \u2014 ship or discard it before dropping it`)}let b={trackId:e,step:"retag",inPlace:!0,added:[],removed:[],startedAt:Date.now(),finishedAt:null,error:null};for(let R of x){let _=await qd(e,R.base);b.added.push(_.repo??_.base)}for(let R of y)await Kd(e,R.name),b.removed.push(R.repo??R.base);return b.step="done",b.finishedAt=Date.now(),b}if(u?.kind!=="worktree"&&u?.kind!=="repo")throw ht(`can't reshape a "${u?.kind??"unknown"}" workspace`);let d=u.kind==="worktree"&&l.some(g=>g.base===u.base);if(u.kind==="worktree"&&!d){let g=await Uo(u.dir??o.cwd,{ignorePlumbing:!0}).catch(()=>!1),y=await Ho(u.dir??o.cwd,u.baseRef).catch(()=>0);if(g||y>0)throw ht(`"${z.basename(u.base)}" has work (${g?"uncommitted changes":`${y} commit${y===1?"":"s"} ahead of ${u.baseRef??"base"}`}) \u2014 ship or discard it before swapping it out`)}Oa(e,"reshape");let p=o.boxes.find(g=>g.name===o.leadBox)||null;if(!p)throw ht("this Track has no lead box");let f=p.agent||"claude",w=await Ra(f,n),m={trackId:e,step:"checkpoint",inPlace:!1,startedAt:Date.now(),finishedAt:null,error:null,added:l.filter(g=>!(u.kind==="worktree"&&g.base===u.base)).map(g=>g.slug??g.base),removed:u.kind==="worktree"&&!d?[u.repo??u.base]:[],scratch:!1,views:0,checkpoint:null};return Qw.set(e,m),await Od(e,{step:m.step,startedAt:m.startedAt,finishedAt:null,error:null,added:m.added,removed:m.removed,layout:null}),Z4(m,o,{desired:l,keep:d,lead:p,agent:f,agentCmd:w,skipPermissions:n}).catch(async g=>{m.error=g?.message||String(g),m.finishedAt=Date.now(),console.error(`[reshape ${e}] FAILED at step "${m.step}": ${m.error}`),await Od(e,{step:m.step,error:m.error,finishedAt:m.finishedAt}).catch(()=>{})}),m}async function Z4(e,t,{desired:n,keep:r,lead:o,agent:s,agentCmd:a,skipPermissions:i}){let c=e.trackId,l=t.workspace,u=t.cwd,d=async(A,S={})=>{e.step=A,console.log(`[reshape ${c}] step \u2192 ${A}`),await Od(c,{step:A,...S})},p=await be(o.name).catch(()=>null),f=o.sessionId??p?.sessionId??null,w=o.pinned===!0;if(await d("checkpoint"),e.checkpoint="llm",!p)e.checkpoint="skipped-dead";else if(Jr(s))e.checkpoint="skipped-capped";else try{await mu(o.name,{timeoutMs:ng})}catch{e.checkpoint="reconstructed"}let m=null;e.checkpoint!=="llm"&&(m=await hu(c,u,{trackName:t.name||c}).catch(()=>null)),await d("quiesce"),e.views=await mw(c).catch(()=>0),await Ml(u).catch(()=>{}),p&&(await vm(o.name,{fromAgent:s}).catch(()=>{}),await $t(o.name).catch(()=>{}));let g=`${u}.reshape-${Date.now()}`,y=new Set([".bostrat"]),x={shape:l.kind,dir:u,staging:g,base:l.kind==="worktree"?l.base:null,sub:l.kind==="worktree"&&r?k_(l.base,l.repo??null,y):null,scratch:null},b=l.branch||`track/${ep(t.name||c)}-${c}`,R=[],_=[],C=null;try{if(await d("move",{layout:x}),l.kind==="worktree")if(await Md(l.base,u,g),await V.mkdir(u,{recursive:!0}),r){let S=z.join(u,x.sub);await Md(l.base,g,S),await hn(z.join(S,".bostrat"))&&await V.rename(z.join(S,".bostrat"),z.join(u,".bostrat"));let N=z.join(S,"AGENTS.md");Sc(await V.readFile(N,"utf8").catch(()=>null))&&(await V.rm(N,{force:!0}).catch(()=>{}),await j_(S,"/AGENTS.md").catch(()=>{})),R.push({name:x.sub,dir:S,base:l.base,baseRef:l.baseRef??null,repo:l.repo??null})}else await hn(z.join(g,".bostrat"))&&await V.rename(z.join(g,".bostrat"),z.join(u,".bostrat"));else await V.rename(u,g),await V.mkdir(u,{recursive:!0}),await hn(z.join(g,".bostrat"))&&await V.rename(z.join(g,".bostrat"),z.join(u,".bostrat"));await d("materialize");for(let S of n){if(l.kind==="worktree"&&S.base===l.base)continue;let N=k_(S.base,S.slug,y),H=z.join(u,N),q=await qo(S.base);await zm(S.base,b)?await ji(S.base,H,b):await Wo(S.base,H,b,q);let re={name:N,dir:H,base:S.base,baseRef:q,repo:S.slug};R.push(re),_.push(re)}if(l.kind==="repo"&&await X4(g)){let S="scratch";for(let N=2;y.has(S);N++)S=`scratch-${N}`;y.add(S),x.scratch=S,await Od(c,{layout:x}),await V.rename(g,z.join(u,S)),e.scratch=!0}await Ma(u,R,b,{scratch:x.scratch}),await d("relaunch"),C=await _n(o.name,u,{agentCmd:a,agent:s}),await tr({cwd:u,sessionName:o.name,agent:s,agentCmd:ls(s)}).catch(S=>{if(S?.code!=="cli-not-running")throw S});let A=await Pe(o.name,{lines:Ye}).catch(()=>"");if(!Po(s,A))throw new Error(`relaunched ${s} CLI never drew its composer in the hub`)}catch(A){await d("rollback",{error:A?.message||String(A)}),await $t(o.name).catch(()=>{}),await P_(x,{added:_}).catch(q=>{console.error(`[reshape ${c}] rollback move failed: ${q?.message||q}`)});let S=await Q(),N=de(S,c),H=N?.boxes.find(q=>q.name===o.name)||null;try{let q=jd(s,f,{skipPermissions:i,cwd:u,peerName:o.name}),re=await _n(o.name,u,{agentCmd:q,agent:s,resumeSessionId:f,pinned:w});H&&(H.hookTokenHash=To(re.hookToken),H.state="live"),Do({cwd:u,sessionName:o.name,agent:s,agentCmd:q})}catch(q){console.error(`[reshape ${c}] rollback relaunch failed: ${q?.message||q}`)}throw N&&(Se(N,"retag-failed",{action:"reshape",box:o.name,agent:s,reason:A?.message||String(A),rolledBack:!0}),N.reshape={...N.reshape||{},step:"error",error:A?.message||String(A),finishedAt:Date.now(),recovered:"rolled-back"},await ae()),e.step="error",e.recovered="rolled-back",e.error=A?.message||String(A),e.finishedAt=Date.now(),A}await d("commit");let U=await Q(),B=de(U,c);if(!B)throw new Error(`track "${c}" vanished mid-reshape`);let T=B.boxes.find(A=>A.name===o.name);if(!T)throw new Error(`lead box row "${o.name}" missing during reshape commit`);let $=Date.now(),L=is(T),J=L[L.length-1];J.endedAt==null&&(J.endedAt=$),J.endReason==null&&(J.endReason="reshape"),L.push({agent:s,sessionId:C.sessionId,pinned:C.pinned===!0,startedAt:$,endedAt:null}),T.cwd=u,T.agent=s,T.sessionId=C.sessionId,T.pinned=C.pinned===!0,T.hookTokenHash=To(C.hookToken),T.state="live",T.role="lead",delete T.readyAt,B.cwd=u,B.workspace={dir:u,kind:"multi",branch:b,repos:R},B.pendingHandoffHydrate={artifact:m||uo,at:$},Se(B,"retagged",{action:"reshape",added:e.added,removed:e.removed,scratch:e.scratch,checkpoint:e.checkpoint,views:e.views,box:o.name,agent:s,fromSessionId:f,toSessionId:C.sessionId,epoch:L.length-1,workspace:gg(B.workspace)}),B.reshape={...B.reshape||{},step:"done",finishedAt:$,error:null,checkpoint:e.checkpoint,scratch:e.scratch,views:e.views,layout:null},await ae(),Do({cwd:u,sessionName:o.name,agent:s,agentCmd:a,onReady:async()=>{T.readyAt||(T.readyAt=Date.now(),await ae())}}),await hn(g)&&(l.kind==="worktree"&&await xt(l.base,g).catch(()=>{}),await V.rm(g,{recursive:!0,force:!0}).catch(()=>{})),e.step="done",e.finishedAt=$}async function kg(){let e=await Q(),t=0;for(let n of e.tracks||[]){let r=n.reshape;if(!r||r.finishedAt)continue;t++;let o=n.boxes.find(c=>c.name===n.leadBox)||null;o&&await $t(o.name).catch(()=>{});let s=!1,a=null;if(r.layout)try{let{dir:c,sub:l,scratch:u}=r.layout,d=new Set([".bostrat",l,u].filter(Boolean)),p=[];for(let f of await V.readdir(c).catch(()=>[])){if(d.has(f))continue;let w=z.join(c,f),m=await V.readFile(z.join(w,".git"),"utf8").catch(()=>null),g=m&&/^gitdir:\s*(.+?)\/\.git\/worktrees\//m.exec(m);g&&p.push({base:g[1],dir:w})}s=await P_(r.layout,{added:p})}catch(c){a=c?.message||String(c),console.error(`[reshape ${n.id}] boot rollback failed: ${a}`)}o&&!Sr.has(o.state)&&(o.state="stopped");let i=`interrupted by a node restart during "${r.step}"${s?" \u2014 moved back":""}${a?` (${a})`:""}`;Se(n,"retag-failed",{action:"reshape",box:n.leadBox,agent:o?.agent??null,reason:i,rolledBack:!a,recovered:!0}),n.reshape={...r,step:"error",error:i,finishedAt:Date.now(),recovered:a?"rollback-failed":"rolled-back",layout:null}}return t&&await ae(),t}async function Q4(e,t,{repo:n,repos:r,cwd:o}={}){await V.mkdir(Ac,{recursive:!0});let s=z.join(Ac,e),a=Array.isArray(r)?r.map(c=>typeof c=="string"?c.trim():"").filter(Boolean):[];if(a.length>=2)return Y4(e,t,s,a);a.length===1&&!n&&(n=a[0]),typeof n=="string"&&!z.isAbsolute(n)&&/^[^/\s]+\/[^/\s]+$/.test(n)&&(n=await Is(n)??await Sl(n));let i=await N_([n,o,u4]);if(i){let c=`track/${ep(t)}-${e}`;try{let l=await qo(i);await Wo(i,s,c,l),await Ic(s);let u=await _e(i).catch(()=>null);return{dir:s,base:i,branch:c,kind:"worktree",baseRef:l,repo:u}}catch{await V.rm(s,{recursive:!0,force:!0}).catch(()=>{})}}return await V.mkdir(s,{recursive:!0}),await Vm(s),await Ic(s),{dir:s,base:null,branch:null,kind:"repo"}}async function Ic(e){try{await V.writeFile(z.join(e,"AGENTS.md"),vc,{flag:"wx"})}catch{return}await r2(e,["/AGENTS.md"])}function n2(e,t,{scratch:n=null}={}){let r=e.map(s=>`- \`${s.name}/\`${s.repo?` \u2014 github.com/${s.repo}`:""}${s.baseRef?` (forked from ${s.baseRef})`:""}`).join(`
222
+ `),o=n?`
223
+ \`${n}/\` is this Track's pre-repo workspace, carried over when the
224
+ Track was reshaped onto these repos. It is not part of any tagged repo and
225
+ cannot be shipped \u2014 move anything worth keeping into the repo it belongs to.
226
+ `:"";return`${t2}
223
227
 
224
228
  This directory is NOT a git repo. It is a bostrat Track workspace holding one
225
229
  git worktree per tagged repo, ALL on the same branch \`${t}\`:
226
230
 
227
- ${n}
231
+ ${r}
228
232
 
229
233
  cd into the repo a change belongs to before running git commands; commit (and
230
234
  push / open PRs) in each repo separately, always on that shared branch. Work
231
235
  only needs to land in the repos it actually touches \u2014 an untouched repo's
232
236
  branch simply stays at its fork point and never gets pushed. When asked to run
233
237
  or preview an app, run it from that app's own repo directory.
234
- `}async function Rc(e,t,n){let r=B4(t,n);for(let o of["CLAUDE.md","AGENTS.md"])await ee.writeFile(oe.join(e,o),r).catch(()=>{})}async function S_(e){let{stdout:t}=await c_("git",["-C",e,"rev-parse","--git-path","info/exclude"]);return oe.resolve(e,t.trim())}async function j4(e,t){try{let n=await S_(e);await ee.mkdir(oe.dirname(n),{recursive:!0});let r=await ee.readFile(n,"utf8").catch(()=>""),o=t.filter(s=>!r.split(`
235
- `).includes(s));o.length&&await ee.appendFile(n,(r.endsWith(`
238
+ ${o}`}async function Ma(e,t,n,r={}){let o=n2(t,n,r);for(let s of["CLAUDE.md","AGENTS.md"])await V.writeFile(z.join(e,s),o).catch(()=>{})}async function B_(e){let{stdout:t}=await Dd("git",["-C",e,"rev-parse","--git-path","info/exclude"]);return z.resolve(e,t.trim())}async function r2(e,t){try{let n=await B_(e);await V.mkdir(z.dirname(n),{recursive:!0});let r=await V.readFile(n,"utf8").catch(()=>""),o=t.filter(s=>!r.split(`
239
+ `).includes(s));o.length&&await V.appendFile(n,(r.endsWith(`
236
240
  `)||!r?"":`
237
241
  `)+o.join(`
238
242
  `)+`
239
- `)}catch{}}async function L4(e,t){try{let n=await S_(e),r=await ee.readFile(n,"utf8"),o=r.split(`
243
+ `)}catch{}}async function j_(e,t){try{let n=await B_(e),r=await V.readFile(n,"utf8"),o=r.split(`
240
244
  `).filter(s=>s!==t);o.length!==r.split(`
241
- `).length&&await ee.writeFile(n,o.join(`
242
- `))}catch{}}async function og(){let e={refreshed:0,removed:0,codexGlobal:null};try{await ee.mkdir(Hn,{recursive:!0}),await ee.writeFile(oe.join(Hn,"CLAUDE.md"),P4).catch(()=>{}),await ee.writeFile(oe.join(Hn,"AGENTS.md"),wc).catch(()=>{});let t=process.env.CODEX_HOME||oe.join(process.env.HOME||"/tmp",".codex");if((await ee.stat(t).catch(()=>null))?.isDirectory()){let r=oe.join(t,"AGENTS.md"),o=await ee.readFile(r,"utf8").catch(()=>null);o===null?(await ee.writeFile(r,Ow,{flag:"wx"}).catch(()=>{}),e.codexGlobal="created"):Rw(o)&&o!==Ow&&(await ee.writeFile(r,Ow).catch(()=>{}),e.codexGlobal="refreshed")}for(let r of[gc,va]){let o=await ee.readdir(r,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(!s.isDirectory())continue;let a=oe.join(r,s.name),i=oe.join(a,"AGENTS.md"),c=await ee.readFile(i,"utf8").catch(()=>null);c!==null&&Rw(c)&&c!==wc&&(await ee.writeFile(i,wc).catch(()=>{}),e.refreshed++);let l=oe.join(a,"CLAUDE.md"),u=await ee.readFile(l,"utf8").catch(()=>null);u!==null&&Rw(u)&&(await ee.rm(l,{force:!0}).catch(()=>{}),await L4(a,"/CLAUDE.md"),e.removed++)}}}catch{}return e}async function T_(e){let t=e.workspace;if(!(!t||!t.dir))try{if(t.kind==="multi"){for(let n of Bt(t))n.base&&n.dir&&await Ot(n.base,n.dir).catch(()=>{});await ee.rm(t.dir,{recursive:!0,force:!0})}else t.kind==="worktree"&&t.base?await Ot(t.base,t.dir):await ee.rm(t.dir,{recursive:!0,force:!0})}catch{}}async function Md({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 Ec(o,s),i=await Q(),c=Ad().slice(0,8),l=await N4(c,e,{repo:n,repos:r,cwd:t}),u=new Set(i.tracks.flatMap(w=>(w.boxes||[]).map(m=>m.name))),d=`${e.trim()} lead`;u.has(Fl(d))&&(d=`${e.trim().slice(0,50).trim()} ${c} lead`);let p=await Or(d,l.dir,{agentCmd:a,agent:o,freshWorkspace:!0}),f={id:c,name:e.trim(),cwd:p.cwd,workspace:l,leadBox:p.name,boxes:[mg(p,"lead","live")],events:[],createdAt:Date.now()};return $e(f,"opened",{agent:o,box:p.name,skipPermissions:s,name:f.name,cwd:f.cwd,workspace:{base:l.base??null,branch:l.branch,kind:l.kind,...l.baseRef?{baseRef:l.baseRef}:{},...l.repo?{repo:l.repo}:{},...l.repos?{repos:l.repos.map(({name:w,base:m,baseRef:g,repo:y})=>({name:w,base:m,baseRef:g,repo:y}))}:{}}}),i.tracks.push(f),await ce(),yi({cwd:p.cwd,sessionName:p.name,agent:o,agentCmd:a,onReady:async()=>{let w=f.boxes.find(m=>m.name===f.leadBox);!w||w.readyAt||(w.readyAt=Date.now(),await ce())}}),Nt(f)}async function sg({provider:e="claude",fresh:t=!1}={}){if(!F4.has(e))throw new Error(`unknown setup provider "${e}" (claude | codex | cursor)`);let r=(await Q()).tracks.find(u=>u.kind==="setup"&&u.setup?.provider===e&&!u.archivedAt);if(r){if(!t){let u=await Nt(r);if(u.boxes.find(p=>p.name===u.leadBox)?.state==="live")return u}await Zo(r.id).catch(()=>{})}let o=(await Ec(e,!1)).replace(/\s+--(?:dangerously-skip-permissions|dangerously-bypass-approvals-and-sandbox)\b/g,""),s=Ad().slice(0,8),a=oe.join(Hn,"setup",s);await ee.mkdir(a,{recursive:!0});let i=await Or(`Connect ${e} ${s}`,a,{agentCmd:o,agent:e,firstRun:!0});e==="codex"&&yi({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:[mg(i,"lead","live")],events:[],createdAt:Date.now()};return $e(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 Q()).tracks.push(c),await ce(),Nt(c)}async function ag(e,t,n){await Qp(t.cwd).catch(()=>{}),await jA(e).catch(()=>{});let r=xa.get(e);r&&!r.finishedAt&&(r.error=n,r.finishedAt=Date.now()),xa.delete(e),t.handoff&&!t.handoff.finishedAt&&(t.handoff.step="error",t.handoff.error=n,t.handoff.finishedAt=Date.now());for(let a of es(e))a.finishedAt||(a.canceled=!0,a.finishedAt=Date.now()),await Ag(a).catch(()=>{}),Pt.delete(a.id);for(let a of Object.values(t.subtasks||{}))a.finishedAt||(a.step="error",a.error=n,a.canceled=!0,a.finishedAt=Date.now());let o=await Q(),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 rn(a.name).catch(()=>{})}async function ig(e,{cascadeMocks:t=!0,cascadeRunbooks:n=!1}={}){let r=await Q(),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 sE(s),Qw(e),await ag(e,s,"track deleted"),n?await DE(e).catch(()=>{}):await PE(e).catch(()=>{}),await Vv(),await T_(s),t&&await aE(e).catch(()=>{}),t?await SE(e).catch(()=>{}):await vE(s).catch(()=>{}),$e(s,"track-deleted",{name:s.name,boxes:s.boxes.length,ageMs:s.createdAt?Date.now()-s.createdAt:null}),r.tracks.splice(o,1),await ce(),{ok:!0,id:e,name:s.name,boxes:s.boxes.length}}async function Zo(e){let t=await Q(),n=he(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(),Qw(e),$e(n,"archived",{boxes:n.boxes.length}),await ce(),n.kind==="setup"?(await A_(e),Nt(n)):(vc.add(e),q4(e).catch(()=>{}).finally(()=>vc.delete(e)),{...await Nt(n),archiving:!0})}async function q4(e){try{await W4(e)}catch{}await A_(e).catch(()=>{})}async function A_(e){let t=await Q(),n=he(t,e);if(!(!n||!n.archivedAt)){await ag(e,n,"track archived");for(let r of n.boxes)so.has(r.state)||(r.state="stopped");await ce()}}async function W4(e){let t=await Q(),n=he(t,e);if(!n||!n.archivedAt)return;let r=null,o=[],s="derived",a=(n.events||[]).some(l=>l.type==="said"),i=n.leadBox?await ke(n.leadBox).catch(()=>null):null;if(i?.cwd&&a)try{({text:r,items:o}=await wx(n.leadBox,i.cwd,{timeoutMs:H4})),s="lead-cli"}catch{}if(r||(r=Ox(n,await K(n).catch(()=>[]))),!r)return;let c={text:r,source:s,at:Date.now()};o.length&&(c.items=o),n.beat=c,await M(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 ce()}async function ar(e,t){let n=await at(e,t).catch(()=>null);if(!n?.archiveOnMerge||!n.trackId)return!1;let r=await cg(n);if(r.length){for(let o of r)await Bo(o.repo,o.number,!0).catch(()=>{});return!1}try{return await Zo(n.trackId),!0}catch(o){if(/already archived/i.test(String(o?.message||o)))return!1;throw o}}async function cg(e){return(await un().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 ir(e,t){return Cd(e,t,"merged")}async function Qo(e,t){let n=await at(e,t).catch(()=>null);if(!n?.trackId)return null;let r={repo:n.repo??null,number:n.number,title:n.title??null,url:n.url??null},o=await cg(n);if(o.length){let c=[...n.followupPending||[],r];for(let l of o)await SS(l.repo,l.number,c).catch(()=>{});return null}let s=[...n.followupPending||[],r],a=he(await Q(),n.trackId);if(!a)return null;let i=s[0];return Ji(await Nt(a),"pr.merged",{repo:n.repo??a.workspace?.repo??null,prs:s,prNumber:i?.number??null,prTitle:i?.title??null,prUrl:i?.url??null}).catch(()=>null)}async function Cd(e,t,n="merged"){let r=await at(e,t).catch(()=>null);if(!r?.notifyOnMerge||r.archiveOnMerge||!r.trackId)return!1;let o={repo:r.repo??null,number:r.number,title:r.title??null,url:r.url??null,headRef:r.headRef??null,outcome:n},s=await cg(r);if(s.length){let i=[...r.notifyPending||[],o];for(let c of s)await vS(c.repo,c.number,i).catch(()=>{});return!1}let a=[...r.notifyPending||[],o];if(!await hS(r.repo,r.number).catch(()=>!0))return!1;try{return await Dt(r.trackId,E_(a),{kind:"merge-notify"}),!0}catch{return await jo(r.repo,r.number,!0).catch(()=>{}),!1}}function E_(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 ${o_[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 ${o_[i.outcome]??i.outcome}`).join(`
245
+ `).length&&await V.writeFile(n,o.join(`
246
+ `))}catch{}}async function xg(){let e={refreshed:0,removed:0,codexGlobal:null};try{await V.mkdir(Kn,{recursive:!0}),await V.writeFile(z.join(Kn,"CLAUDE.md"),e2).catch(()=>{}),await V.writeFile(z.join(Kn,"AGENTS.md"),vc).catch(()=>{});let t=process.env.CODEX_HOME||z.join(process.env.HOME||"/tmp",".codex");if((await V.stat(t).catch(()=>null))?.isDirectory()){let r=z.join(t,"AGENTS.md"),o=await V.readFile(r,"utf8").catch(()=>null);o===null?(await V.writeFile(r,zw,{flag:"wx"}).catch(()=>{}),e.codexGlobal="created"):Sc(o)&&o!==zw&&(await V.writeFile(r,zw).catch(()=>{}),e.codexGlobal="refreshed")}for(let r of[Ac,$a]){let o=await V.readdir(r,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(!s.isDirectory())continue;let a=z.join(r,s.name),i=z.join(a,"AGENTS.md"),c=await V.readFile(i,"utf8").catch(()=>null);c!==null&&Sc(c)&&c!==vc&&(await V.writeFile(i,vc).catch(()=>{}),e.refreshed++);let l=z.join(a,"CLAUDE.md"),u=await V.readFile(l,"utf8").catch(()=>null);u!==null&&Sc(u)&&(await V.rm(l,{force:!0}).catch(()=>{}),await j_(a,"/CLAUDE.md"),e.removed++)}}}catch{}return e}async function L_(e){let t=e.workspace;if(!(!t||!t.dir))try{if(t.kind==="multi"){for(let n of Nt(t))n.base&&n.dir&&await xt(n.base,n.dir).catch(()=>{});await V.rm(t.dir,{recursive:!0,force:!0})}else t.kind==="worktree"&&t.base?await xt(t.base,t.dir):await V.rm(t.dir,{recursive:!0,force:!0})}catch{}}async function Gd({name:e,cwd:t,repo:n,repos:r,agent:o="claude",model:s=null,skipPermissions:a=!0}){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");let i=await Ra(o,a,s),c=await Q(),l=Pd().slice(0,8),u=await Q4(l,e,{repo:n,repos:r,cwd:t}),d=new Set(c.tracks.flatMap(m=>(m.boxes||[]).map(g=>g.name))),p=`${e.trim()} lead`;d.has(Kl(p))&&(p=`${e.trim().slice(0,50).trim()} ${l} lead`);let f=await _n(p,u.dir,{agentCmd:i,agent:o,freshWorkspace:!0}),w={id:l,name:e.trim(),cwd:f.cwd,workspace:u,leadBox:f.name,boxes:[Og(f,"lead","live")],events:[],createdAt:Date.now()};return Se(w,"opened",{agent:o,...s?{model:s}:{},box:f.name,skipPermissions:a,name:w.name,cwd:w.cwd,workspace:{base:u.base??null,branch:u.branch,kind:u.kind,...u.baseRef?{baseRef:u.baseRef}:{},...u.repo?{repo:u.repo}:{},...u.repos?{repos:u.repos.map(({name:m,base:g,baseRef:y,repo:x})=>({name:m,base:g,baseRef:y,repo:x}))}:{}}}),c.tracks.push(w),await ae(),Do({cwd:f.cwd,sessionName:f.name,agent:o,agentCmd:i,onReady:async()=>{let m=w.boxes.find(g=>g.name===w.leadBox);!m||m.readyAt||(m.readyAt=Date.now(),await ae())}}),Lt(w)}async function vg({provider:e="claude",fresh:t=!1}={}){if(!o2.has(e))throw new Error(`unknown setup provider "${e}" (claude | codex | cursor)`);let r=(await Q()).tracks.find(u=>u.kind==="setup"&&u.setup?.provider===e&&!u.archivedAt);if(r){if(!t){let u=await Lt(r);if(u.boxes.find(p=>p.name===u.leadBox)?.state==="live")return u}await us(r.id).catch(()=>{})}let o=(await Ra(e,!1)).replace(/\s+--(?:dangerously-skip-permissions|dangerously-bypass-approvals-and-sandbox)\b/g,""),s=Pd().slice(0,8),a=z.join(Kn,"setup",s);await V.mkdir(a,{recursive:!0});let i=await _n(`Connect ${e} ${s}`,a,{agentCmd:o,agent:e,firstRun:!0});e==="codex"&&Do({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:[Og(i,"lead","live")],events:[],createdAt:Date.now()};return Se(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 Q()).tracks.push(c),await ae(),Lt(c)}async function Sg(e,t,n){await Ml(t.cwd).catch(()=>{}),await mw(e).catch(()=>{});let r=cs.get(e);r&&!r.finishedAt&&(r.error=n,r.finishedAt=Date.now()),cs.delete(e),t.handoff&&!t.handoff.finishedAt&&(t.handoff.step="error",t.handoff.error=n,t.handoff.finishedAt=Date.now());for(let a of ps(e))a.finishedAt||(a.canceled=!0,a.finishedAt=Date.now()),await Ug(a).catch(()=>{}),Ct.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 Q(),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 $t(a.name).catch(()=>{})}async function Ag(e,{cascadeMocks:t=!0,cascadeRunbooks:n=!1}={}){let r=await Q(),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 bE(s),fg(e),await Sg(e,s,"track deleted"),n?await YE(e).catch(()=>{}):await JE(e).catch(()=>{}),await lS(),await L_(s),t&&await kE(e).catch(()=>{}),t?await BE(e).catch(()=>{}):await DE(s).catch(()=>{}),Se(s,"track-deleted",{name:s.name,boxes:s.boxes.length,ageMs:s.createdAt?Date.now()-s.createdAt:null}),r.tracks.splice(o,1),await ae(),{ok:!0,id:e,name:s.name,boxes:s.boxes.length}}async function us(e){let t=await Q(),n=de(t,e);if(!n)throw new Error(`track "${e}" not found`);if(n.archivedAt)throw new Error(`track "${e}" is already archived`);return n.archivedAt=Date.now(),fg(e),Se(n,"archived",{boxes:n.boxes.length}),await ae(),n.kind==="setup"?(await F_(e),Lt(n)):($c.add(e),i2(e).catch(()=>{}).finally(()=>$c.delete(e)),{...await Lt(n),archiving:!0})}async function i2(e){try{await c2(e)}catch{}await F_(e).catch(()=>{})}async function F_(e){let t=await Q(),n=de(t,e);if(!(!n||!n.archivedAt)){await Sg(e,n,"track archived");for(let r of n.boxes)Sr.has(r.state)||(r.state="stopped");await ae()}}async function c2(e){let t=await Q(),n=de(t,e);if(!n||!n.archivedAt)return;let r=null,o=[],s="derived",a=(n.events||[]).some(l=>l.type==="said"),i=n.leadBox?await be(n.leadBox).catch(()=>null):null;if(i?.cwd&&a)try{({text:r,items:o}=await Mx(n.leadBox,i.cwd,{timeoutMs:a2})),s="lead-cli"}catch{}if(r||(r=zx(n,await K(n).catch(()=>[]))),!r)return;let c={text:r,source:s,at:Date.now()};o.length&&(c.items=o),n.beat=c,await M(n,{type:"track.summary.recorded",actor:"orchestrator",source:"orchestrator",boxId:n.leadBox||null,provider:i?.agent||null,payload:o.length?{text:r,items:o,source:s}:{text:r,source:s}}).catch(()=>{}),await ae()}async function ur(e,t){let n=await at(e,t).catch(()=>null);if(!n?.archiveOnMerge||!n.trackId)return!1;let r=await Tg(n);if(r.length){for(let o of r)await zo(o.repo,o.number,!0).catch(()=>{});return!1}try{return await us(n.trackId),!0}catch(o){if(/already archived/i.test(String(o?.message||o)))return!1;throw o}}async function Tg(e){return(await dn().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 dr(e,t){return zd(e,t,"merged")}async function ds(e,t){let n=await at(e,t).catch(()=>null);if(!n?.trackId)return null;let r={repo:n.repo??null,number:n.number,title:n.title??null,url:n.url??null},o=await Tg(n);if(o.length){let c=[...n.followupPending||[],r];for(let l of o)await jS(l.repo,l.number,c).catch(()=>{});return null}let s=[...n.followupPending||[],r],a=de(await Q(),n.trackId);if(!a)return null;let i=s[0];return tc(await Lt(a),"pr.merged",{repo:n.repo??a.workspace?.repo??null,prs:s,prNumber:i?.number??null,prTitle:i?.title??null,prUrl:i?.url??null}).catch(()=>null)}async function zd(e,t,n="merged"){let r=await at(e,t).catch(()=>null);if(!r?.notifyOnMerge||r.archiveOnMerge||!r.trackId)return!1;let o={repo:r.repo??null,number:r.number,title:r.title??null,url:r.url??null,headRef:r.headRef??null,outcome:n},s=await Tg(r);if(s.length){let i=[...r.notifyPending||[],o];for(let c of s)await BS(c.repo,c.number,i).catch(()=>{});return!1}let a=[...r.notifyPending||[],o];if(!await RS(r.repo,r.number).catch(()=>!0))return!1;try{return await Ft(r.trackId,U_(a),{kind:"merge-notify"}),!0}catch{return await Vo(r.repo,r.number,!0).catch(()=>{}),!1}}function U_(e){let t=i=>`${i.repo?`${i.repo}`:""}#${i.number}${i.title?` "${i.title}"`:""}${i.url?` (${i.url})`:""}`;if(e.length===1){let i=e[0],c=`#${i.number}${i.title?` "${i.title}"`:""}`;return i.outcome!=="merged"?`PR ${c}${i.url?` (${i.url})`:""}${i.headRef?` \u2014 branch ${i.headRef} \u2014`:""} was ${x_[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 ${x_[i.outcome]??i.outcome}`).join(`
243
247
  `),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}
244
248
  ${s}
245
- ${a}`}async function lg(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<li()?!1:Xn(e.name)}async function Sc(e,t,n){return!t||e.archivedAt||so.has(t.state)?!1:(await ie({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 rn(t.name).catch(()=>{}),t.state="stopped",Oc(e))}async function Oc(e,{freshSession:t=!1,reason:n=null}={}){let r=e.boxes.find(a=>a.name===e.leadBox);if(!r)return!1;let o=Mw.get(r.name);if(o)return o;let s=K4(e,r,{freshSession:t,reason:n}).finally(()=>Mw.delete(r.name));return Mw.set(r.name,s),s}async function K4(e,t,{freshSession:n=!1,reason:r=null}={}){if(e.archivedAt||e.transferredTo||so.has(t.state)||await ke(t.name))return!1;let o=n===!0,s=o?Ad():null,a=o?ii(Uw(t.agent),s,t.name):Hw(t.agent,t.sessionId,{cwd:t.cwd,peerName:t.name}),i=await Ll(a);if(i===Ts)return $e(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:`agent "${t.agent}" is not installed on this box`}),!1;i===As&&console.warn(`[track] ${t.name}: could not confirm "${t.agent}" on PATH \u2014 relaunching anyway (launch verifier will catch a real miss)`);let c=o?{sessionId:t.sessionId??null,pinned:t.pinned===!0,epochs:JSON.parse(JSON.stringify(ka(t)))}:null,l=Date.now();if(o){let u=ka(t),d=u[u.length-1];d.endedAt==null&&(d.endedAt=l),d.endReason==null&&(d.endReason=r||"fresh-session"),u.push({agent:t.agent,sessionId:s,pinned:t.agent==="claude",startedAt:l,endedAt:null}),t.sessionId=s,t.pinned=t.agent==="claude"}try{let u=await Or(t.name,t.cwd,{agentCmd:a,agent:t.agent,resumeSessionId:t.sessionId,pinned:t.pinned===!0});return t.hookTokenHash=Ha(u.hookToken),yi({cwd:t.cwd,sessionName:t.name,agent:t.agent,agentCmd:a}),t.state="live",o&&$e(e,"lead-refreshed",{box:t.name,agent:t.agent,fromSessionId:c.sessionId,toSessionId:s,epoch:t.epochs.length-1,reason:r||"fresh-session"}),$e(e,"rehydrated",{box:t.name,agent:t.agent,...o?{fresh:!0}:{}}),!0}catch(u){return o&&(t.sessionId=c.sessionId,t.pinned=c.pinned,t.epochs=c.epochs),$e(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:String(u?.message||u)}),!1}}async function Nd(e,{freshSession:t=!1}={}){let n=await Q(),r=he(n,e);if(!r)throw new Error(`track "${e}" not found`);if(!r.archivedAt)throw new Error(`track "${e}" is not archived`);return delete r.archivedAt,vc.delete(e),$e(r,"unarchived",{}),await Oc(r,t?{freshSession:!0,reason:"loop-fire"}:{}),await ce(),Nt(r)}async function ug(e,t){let n=typeof t=="string"?t.trim():"";if(!n)throw new Error("name (non-empty string) required");if(n.length>jw)throw new Error(`name too long (max ${jw} chars)`);let r=await Q(),o=he(r,e);if(!o)throw new Error(`track "${e}" not found`);if(String(o.name||"").startsWith("\u21BB"))throw new Error("loop run Tracks are named by their loop \u2014 rename the loop on the Loops tab");if(n===o.name)return Nt(o);let s=o.name;return o.name=n,$e(o,"renamed",{from:s,to:n}),await ce(),Nt(o)}async function dg(){let e=await Q(),t=0;for(let n of e.tracks||[])n.transferredTo&&yu(n,{at:n.transferredAt??Date.now()})&&t++;return t&&await ce(),t}async function pg(){let e=await Q(),t=new Set((await nn()).map(s=>s.name)),n=new Set((e.tracks||[]).filter(s=>!De(s)).flatMap(s=>(s.boxes||[]).map(a=>a.name))),r=0,o=!1;for(let s of e.tracks||[])if(De(s))for(let a of s.boxes)t.has(a.name)&&!n.has(a.name)&&(await rn(a.name).catch(()=>{}),s.transferredTo?console.log(`[track] reaped orphan box ${a.name} on transferred-away track ${s.id} (\u2192 ${s.transferredTo})`):$e(s,"orphan-reaped",{box:a.name,agent:a.agent}),r++,o=!0),!so.has(a.state)&&a.state!=="stopped"&&(a.state="stopped",o=!0);return o&&await ce(),r}async function Pd(e,{freshSession:t=!1}={}){let n=await Q(),r=he(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it before restarting the lead`);yg(r);let o=r.boxes.find(i=>i.name===r.leadBox);if(!o)throw new Error(`track "${e}" has no lead box`);if(so.has(o.state))throw new Error("lead box is terminal \u2014 nothing to restart");if(await ke(r.leadBox)){let i=await Be(r.leadBox,{lines:Ze}).catch(()=>"");if(gi(o.agent,i))throw new Error("lead is mid-turn \u2014 retry when it goes idle");await rn(r.leadBox),o.state="stopped"}let a=await Oc(r,t?{freshSession:!0,reason:"loop-fire"}:{});if(await ce(),!a)throw new Error("rehydrate failed \u2014 see the track's rehydrate-failed event");return Nt(r)}async function fg(e,t,n){let r=await se(e);if(!r)throw new Error(`track "${e}" not found`);if(!t)throw new Error("unknown offer");let o=await K(r).catch(()=>[]);if(!o.some(i=>i.type==="box.fullscreen.detected"&&i.payload?.offerId===t))throw new Error("unknown offer");if(o.some(i=>i.type==="box.fullscreen.answered"&&i.payload?.offerId===t))throw new Error("offer already answered");return n&&await Pd(e),await M(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 s_(e,t){if(!e?.id||!t?.box)return[];let n=(e.boxes||[]).find(r=>r.name===t.box);return Ju({trackId:e.id,boxId:t.box,epoch:0,provider:n?.agent??t.agent??null})}function ka(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 Td(e,t){let n=await Q(),r=he(n,e);r&&(r.handoff={...r.handoff||{},...t},await ce())}function __(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 hg(){let e=await Q(),t=!1;for(let n of e.tracks||[]){let r=n.handoff,o=__(n);if(!o)continue;t=!0;let s=!!r.toBox&&r.toBox===r.fromBox;if(s&&o.step==="error"){let c=await ke(r.fromBox).catch(()=>null),l=n.boxes.find(u=>u.name===r.fromBox);if(c&&l&&c.agent===r.toAgent&&r.toAgent!==l.agent){let u=Date.now(),d=ka(l),p=d[d.length-1],f=p.agent,w=p.sessionId??null;p.endedAt=u,r.reason&&(p.endReason=r.reason);let m=c.agent==="claude"&&!!c.sessionId;d.push({agent:r.toAgent,sessionId:c.sessionId||null,pinned:m,startedAt:u,endedAt:null}),l.agent=r.toAgent,l.sessionId=c.sessionId||null,l.pinned=m,l.state="live",n.pendingHandoffHydrate={artifact:Yo,at:u},$e(n,"lead-handoff",{from:r.fromBox,to:r.fromBox,fromAgent:f,toAgent:r.toAgent,fromSessionId:w,toSessionId:c.sessionId||null,epoch:d.length-1,singleBox:!0,skipPermissions:r.skipPermissions,reason:r.reason??null,handoffStartedAt:r.startedAt,recovered:!0}),n.handoff={...r,step:"done",finishedAt:u,recovered:"swap adopted from live tmux tags after restart"},await ie({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 ie({flow:"lead-handoff",phase:"reconciled",trackId:n.id,outcome:o.step,recovered:o.recovered,fromBox:o.fromBox,toBox:o.toBox}).catch(()=>{}),i&&await rn(i).catch(()=>{}),a&&await rn(a).catch(()=>{})}return t&&await ce(),t}async function Dd(e,t,n=!0,r=null){let o=xa.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is already running for this Track");let s=he(await Q(),e);if(!s)throw new Error(`track "${e}" not found`);$c(e,"handoff");let a=await Ec(t,n),i=Po(t);if(i){let u=new Error(`can't hand off to ${t} \u2014 its ${i.window} spend limit is reached ($${i.spentUsd.toFixed(2)} of $${i.limitUsd.toFixed(2)})`);throw u.usageCap=i,u}let c=await ke(s.leadBox);if(!c)throw new Error(`lead box "${s.leadBox}" is not running`);let l={trackId:e,step:"checkpoint",fromBox:s.leadBox,toAgent:t,skipPermissions:n,reason:p_(r),toBox:s.leadBox,startedAt:Date.now(),finishedAt:null,error:null};return xa.set(e,l),await Td(e,{step:l.step,fromBox:l.fromBox,toAgent:t,toBox:l.toBox,skipPermissions:n,startedAt:l.startedAt,finishedAt:null,error:null}),G4(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 Td(e,{step:l.step,error:l.error,finishedAt:l.finishedAt}).catch(()=>{}),ie({flow:"lead-handoff",phase:"failed",trackId:e,step:l.step,error:l.error,fromBox:l.fromBox,toAgent:l.toAgent,toBox:l.toBox}).catch(()=>{})}),ie({flow:"lead-handoff",phase:"started",trackId:e,fromBox:l.fromBox,toAgent:t,cwd:c.cwd}).catch(()=>{}),l}async function G4(e,t,n,r,o){let s=async($,C={})=>{e.step=$,console.log(`[lead-handoff ${e.trackId}] step \u2192 ${$}`),await Td(e.trackId,{step:$,toBox:e.toBox}),await ie({flow:"lead-handoff",phase:$,trackId:e.trackId,fromBox:e.fromBox,toBox:e.toBox,toAgent:o,sessionName:C.sessionName,...C})};console.log(`[lead-handoff ${e.trackId}] ${e.fromBox}: ${n.agent} \u2192 ${o} IN PLACE`);let a=await Q(),i=he(a,e.trackId)?.boxes.find($=>$.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",Po(c))e.checkpoint="skipped-capped";else try{await tm(e.fromBox,{timeoutMs:u_})}catch($){e.checkpoint="reconstructed",await ie({flow:"lead-handoff",phase:"checkpoint-fallback",trackId:e.trackId,fromBox:e.fromBox,error:$?.message||String($)}).catch(()=>{})}e.checkpoint!=="llm"&&(e.statusArtifact=await nm(e.trackId,n.cwd,{trackName:t.name||t.id}).catch(()=>null),await s("checkpoint-degraded",{sessionName:e.fromBox,checkpoint:e.checkpoint,statusArtifact:e.statusArtifact})),await s("swap",{cwd:n.cwd,agentCmd:r});let p=await lm(e.fromBox,{agentCmd:r,agent:o});await s("hydrate",{sessionName:e.fromBox});let f=m0(p.launchCmd);await Cr({cwd:n.cwd,sessionId:p.sessionId,sessionName:e.fromBox,agent:o,agentCmd:Sa(o),launchEcho:f}).catch($=>{if($?.code!=="cli-not-running")throw $});let w=jf(await Be(e.fromBox,{lines:Ze}).catch(()=>""),f);if(!Ns(o,w)){await s("rollback",{sessionName:e.fromBox,fromAgent:c});let $=Hw(c,l,{skipPermissions:e.skipPermissions,cwd:n.cwd,peerName:e.fromBox});await lm(e.fromBox,{agentCmd:$,agent:c,resumeSessionId:l,pinned:u});let C=await Q(),L=he(C,e.trackId);if(L){let q=L.boxes.find(I=>I.name===e.fromBox);q&&(q.state="live"),$e(L,"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 ce()}throw new Error(`incoming ${o} CLI never drew its composer \u2014 rolled back to ${c} (--resume, context intact)`)}await s("commit");let m=await Q(),g=he(m,e.trackId);if(!g)throw new Error(`track "${e.trackId}" not found during handoff commit \u2014 was it deleted or archived mid-flight?`);let y=g.boxes.find($=>$.name===e.fromBox);if(!y)throw new Error(`lead box row "${e.fromBox}" missing during handoff commit`);let x=Date.now(),b=ka(y),O=b[b.length-1];O.endedAt=x,e.reason&&(O.endReason=e.reason),b.push({agent:o,sessionId:p.sessionId,pinned:p.pinned,startedAt:x,endedAt:null}),y.agent=o,y.sessionId=p.sessionId,y.pinned=p.pinned,y.state="live",y.role="lead",g.pendingHandoffHydrate={artifact:e.statusArtifact||Yo,at:x},$e(g,"lead-handoff",{from:e.fromBox,to:e.fromBox,fromAgent:c,toAgent:o,fromSessionId:l,toSessionId:p.sessionId,epoch:b.length-1,singleBox:!0,forced:p.forced||void 0,skipPermissions:e.skipPermissions,reason:e.reason,handoffStartedAt:e.startedAt,checkpoint:e.checkpoint}),await ce(),await s("done",{sessionName:e.fromBox}),await Td(e.trackId,{finishedAt:Date.now(),error:null}),e.finishedAt=Date.now()}async function gg(e){let t=Fw.get(e);if(t&&!t.finishedAt)throw new Error("a transfer is already running for this Track");let n=await Q(),r=he(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=xa.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is running \u2014 retry when it settles");for(let a of Pt.values())if(a.trackId===e&&!a.finishedAt)throw new Error("a subtask is still running on this Track \u2014 wait for it to merge back before moving");let s={trackId:e,step:"checkpoint",startedAt:Date.now(),finishedAt:null,error:null};return Fw.set(e,s),z4(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 z4(e,t){let n=t.boxes.find(u=>u.name===t.leadBox)||null,r=n?await ke(n.name).catch(()=>null):null;if(e.checkpoint="llm",!r||n&&Po(n.agent))e.checkpoint=r?"skipped-capped":"skipped-dead";else try{await tm(t.leadBox,{timeoutMs:u_})}catch{e.checkpoint="reconstructed"}e.checkpoint!=="llm"&&await nm(t.id,t.cwd,{trackName:t.name||t.id}).catch(()=>null),e.step="push";let o=t.workspace?.branch??null,s=[];if(o)for(let u of Bt(t.workspace)){if(!u?.dir)continue;let d={name:u.name??null,repo:u.repo??null,baseSha:null,pushed:!1};try{await mn(u.dir,["push","origin",o],Lw);let{stdout:p}=await mn(u.dir,["rev-parse","HEAD"]);d.baseSha=p.trim(),d.pushed=!0}catch(p){d.error=String(p?.message||p).split(`
246
- `)[0]}s.push(d)}e.step="wip";let a=await yw({id:t.id,cwd:t.cwd},{force:!0}),i=await Q(),c=he(i,t.id),l=c?.boxes.find(u=>u.name===c.leadBox)||null;l&&ka(l),await ce(),e.result={name:c?.name??t.name,agent:l?.agent??null,leadBox:c?.leadBox??t.leadBox,createdAt:c?.createdAt??null,branch:o,repos:s.filter(u=>u.pushed).map(({name:u,repo:d,baseSha:p})=>({name:u,repo:d,baseSha:p})),unpushed:s.filter(u=>!u.pushed).map(({name:u,repo:d,error:p})=>({name:u,repo:d,error:p})),wip:a.pushed?{ref:a.ref,sha:a.sha}:null,checkpoint:e.checkpoint,epochs:l?.epochs??[],codeless:!o||!s.some(u=>u.pushed)},e.step="ready",e.finishedAt=Date.now()}function yg(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 Bd(e,{toNode:t,mode:n="transfer"}={}){if(!t||typeof t!="string")throw new Error("toNode required");let r=await Q(),o=he(r,e);if(!o)throw new Error(`track "${e}" not found`);if(o.transferredTo)return{ok:!0,alreadyTransferred:o.transferredTo};Qw(e),await ag(e,o,n==="recover"?"track recovered onto another node":"track transferred to another node");let s=Date.now();yu(o,{at:s,reason:n==="recover"?"node-offline":"node-transfer"});let a=await bw({id:o.id,cwd:o.cwd});return o.transferredTo=t,o.transferredAt=s,$e(o,"transferred-out",{toNode:t,mode:n,box:o.leadBox,...a.pushed?{rescueRef:a.ref,rescueSha:a.sha}:{}}),await ce(),{ok:!0,toNode:t,rescue:a.pushed?{ref:a.ref,sha:a.sha}:null}}async function bg(e){let t=[];for(let n of Array.isArray(e)?e:[])if(!(!n?.id||!n?.toNode))try{let r=await Bd(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 a_(e,t,n){try{await wu(e,t,n)}catch{await mn(e,["worktree","prune"]).catch(()=>{}),await wu(e,t,n)}return t}function J4(e){if(typeof e!="string"||!V4.test(e)||e.includes("..")||e.includes("@{")||e.endsWith(".lock"))throw new Error("branch fails the safe-ref check")}async function kg(e={}){let{trackId:t,name:n,agent:r="claude",skipPermissions:o=!0,mode:s="transfer"}=e;if(!t||typeof t!="string"||!/^[0-9a-f]{8}$/.test(t))throw new Error("trackId (8-hex string) required");if(typeof n!="string"||!n.trim())throw new Error("name (string) required");if(s!=="transfer"&&s!=="recover")throw new Error(`unknown adopt mode "${s}"`);if(e.branch!=null&&J4(e.branch),Cw.has(t))throw new Error("an adopt is already running for this Track");Cw.set(t,{startedAt:Date.now()});try{return await Y4({...e,trackId:t,name:n,agent:r,skipPermissions:o,mode:s})}finally{Cw.delete(t)}}async function Y4({trackId:e,name:t,agent:n,skipPermissions:r,mode:o,fromNode:s=null,toNode:a=null,branch:i=null,repos:c=[],wip:l=null,brief:u=null,epochs:d=[],createdAt:p=null,leadBox:f=null,reason:w=null,downSince:m=null}){let g=await Ec(n,r),y=await Q(),x=he(y,e);if(x&&!x.transferredTo)throw new Error(`track "${e}" is already hosted on this node`);x&&(await bw({id:x.id,cwd:x.cwd}).catch(()=>{}),await T_(x),y.tracks.splice(y.tracks.indexOf(x),1),await ce()),await ee.mkdir(gc,{recursive:!0});let b=oe.join(gc,e);await ee.rm(b,{recursive:!0,force:!0}).catch(()=>{});let O=null,$=!1,C=[];try{let L=[];if(i)for(let W of Array.isArray(c)?c:[]){let te=typeof W=="string"?W:W?.repo;if(!te||!/^[^/\s]+\/[^/\s]+$/.test(te))continue;let le=await ws(te)??await bl(te);await mn(le,["fetch","origin",`+refs/heads/${i}:refs/heads/${i}`],Lw),L.push({slug:te,base:le,name:typeof W=="object"?W?.name??null:null})}if(i&&L.length===1){let{base:W,slug:te}=L[0];await a_(W,b,i),C.push({base:W,dir:b}),await xc(b);let le=await Gs(W);O={dir:b,base:W,branch:i,kind:"worktree",baseRef:le,repo:te}}else if(i&&L.length>=2){await ee.mkdir(b,{recursive:!0});let W=new Set([".bostrat"]),te=[];for(let le of L){let J=le.name||oe.basename(le.base);W.has(J)&&(J=le.slug.replace("/","-"));for(let Ne=2;W.has(J);Ne++)J=`${oe.basename(le.base)}-${Ne}`;W.add(J);let ye=oe.join(b,J);await a_(le.base,ye,i),C.push({base:le.base,dir:ye});let Ce=await Gs(le.base);te.push({name:J,dir:ye,base:le.base,baseRef:Ce,repo:le.slug})}await Rc(b,te,i),O={dir:b,kind:"multi",branch:i,repos:te}}else $=!0,await ee.mkdir(b,{recursive:!0}),await Cm(b),await xc(b),O={dir:b,base:null,branch:null,kind:"repo"};let q=!1,I=null,_=null;if(l?.sha&&O.kind==="worktree")try{await mn(b,["fetch","origin",gw(e)],Lw);let{stdout:W}=await mn(b,["rev-parse","FETCH_HEAD^"]),{stdout:te}=await mn(b,["rev-parse","HEAD"]),le=W.trim()===te.trim();le||await mn(b,["merge-base","--is-ancestor",te.trim(),W.trim()]).then(()=>!0,()=>!1)&&(await mn(b,["reset","--hard",W.trim()]),_={from:te.trim(),to:W.trim()},le=!0),le?(await mn(b,["read-tree","--reset","-u","FETCH_HEAD"]),await mn(b,["reset","-q"]),q=!0):I="snapshot does not parent the fetched branch head"}catch(W){I=String(W?.message||W).split(`
247
- `)[0]}else l?.sha&&(I="wip snapshots cover single-repo worktrees only");await zE({id:e,cwd:b}).catch(()=>({restored:!1}));let F=oe.join(b,Yo),V=null;(await Ml(b)).restored?V="checkpoint":typeof u=="string"&&u.trim()&&(await ee.mkdir(oe.dirname(F),{recursive:!0}),await ee.writeFile(F,u),V="brief");let E=new Set(y.tracks.flatMap(W=>(W.boxes||[]).map(te=>te.name))),N=null;f&&!E.has(f)&&!await ke(f).catch(()=>null)?N=f:(N=`${t.trim()} lead`,E.has(Fl(N))&&(N=`${t.trim().slice(0,50).trim()} ${e} lead`));let H=await Or(N,b,{agentCmd:g,agent:n});yi({cwd:H.cwd,sessionName:H.name,agent:n,agentCmd:g});let z=Date.now(),fe=mg(H,"lead","live"),me=(Array.isArray(d)?d:[]).filter(W=>W&&typeof W=="object").map(W=>({...W})),Se=me[me.length-1];Se&&Se.endedAt==null&&(Se.endedAt=z,Se.endReason==null&&(Se.endReason=o==="recover"?"node-offline":"node-transfer")),me.push({agent:n,sessionId:H.sessionId??null,pinned:H.pinned===!0,startedAt:z,endedAt:null}),fe.epochs=me;let Ae={id:e,name:t.trim(),cwd:H.cwd,workspace:O,leadBox:H.name,boxes:[fe],events:[],createdAt:Number.isFinite(p)?p:z,...V?{pendingHandoffHydrate:{artifact:Yo,at:z}}:{}};return $e(Ae,"transferred-in",{box:H.name,agent:n,fromNode:s,toNode:a,mode:o,reason:w,...o==="recover"?{downSince:Number.isFinite(m)?m:null}:{},branch:O.branch??null,wip:q,..._?{wipAdvanced:_}:{},epoch:me.length-1,name:Ae.name,cwd:Ae.cwd,workspace:{base:O.base??null,branch:O.branch??null,kind:O.kind,...O.baseRef?{baseRef:O.baseRef}:{},...O.repo?{repo:O.repo}:{},...O.repos?{repos:O.repos.map(({name:W,base:te,baseRef:le,repo:J})=>({name:W,base:te,baseRef:le,repo:J}))}:{}}}),y.tracks.push(Ae),await ce(),{...await Nt(Ae),adopt:{wipApplied:q,wipSkipped:I,..._?{wipAdvanced:_}:{},codeless:$,artifactSource:V}}}catch(L){for(let q of C)await Ot(q.base,q.dir).catch(()=>{});throw await ee.rm(b,{recursive:!0,force:!0}).catch(()=>{}),L}}async function I_(e,t,n){let r=await Q(),o=he(r,e);o&&(o.subtasks=o.subtasks||{},o.subtasks[t]={...o.subtasks[t]||{},...n},await ce())}async function ha(e,t){e.step=t,await Mc(e)}function $_(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 R_(e){return!!e&&!e.finishedAt&&!e.canceled&&e.step==="working"&&!!e.box&&!!e.dir&&!!e.base&&!!e.branch}async function e2(e,t,n){if(!R_(n)||Pt.has(t)||!await ke(n.box).catch(()=>null))return!1;try{await ee.access(n.dir)}catch{return!1}let o=await ke(e.leadBox).catch(()=>null);if(!o?.cwd)return!1;let s={...n,id:t,leadBox:e.leadBox,step:"working",canceled:!1,forceMerge:!1};return Pt.set(t,s),M_(s,o).catch(a=>O_(s,a)),!0}async function xg(){let e=await Q(),t=!1;for(let n of e.tracks||[]){for(let[r,o]of Object.entries(n.subtasks||{})){if(Pt.has(r))continue;if(await e2(n,r,o)){t=!0,$e(n,"subtask-resumed",{box:o.box,agent:o.agent,task:o.task,subtaskId:r,resumedStep:o.step}),await ie({flow:"subtask",phase:"resumed",trackId:n.id,subtaskId:r,box:o.box,branch:o.branch}).catch(()=>{});continue}let s=o.step,a=$_(o);if(!a)continue;t=!0,n.subtasks[r]=a;let i=n.boxes.find(c=>c.subtaskId===r);i&&!so.has(i.state)&&(i.state="canceled"),$e(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 ie({flow:"subtask",phase:"reconciled",trackId:n.id,subtaskId:r,outcome:a.step,recovered:a.recovered,box:o.box,branch:o.branch}).catch(()=>{}),await i_(n,o.box,o.dir)}for(let r of n.boxes){if(r.role!=="subtask"||so.has(r.state)||Pt.has(r.subtaskId)||n.subtasks?.[r.subtaskId])continue;t=!0,r.state="canceled";let o=r.subtaskId?oe.join(va,`${n.id}-${r.subtaskId}`):null;await ie({flow:"subtask",phase:"reaped-legacy-orphan",trackId:n.id,subtaskId:r.subtaskId,box:r.name}).catch(()=>{}),await i_(n,r.name,o)}}return t=await t2(e)||t,t&&await ce(),t}async function i_(e,t,n){if(t&&await rn(t).catch(()=>{}),!n)return;if(e.workspace?.kind==="multi"){for(let o of Bt(e.workspace)){let s=oe.join(n,o.name);await Ot(o.base,s).then(()=>!0,()=>!1)||await Ot(o.dir,s).catch(()=>{})}await ee.rm(n,{recursive:!0,force:!0}).catch(()=>{});return}let r=await ke(e.leadBox).catch(()=>null);r?.cwd&&await Ot(r.cwd,n).catch(()=>{})}async function t2(e){let t;try{t=await ee.readdir(va)}catch{return!1}let n=new Set;for(let o of e.tracks||[]){for(let s of Object.keys(o.subtasks||{}))n.add(`${o.id}-${s}`);for(let s of o.boxes||[])s.subtaskId&&n.add(`${o.id}-${s.subtaskId}`)}for(let o of Pt.values())o.dir&&n.add(oe.basename(o.dir));let r=!1;for(let o of t){if(n.has(o))continue;let s=oe.join(va,o),a=(e.tracks||[]).find(i=>o.startsWith(`${i.id}-`));if(a?.workspace?.kind==="multi"){for(let i of Bt(a.workspace))await Ot(i.base,oe.join(s,i.name)).catch(()=>{});await ee.rm(s,{recursive:!0,force:!0}).catch(()=>{})}else{let i=a?await ke(a.leadBox).catch(()=>null):null;i?.cwd?await Ot(i.cwd,s).catch(()=>{}):await ee.rm(s,{recursive:!0,force:!0}).catch(()=>{})}await ie({flow:"subtask",phase:"swept-orphan-worktree",dir:s}).catch(()=>{}),r=!0}return r}async function Sg(e,{agent:t,task:n,skipPermissions:r=!0,reason:o=null}={}){if(typeof n!="string"||!Hs(n))throw new Error("task (string) required");let s=await Ec(t,r),a=Po(t);if(a){let f=new Error(`can't delegate to ${t} \u2014 its ${a.window} spend limit is reached ($${a.spentUsd.toFixed(2)} of $${a.limitUsd.toFixed(2)})`);throw f.usageCap=a,f}let i=he(await Q(),e);if(!i)throw new Error(`track "${e}" not found`);let c=await ke(i.leadBox);if(!c)throw new Error(`lead box "${i.leadBox}" is not running`);if(!c.cwd)throw new Error("can't resolve the lead's working directory");let l=i.workspace?.kind==="multi",u=null;if(l){let f=Bt(i.workspace);if(!f.length)throw new Error("this multi-repo Track has no tagged repos to delegate into");for(let w of f)if(!w?.dir||!await qs(w.dir))throw new Error(`tagged checkout "${w?.name??"?"}" is missing from the lead workspace (${w?.dir??"no dir"})`);u=f.map(w=>({name:w.name,leadDir:w.dir,base:null}))}else if(!await qs(c.cwd))throw new Error(`subtask delegation needs the lead's workspace to be a git repo (got ${c.cwd})`);let d=Ad().slice(0,8),p={id:d,trackId:e,trackName:i.name,agent:t,task:Hs(n),skipPermissions:r,reason:p_(o),step:"snapshot",leadBox:i.leadBox,box:null,branch:`bostrat/${vg(i.name)}-${d}`,base:null,repos:u,dir:oe.join(va,`${e}-${d}`),stat:null,conflicts:[],applied:null,startedAt:Date.now(),finishedAt:null,error:null,canceled:!1,forceMerge:!1};return Pt.set(d,p),await Mc(p),n2(p,c,s).catch(f=>O_(p,f)),p}async function O_(e,t){e.failedStep=e.step,e.error=t instanceof Tc?"canceled":t?.message||String(t),e.step=t instanceof Tc?"canceled":"error",e.finishedAt=Date.now(),await Ag(e).catch(()=>{}),await Mc(e).catch(()=>{}),await a2(e).catch(()=>{})}function Ld(e){let t=Pt.get(e);if(!t)throw new Error(`subtask "${e}" not found`);if(t.finishedAt)throw new Error("subtask already finished");return t.canceled=!0,t}function Tg(e){let t=Pt.get(e);if(!t)throw new Error(`subtask "${e}" not found`);if(t.finishedAt)throw new Error("subtask already finished");if(t.step!=="working")throw new Error(`subtask is not waiting to merge (step: ${t.step})`);return t.forceMerge=!0,t}async function n2(e,t,n){if(await ha(e,"snapshot"),e.repos){for(let s of e.repos)s.base=await Ws(s.leadDir,`bostrat: snapshot for subtask ${e.id}`);await Mc(e)}else e.base=await Ws(t.cwd,`bostrat: snapshot for subtask ${e.id}`);if(await ha(e,"spawn"),await ee.mkdir(va,{recursive:!0}),e.repos){await ee.mkdir(e.dir,{recursive:!0});for(let a of e.repos)await Ks(a.leadDir,oe.join(e.dir,a.name),e.branch,a.base);let s=Bt((he(await Q(),e.trackId)||{}).workspace);await Rc(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 Ks(t.cwd,e.dir,e.branch,e.base),await xc(e.dir);await r2(e,t);let r=e.trackName.slice(0,38).trim(),o=await Or(`${r} ${e.agent} sub ${e.id}`,e.dir,{agentCmd:n,agent:e.agent});e.box=o.name,await o2(e,o),await f_(e.trackId,o.name,JU(e.task,!!e.repos),{kind:"subtask"}),await M_(e,t)}async function M_(e,t){await ha(e,"working");let n=oe.join(e.dir,Sd);if(await c2(n,e),e.canceled)throw new Tc;if(await ha(e,"merge"),e.repos){let s={files:0,insertions:0,deletions:0},a=[],i=[],c=!0;for(let l of e.repos){let u=oe.join(e.dir,l.name);await Mm(u,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:s_({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),l.stat=await Pm(l.leadDir,l.base,e.branch,ma),l.files=await Dm(l.leadDir,l.base,e.branch,ma);let d=await Bm(l.leadDir,l.base,e.branch,ma);l.applied=d.applied,l.conflicts=d.conflicts??[],s.files+=l.stat.files,s.insertions+=l.stat.insertions,s.deletions+=l.stat.deletions,a.push(...l.files.map(p=>oe.join(l.name,p))),i.push(...l.conflicts.map(p=>p.startsWith("patch did not apply cleanly")?`${l.name}: ${p}`:oe.join(l.name,p))),d.applied||(c=!1)}e.stat=s,e.files=a,e.conflicts=i,e.applied=c}else{await Mm(e.dir,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:s_({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),e.stat=await Pm(t.cwd,e.base,e.branch,ma),e.files=await Dm(t.cwd,e.base,e.branch,ma);let s=await Bm(t.cwd,e.base,e.branch,ma);e.applied=s.applied,e.conflicts=s.conflicts}await Mc(e);let r=await i2(e,t,n);await ha(e,"resume"),await f_(e.trackId,e.leadBox,YU(e.task,e.stat,e.conflicts,r),{kind:"subtask-resume"}),await ha(e,"reap"),await Ag(e),e.step="done";let o=Date.now();await I_(e.trackId,e.id,{...jd(e),finishedAt:o}),await s2(e,o),e.finishedAt=o}async function r2(e,t){let n=oe.join(e.dir,oe.dirname(yc));await ee.mkdir(n,{recursive:!0});let r="";try{r=await Xk(t.cwd,t.sessionId)}catch{}if(!r)try{r=await ee.readFile(oe.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}
249
+ ${a}`}async function Eg(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<gi()?!1:er(e.name)}async function Rc(e,t,n){return!t||e.archivedAt||Sr.has(t.state)?!1:(await ue({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 $t(t.name).catch(()=>{}),t.state="stopped",Pc(e))}async function Pc(e,{freshSession:t=!1,reason:n=null}={}){let r=e.boxes.find(a=>a.name===e.leadBox);if(!r)return!1;let o=Vw.get(r.name);if(o)return o;let s=l2(e,r,{freshSession:t,reason:n}).finally(()=>Vw.delete(r.name));return Vw.set(r.name,s),s}async function l2(e,t,{freshSession:n=!1,reason:r=null}={}){if(e.archivedAt||e.transferredTo||Sr.has(t.state)||await be(t.name))return!1;let o=n===!0,s=o?Pd():null,a=o?hi(tg(t.agent),s,t.name):jd(t.agent,t.sessionId,{cwd:t.cwd,peerName:t.name}),i=await ql(a);if(i===Ds)return Se(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:`agent "${t.agent}" is not installed on this box`}),!1;i===Bs&&console.warn(`[track] ${t.name}: could not confirm "${t.agent}" on PATH \u2014 relaunching anyway (launch verifier will catch a real miss)`);let c=o?{sessionId:t.sessionId??null,pinned:t.pinned===!0,epochs:JSON.parse(JSON.stringify(is(t)))}:null,l=Date.now();if(o){let u=is(t),d=u[u.length-1];d.endedAt==null&&(d.endedAt=l),d.endReason==null&&(d.endReason=r||"fresh-session"),u.push({agent:t.agent,sessionId:s,pinned:t.agent==="claude",startedAt:l,endedAt:null}),t.sessionId=s,t.pinned=t.agent==="claude"}try{let u=await _n(t.name,t.cwd,{agentCmd:a,agent:t.agent,resumeSessionId:t.sessionId,pinned:t.pinned===!0});return t.hookTokenHash=To(u.hookToken),Do({cwd:t.cwd,sessionName:t.name,agent:t.agent,agentCmd:a}),t.state="live",o&&Se(e,"lead-refreshed",{box:t.name,agent:t.agent,fromSessionId:c.sessionId,toSessionId:s,epoch:t.epochs.length-1,reason:r||"fresh-session"}),Se(e,"rehydrated",{box:t.name,agent:t.agent,...o?{fresh:!0}:{}}),!0}catch(u){return o&&(t.sessionId=c.sessionId,t.pinned=c.pinned,t.epochs=c.epochs),Se(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:String(u?.message||u)}),!1}}async function Vd(e,{freshSession:t=!1}={}){let n=await Q(),r=de(n,e);if(!r)throw new Error(`track "${e}" not found`);if(!r.archivedAt)throw new Error(`track "${e}" is not archived`);return delete r.archivedAt,$c.delete(e),Se(r,"unarchived",{}),await Pc(r,t?{freshSession:!0,reason:"loop-fire"}:{}),await ae(),Lt(r)}async function _g(e,t){let n=typeof t=="string"?t.trim():"";if(!n)throw new Error("name (non-empty string) required");if(n.length>eg)throw new Error(`name too long (max ${eg} chars)`);let r=await Q(),o=de(r,e);if(!o)throw new Error(`track "${e}" not found`);if(String(o.name||"").startsWith("\u21BB"))throw new Error("loop run Tracks are named by their loop \u2014 rename the loop on the Loops tab");if(n===o.name)return Lt(o);let s=o.name;return o.name=n,Se(o,"renamed",{from:s,to:n}),await ae(),Lt(o)}async function Ig(){let e=await Q(),t=0;for(let n of e.tracks||[])n.transferredTo&&Au(n,{at:n.transferredAt??Date.now()})&&t++;return t&&await ae(),t}async function $g(){let e=await Q(),t=new Set((await on()).map(s=>s.name)),n=new Set((e.tracks||[]).filter(s=>!je(s)).flatMap(s=>(s.boxes||[]).map(a=>a.name))),r=0,o=!1;for(let s of e.tracks||[])if(je(s))for(let a of s.boxes)t.has(a.name)&&!n.has(a.name)&&(await $t(a.name).catch(()=>{}),s.transferredTo?console.log(`[track] reaped orphan box ${a.name} on transferred-away track ${s.id} (\u2192 ${s.transferredTo})`):Se(s,"orphan-reaped",{box:a.name,agent:a.agent}),r++,o=!0),!Sr.has(a.state)&&a.state!=="stopped"&&(a.state="stopped",o=!0);return o&&await ae(),r}async function Jd(e,{freshSession:t=!1}={}){let n=await Q(),r=de(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it before restarting the lead`);Xd(r);let o=r.boxes.find(i=>i.name===r.leadBox);if(!o)throw new Error(`track "${e}" has no lead box`);if(Sr.has(o.state))throw new Error("lead box is terminal \u2014 nothing to restart");if(await be(r.leadBox)){let i=await Pe(r.leadBox,{lines:Ye}).catch(()=>"");if(Ti(o.agent,i))throw new Error("lead is mid-turn \u2014 retry when it goes idle");await $t(r.leadBox),o.state="stopped"}let a=await Pc(r,t?{freshSession:!0,reason:"loop-fire"}:{});if(await ae(),!a)throw new Error("rehydrate failed \u2014 see the track's rehydrate-failed event");return Lt(r)}async function Rg(e,t,n){let r=await ce(e);if(!r)throw new Error(`track "${e}" not found`);if(!t)throw new Error("unknown offer");let o=await K(r).catch(()=>[]);if(!o.some(i=>i.type==="box.fullscreen.detected"&&i.payload?.offerId===t))throw new Error("unknown offer");if(o.some(i=>i.type==="box.fullscreen.answered"&&i.payload?.offerId===t))throw new Error("offer already answered");return n&&await Jd(e),await M(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 v_(e,t){if(!e?.id||!t?.box)return[];let n=(e.boxes||[]).find(r=>r.name===t.box);return td({trackId:e.id,boxId:t.box,epoch:0,provider:n?.agent??t.agent??null})}function is(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 Cd(e,t){let n=await Q(),r=de(n,e);r&&(r.handoff={...r.handoff||{},...t},await ae())}function H_(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 Mg(){let e=await Q(),t=!1;for(let n of e.tracks||[]){let r=n.handoff,o=H_(n);if(!o)continue;t=!0;let s=!!r.toBox&&r.toBox===r.fromBox;if(s&&o.step==="error"){let c=await be(r.fromBox).catch(()=>null),l=n.boxes.find(u=>u.name===r.fromBox);if(c&&l&&c.agent===r.toAgent&&r.toAgent!==l.agent){let u=Date.now(),d=is(l),p=d[d.length-1],f=p.agent,w=p.sessionId??null;p.endedAt=u,r.reason&&(p.endReason=r.reason);let m=c.agent==="claude"&&!!c.sessionId;d.push({agent:r.toAgent,sessionId:c.sessionId||null,pinned:m,startedAt:u,endedAt:null}),l.agent=r.toAgent,l.sessionId=c.sessionId||null,l.pinned=m,l.state="live",n.pendingHandoffHydrate={artifact:uo,at:u},Se(n,"lead-handoff",{from:r.fromBox,to:r.fromBox,fromAgent:f,toAgent:r.toAgent,fromSessionId:w,toSessionId:c.sessionId||null,epoch:d.length-1,singleBox:!0,skipPermissions:r.skipPermissions,reason:r.reason??null,handoffStartedAt:r.startedAt,recovered:!0}),n.handoff={...r,step:"done",finishedAt:u,recovered:"swap adopted from live tmux tags after restart"},await ue({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 ue({flow:"lead-handoff",phase:"reconciled",trackId:n.id,outcome:o.step,recovered:o.recovered,fromBox:o.fromBox,toBox:o.toBox}).catch(()=>{}),i&&await $t(i).catch(()=>{}),a&&await $t(a).catch(()=>{})}return t&&await ae(),t}async function Yd(e,t,n=!0,r=null){let o=cs.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is already running for this Track");let s=de(await Q(),e);if(!s)throw new Error(`track "${e}" not found`);Oa(e,"handoff");let a=await Ra(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 be(s.leadBox);if(!c)throw new Error(`lead box "${s.leadBox}" is not running`);let l={trackId:e,step:"checkpoint",fromBox:s.leadBox,toAgent:t,skipPermissions:n,reason:__(r),toBox:s.leadBox,startedAt:Date.now(),finishedAt:null,error:null};return cs.set(e,l),await Cd(e,{step:l.step,fromBox:l.fromBox,toAgent:t,toBox:l.toBox,skipPermissions:n,startedAt:l.startedAt,finishedAt:null,error:null}),u2(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 Cd(e,{step:l.step,error:l.error,finishedAt:l.finishedAt}).catch(()=>{}),ue({flow:"lead-handoff",phase:"failed",trackId:e,step:l.step,error:l.error,fromBox:l.fromBox,toAgent:l.toAgent,toBox:l.toBox}).catch(()=>{})}),ue({flow:"lead-handoff",phase:"started",trackId:e,fromBox:l.fromBox,toAgent:t,cwd:c.cwd}).catch(()=>{}),l}async function u2(e,t,n,r,o){let s=async(_,C={})=>{e.step=_,console.log(`[lead-handoff ${e.trackId}] step \u2192 ${_}`),await Cd(e.trackId,{step:_,toBox:e.toBox}),await ue({flow:"lead-handoff",phase:_,trackId:e.trackId,fromBox:e.fromBox,toBox:e.toBox,toAgent:o,sessionName:C.sessionName,...C})};console.log(`[lead-handoff ${e.trackId}] ${e.fromBox}: ${n.agent} \u2192 ${o} IN PLACE`);let a=await Q(),i=de(a,e.trackId)?.boxes.find(_=>_.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 mu(e.fromBox,{timeoutMs:ng})}catch(_){e.checkpoint="reconstructed",await ue({flow:"lead-handoff",phase:"checkpoint-fallback",trackId:e.trackId,fromBox:e.fromBox,error:_?.message||String(_)}).catch(()=>{})}e.checkpoint!=="llm"&&(e.statusArtifact=await hu(e.trackId,n.cwd,{trackName:t.name||t.id}).catch(()=>null),await s("checkpoint-degraded",{sessionName:e.fromBox,checkpoint:e.checkpoint,statusArtifact:e.statusArtifact})),await s("swap",{cwd:n.cwd,agentCmd:r});let p=await Sm(e.fromBox,{agentCmd:r,agent:o});await s("hydrate",{sessionName:e.fromBox});let f=R0(p.launchCmd);await tr({cwd:n.cwd,sessionId:p.sessionId,sessionName:e.fromBox,agent:o,agentCmd:ls(o),launchEcho:f}).catch(_=>{if(_?.code!=="cli-not-running")throw _});let w=Qf(await Pe(e.fromBox,{lines:Ye}).catch(()=>""),f);if(!Po(o,w)){await s("rollback",{sessionName:e.fromBox,fromAgent:c});let _=jd(c,l,{skipPermissions:e.skipPermissions,cwd:n.cwd,peerName:e.fromBox});await Sm(e.fromBox,{agentCmd:_,agent:c,resumeSessionId:l,pinned:u});let C=await Q(),U=de(C,e.trackId);if(U){let B=U.boxes.find(T=>T.name===e.fromBox);B&&(B.state="live"),Se(U,"lead-handoff-failed",{box:e.fromBox,fromAgent:c,toAgent:o,reason:e.reason,error:`incoming ${o} CLI never drew its composer`,rolledBack:!0,handoffStartedAt:e.startedAt}),await ae()}throw new Error(`incoming ${o} CLI never drew its composer \u2014 rolled back to ${c} (--resume, context intact)`)}await s("commit");let m=await Q(),g=de(m,e.trackId);if(!g)throw new Error(`track "${e.trackId}" not found during handoff commit \u2014 was it deleted or archived mid-flight?`);let y=g.boxes.find(_=>_.name===e.fromBox);if(!y)throw new Error(`lead box row "${e.fromBox}" missing during handoff commit`);let x=Date.now(),b=is(y),R=b[b.length-1];R.endedAt=x,e.reason&&(R.endReason=e.reason),b.push({agent:o,sessionId:p.sessionId,pinned:p.pinned,startedAt:x,endedAt:null}),y.agent=o,y.sessionId=p.sessionId,y.pinned=p.pinned,y.state="live",y.role="lead",g.pendingHandoffHydrate={artifact:e.statusArtifact||uo,at:x},Se(g,"lead-handoff",{from:e.fromBox,to:e.fromBox,fromAgent:c,toAgent:o,fromSessionId:l,toSessionId:p.sessionId,epoch:b.length-1,singleBox:!0,forced:p.forced||void 0,skipPermissions:e.skipPermissions,reason:e.reason,handoffStartedAt:e.startedAt,checkpoint:e.checkpoint}),await ae(),await s("done",{sessionName:e.fromBox}),await Cd(e.trackId,{finishedAt:Date.now(),error:null}),e.finishedAt=Date.now()}async function Pg(e){let t=Nd.get(e);if(t&&!t.finishedAt)throw new Error("a transfer is already running for this Track");let n=await Q(),r=de(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error("track is archived \u2014 restore it before moving it");if(r.kind==="setup")throw new Error("setup boxes don't move");if(r.transferredTo)throw new Error(`track already transferred to ${r.transferredTo}`);let o=cs.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is running \u2014 retry when it settles");for(let a of Ct.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 Nd.set(e,s),d2(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 d2(e,t){let n=t.boxes.find(u=>u.name===t.leadBox)||null,r=n?await be(n.name).catch(()=>null):null;if(e.checkpoint="llm",!r||n&&Jr(n.agent))e.checkpoint=r?"skipped-capped":"skipped-dead";else try{await mu(t.leadBox,{timeoutMs:ng})}catch{e.checkpoint="reconstructed"}e.checkpoint!=="llm"&&await hu(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 Nt(t.workspace)){if(!u?.dir)continue;let d={name:u.name??null,repo:u.repo??null,baseSha:null,pushed:!1};try{await wn(u.dir,["push","origin",o],Cg);let{stdout:p}=await wn(u.dir,["rev-parse","HEAD"]);d.baseSha=p.trim(),d.pushed=!0}catch(p){d.error=String(p?.message||p).split(`
250
+ `)[0]}s.push(d)}e.step="wip";let a=await Pw(t,{force:!0}),i=await Q(),c=de(i,t.id),l=c?.boxes.find(u=>u.name===c.leadBox)||null;l&&is(l),await ae(),e.result={name:c?.name??t.name,agent:l?.agent??null,leadBox:c?.leadBox??t.leadBox,createdAt:c?.createdAt??null,branch:o,repos:s.filter(u=>u.pushed).map(({name:u,repo:d,baseSha:p})=>({name:u,repo:d,baseSha:p})),unpushed:s.filter(u=>!u.pushed).map(({name:u,repo:d,error:p})=>({name:u,repo:d,error:p})),wip:a.pushed[0]?{ref:a.pushed[0].ref,sha:a.pushed[0].sha}:null,wips:a.pushed,wipSkipped:a.skipped,checkpoint:e.checkpoint,epochs:l?.epochs??[],codeless:!o||!s.some(u=>u.pushed)},e.step="ready",e.finishedAt=Date.now()}function Xd(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 Zd(e,{toNode:t,mode:n="transfer"}={}){if(!t||typeof t!="string")throw new Error("toNode required");let r=await Q(),o=de(r,e);if(!o)throw new Error(`track "${e}" not found`);if(o.transferredTo)return{ok:!0,alreadyTransferred:o.transferredTo};fg(e),await Sg(e,o,n==="recover"?"track recovered onto another node":"track transferred to another node");let s=Date.now();Au(o,{at:s,reason:n==="recover"?"node-offline":"node-transfer"});let a=await Dw(o,{ts:s}),i=a.pushed[0]??null;return o.transferredTo=t,o.transferredAt=s,Se(o,"transferred-out",{toNode:t,mode:n,box:o.leadBox,...i?{rescueRef:i.ref,rescueSha:i.sha}:{},...a.pushed.length?{rescues:a.pushed}:{}}),await ae(),{ok:!0,toNode:t,rescue:i?{ref:i.ref,sha:i.sha}:null,rescues:a.pushed}}async function Dg(e){let t=[];for(let n of Array.isArray(e)?e:[])if(!(!n?.id||!n?.toNode))try{let r=await Zd(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 S_(e,t,n){try{await ji(e,t,n)}catch{await wn(e,["worktree","prune"]).catch(()=>{}),await ji(e,t,n)}return t}function p2(e,{wip:t=null,wips:n=null}={}){let r=Nt(e).filter(a=>a?.dir),o=Array.isArray(n)?n.filter(a=>a?.sha):[];if(!o.length)return t?.sha&&r.length===1?r:[];let s=r.filter(a=>o.some(i=>i.repo?i.repo===a.repo:i.name!=null&&i.name===a.name));return!s.length&&r.length===1&&o.length===1?r:s}async function f2(e,t){try{await wn(e,["fetch","origin",Nw(t)],Cg);let{stdout:n}=await wn(e,["rev-parse","FETCH_HEAD^"]),{stdout:r}=await wn(e,["rev-parse","HEAD"]),o=null,s=n.trim()===r.trim();return s||await wn(e,["merge-base","--is-ancestor",r.trim(),n.trim()]).then(()=>!0,()=>!1)&&(await wn(e,["reset","--hard",n.trim()]),o={from:r.trim(),to:n.trim()},s=!0),s?(await wn(e,["read-tree","--reset","-u","FETCH_HEAD"]),await wn(e,["reset","-q"]),{applied:!0,skipped:null,advanced:o}):{applied:!1,skipped:"snapshot does not parent the fetched branch head",advanced:null}}catch(n){return{applied:!1,skipped:String(n?.message||n).split(`
251
+ `)[0],advanced:null}}}function h2(e){if(typeof e!="string"||!m2.test(e)||e.includes("..")||e.includes("@{")||e.endsWith(".lock"))throw new Error("branch fails the safe-ref check")}async function Bg(e={}){let{trackId:t,name:n,agent:r="claude",skipPermissions:o=!0,mode:s="transfer"}=e;if(!t||typeof t!="string"||!/^[0-9a-f]{8}$/.test(t))throw new Error("trackId (8-hex string) required");if(typeof n!="string"||!n.trim())throw new Error("name (string) required");if(s!=="transfer"&&s!=="recover")throw new Error(`unknown adopt mode "${s}"`);if(e.branch!=null&&h2(e.branch),$d.has(t))throw new Error("an adopt is already running for this Track");$d.set(t,{startedAt:Date.now()});try{return await w2({...e,trackId:t,name:n,agent:r,skipPermissions:o,mode:s})}finally{$d.delete(t)}}async function w2({trackId:e,name:t,agent:n,skipPermissions:r,mode:o,fromNode:s=null,toNode:a=null,branch:i=null,repos:c=[],wip:l=null,wips:u=null,brief:d=null,epochs:p=[],createdAt:f=null,leadBox:w=null,reason:m=null,downSince:g=null}){let y=await Ra(n,r),x=await Q(),b=de(x,e);if(b&&!b.transferredTo)throw new Error(`track "${e}" is already hosted on this node`);b&&(await Dw(b).catch(()=>{}),await L_(b),x.tracks.splice(x.tracks.indexOf(b),1),await ae()),await V.mkdir(Ac,{recursive:!0});let R=z.join(Ac,e);await V.rm(R,{recursive:!0,force:!0}).catch(()=>{});let _=null,C=!1,U=[];try{let B=[];if(i)for(let X of Array.isArray(c)?c:[]){let Y=typeof X=="string"?X:X?.repo;if(!Y||!/^[^/\s]+\/[^/\s]+$/.test(Y))continue;let ie=await Is(Y)??await Sl(Y);await wn(ie,["fetch","origin",`+refs/heads/${i}:refs/heads/${i}`],Cg),B.push({slug:Y,base:ie,name:typeof X=="object"?X?.name??null:null})}if(i&&B.length===1){let{base:X,slug:Y}=B[0];await S_(X,R,i),U.push({base:X,dir:R}),await Ic(R);let ie=await qo(X);_={dir:R,base:X,branch:i,kind:"worktree",baseRef:ie,repo:Y}}else if(i&&B.length>=2){await V.mkdir(R,{recursive:!0});let X=new Set([".bostrat"]),Y=[];for(let ie of B){let ve=ie.name||z.basename(ie.base);X.has(ve)&&(ve=ie.slug.replace("/","-"));for(let D=2;X.has(ve);D++)ve=`${z.basename(ie.base)}-${D}`;X.add(ve);let Ne=z.join(R,ve);await S_(ie.base,Ne,i),U.push({base:ie.base,dir:Ne});let O=await qo(ie.base);Y.push({name:ve,dir:Ne,base:ie.base,baseRef:O,repo:ie.slug})}await Ma(R,Y,i),_={dir:R,kind:"multi",branch:i,repos:Y}}else C=!0,await V.mkdir(R,{recursive:!0}),await Vm(R),await Ic(R),_={dir:R,base:null,branch:null,kind:"repo"};let T=[];for(let X of p2(_,{wip:l,wips:u})){let Y=await f2(X.dir,e);T.push({name:X.name,repo:X.repo,applied:Y.applied,skipped:Y.skipped,...Y.advanced?{advanced:Y.advanced}:{}})}let $=T.some(X=>X.applied),L=T.length===1?T[0].skipped:T.filter(X=>X.skipped).map(X=>`${X.name??X.repo}: ${X.skipped}`).join("; ")||null,J=T.length===1?T[0].advanced??null:null;await l_({id:e,cwd:R}).catch(()=>({restored:!1}));let A=z.join(R,uo),S=null;(await Bl(R)).restored?S="checkpoint":typeof d=="string"&&d.trim()&&(await V.mkdir(z.dirname(A),{recursive:!0}),await V.writeFile(A,d),S="brief");let H=new Set(x.tracks.flatMap(X=>(X.boxes||[]).map(Y=>Y.name))),q=null;w&&!H.has(w)&&!await be(w).catch(()=>null)?q=w:(q=`${t.trim()} lead`,H.has(Kl(q))&&(q=`${t.trim().slice(0,50).trim()} ${e} lead`));let re=await _n(q,R,{agentCmd:y,agent:n});Do({cwd:re.cwd,sessionName:re.name,agent:n,agentCmd:y});let we=Date.now(),Re=Og(re,"lead","live"),Ee=(Array.isArray(p)?p:[]).filter(X=>X&&typeof X=="object").map(X=>({...X})),Z=Ee[Ee.length-1];Z&&Z.endedAt==null&&(Z.endedAt=we,Z.endReason==null&&(Z.endReason=o==="recover"?"node-offline":"node-transfer")),Ee.push({agent:n,sessionId:re.sessionId??null,pinned:re.pinned===!0,startedAt:we,endedAt:null}),Re.epochs=Ee;let ye={id:e,name:t.trim(),cwd:re.cwd,workspace:_,leadBox:re.name,boxes:[Re],events:[],createdAt:Number.isFinite(f)?f:we,...S?{pendingHandoffHydrate:{artifact:uo,at:we}}:{}};return Se(ye,"transferred-in",{box:re.name,agent:n,fromNode:s,toNode:a,mode:o,reason:m,...o==="recover"?{downSince:Number.isFinite(g)?g:null}:{},branch:_.branch??null,wip:$,...J?{wipAdvanced:J}:{},..._.kind==="multi"&&T.length?{wipRepos:T}:{},epoch:Ee.length-1,name:ye.name,cwd:ye.cwd,workspace:{base:_.base??null,branch:_.branch??null,kind:_.kind,..._.baseRef?{baseRef:_.baseRef}:{},..._.repo?{repo:_.repo}:{},..._.repos?{repos:_.repos.map(({name:X,base:Y,baseRef:ie,repo:ve})=>({name:X,base:Y,baseRef:ie,repo:ve}))}:{}}}),x.tracks.push(ye),await ae(),{...await Lt(ye),adopt:{wipApplied:$,wipSkipped:L,...J?{wipAdvanced:J}:{},..._.kind==="multi"?{wipRepos:T}:{},codeless:C,artifactSource:S}}}catch(B){for(let T of U)await xt(T.base,T.dir).catch(()=>{});throw await V.rm(R,{recursive:!0,force:!0}).catch(()=>{}),B}}async function W_(e,t,n){let r=await Q(),o=de(r,e);o&&(o.subtasks=o.subtasks||{},o.subtasks[t]={...o.subtasks[t]||{},...n},await ae())}async function Aa(e,t){e.step=t,await Dc(e)}function q_(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 K_(e){return!!e&&!e.finishedAt&&!e.canceled&&e.step==="working"&&!!e.box&&!!e.dir&&!!e.base&&!!e.branch}async function k2(e,t,n){if(!K_(n)||Ct.has(t)||!await be(n.box).catch(()=>null))return!1;try{await V.access(n.dir)}catch{return!1}let o=await be(e.leadBox).catch(()=>null);if(!o?.cwd)return!1;let s={...n,id:t,leadBox:e.leadBox,step:"working",canceled:!1,forceMerge:!1};return Ct.set(t,s),z_(s,o).catch(a=>G_(s,a)),!0}async function jg(){let e=await Q(),t=!1;for(let n of e.tracks||[]){for(let[r,o]of Object.entries(n.subtasks||{})){if(Ct.has(r))continue;if(await k2(n,r,o)){t=!0,Se(n,"subtask-resumed",{box:o.box,agent:o.agent,task:o.task,subtaskId:r,resumedStep:o.step}),await ue({flow:"subtask",phase:"resumed",trackId:n.id,subtaskId:r,box:o.box,branch:o.branch}).catch(()=>{});continue}let s=o.step,a=q_(o);if(!a)continue;t=!0,n.subtasks[r]=a;let i=n.boxes.find(c=>c.subtaskId===r);i&&!Sr.has(i.state)&&(i.state="canceled"),Se(n,"subtask-failed",{from:o.box,fromAgent:o.agent,task:o.task,subtaskId:r,failedStep:s,error:a.error,recovered:a.recovered,durationMs:o.startedAt?a.finishedAt-o.startedAt:null}),await ue({flow:"subtask",phase:"reconciled",trackId:n.id,subtaskId:r,outcome:a.step,recovered:a.recovered,box:o.box,branch:o.branch}).catch(()=>{}),await A_(n,o.box,o.dir)}for(let r of n.boxes){if(r.role!=="subtask"||Sr.has(r.state)||Ct.has(r.subtaskId)||n.subtasks?.[r.subtaskId])continue;t=!0,r.state="canceled";let o=r.subtaskId?z.join($a,`${n.id}-${r.subtaskId}`):null;await ue({flow:"subtask",phase:"reaped-legacy-orphan",trackId:n.id,subtaskId:r.subtaskId,box:r.name}).catch(()=>{}),await A_(n,r.name,o)}}return t=await x2(e)||t,t&&await ae(),t}async function A_(e,t,n){if(t&&await $t(t).catch(()=>{}),!n)return;if(e.workspace?.kind==="multi"){for(let o of Nt(e.workspace)){let s=z.join(n,o.name);await xt(o.base,s).then(()=>!0,()=>!1)||await xt(o.dir,s).catch(()=>{})}await V.rm(n,{recursive:!0,force:!0}).catch(()=>{});return}let r=await be(e.leadBox).catch(()=>null);r?.cwd&&await xt(r.cwd,n).catch(()=>{})}async function x2(e){let t;try{t=await V.readdir($a)}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 Ct.values())o.dir&&n.add(z.basename(o.dir));let r=!1;for(let o of t){if(n.has(o))continue;let s=z.join($a,o),a=(e.tracks||[]).find(i=>o.startsWith(`${i.id}-`));if(a?.workspace?.kind==="multi"){for(let i of Nt(a.workspace))await xt(i.base,z.join(s,i.name)).catch(()=>{});await V.rm(s,{recursive:!0,force:!0}).catch(()=>{})}else{let i=a?await be(a.leadBox).catch(()=>null):null;i?.cwd?await xt(i.cwd,s).catch(()=>{}):await V.rm(s,{recursive:!0,force:!0}).catch(()=>{})}await ue({flow:"subtask",phase:"swept-orphan-worktree",dir:s}).catch(()=>{}),r=!0}return r}async function Lg(e,{agent:t,task:n,skipPermissions:r=!0,reason:o=null}={}){if(typeof n!="string"||!Qs(n))throw new Error("task (string) required");let s=await Ra(t,r),a=Jr(t);if(a){let f=new Error(`can't delegate to ${t} \u2014 its ${a.window} spend limit is reached ($${a.spentUsd.toFixed(2)} of $${a.limitUsd.toFixed(2)})`);throw f.usageCap=a,f}let i=de(await Q(),e);if(!i)throw new Error(`track "${e}" not found`);let c=await be(i.leadBox);if(!c)throw new Error(`lead box "${i.leadBox}" is not running`);if(!c.cwd)throw new Error("can't resolve the lead's working directory");let l=i.workspace?.kind==="multi",u=null;if(l){let f=Nt(i.workspace);if(!f.length)throw new Error("this multi-repo Track has no tagged repos to delegate into");for(let w of f)if(!w?.dir||!await ea(w.dir))throw new Error(`tagged checkout "${w?.name??"?"}" is missing from the lead workspace (${w?.dir??"no dir"})`);u=f.map(w=>({name:w.name,leadDir:w.dir,base:null}))}else if(!await ea(c.cwd))throw new Error(`subtask delegation needs the lead's workspace to be a git repo (got ${c.cwd})`);let d=Pd().slice(0,8),p={id:d,trackId:e,trackName:i.name,agent:t,task:Qs(n),skipPermissions:r,reason:__(o),step:"snapshot",leadBox:i.leadBox,box:null,branch:`bostrat/${ep(i.name)}-${d}`,base:null,repos:u,dir:z.join($a,`${e}-${d}`),stat:null,conflicts:[],applied:null,startedAt:Date.now(),finishedAt:null,error:null,canceled:!1,forceMerge:!1};return Ct.set(d,p),await Dc(p),v2(p,c,s).catch(f=>G_(p,f)),p}async function G_(e,t){e.failedStep=e.step,e.error=t instanceof Oc?"canceled":t?.message||String(t),e.step=t instanceof Oc?"canceled":"error",e.finishedAt=Date.now(),await Ug(e).catch(()=>{}),await Dc(e).catch(()=>{}),await E2(e).catch(()=>{})}function tp(e){let t=Ct.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 Fg(e){let t=Ct.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 v2(e,t,n){if(await Aa(e,"snapshot"),e.repos){for(let s of e.repos)s.base=await ta(s.leadDir,`bostrat: snapshot for subtask ${e.id}`);await Dc(e)}else e.base=await ta(t.cwd,`bostrat: snapshot for subtask ${e.id}`);if(await Aa(e,"spawn"),await V.mkdir($a,{recursive:!0}),e.repos){await V.mkdir(e.dir,{recursive:!0});for(let a of e.repos)await Wo(a.leadDir,z.join(e.dir,a.name),e.branch,a.base);let s=Nt((de(await Q(),e.trackId)||{}).workspace);await Ma(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 Wo(t.cwd,e.dir,e.branch,e.base),await Ic(e.dir);await S2(e,t);let r=e.trackName.slice(0,38).trim(),o=await _n(`${r} ${e.agent} sub ${e.id}`,e.dir,{agentCmd:n,agent:e.agent});e.box=o.name,await A2(e,o),await I_(e.trackId,o.name,p4(e.task,!!e.repos),{kind:"subtask"}),await z_(e,t)}async function z_(e,t){await Aa(e,"working");let n=z.join(e.dir,Rd);if(await I2(n,e),e.canceled)throw new Oc;if(await Aa(e,"merge"),e.repos){let s={files:0,insertions:0,deletions:0},a=[],i=[],c=!0;for(let l of e.repos){let u=z.join(e.dir,l.name);await Gm(u,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:v_({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),l.stat=await Ym(l.leadDir,l.base,e.branch,Sa),l.files=await Xm(l.leadDir,l.base,e.branch,Sa);let d=await Zm(l.leadDir,l.base,e.branch,Sa);l.applied=d.applied,l.conflicts=d.conflicts??[],s.files+=l.stat.files,s.insertions+=l.stat.insertions,s.deletions+=l.stat.deletions,a.push(...l.files.map(p=>z.join(l.name,p))),i.push(...l.conflicts.map(p=>p.startsWith("patch did not apply cleanly")?`${l.name}: ${p}`:z.join(l.name,p))),d.applied||(c=!1)}e.stat=s,e.files=a,e.conflicts=i,e.applied=c}else{await Gm(e.dir,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:v_({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),e.stat=await Ym(t.cwd,e.base,e.branch,Sa),e.files=await Xm(t.cwd,e.base,e.branch,Sa);let s=await Zm(t.cwd,e.base,e.branch,Sa);e.applied=s.applied,e.conflicts=s.conflicts}await Dc(e);let r=await _2(e,t,n);await Aa(e,"resume"),await I_(e.trackId,e.leadBox,f4(e.task,e.stat,e.conflicts,r),{kind:"subtask-resume"}),await Aa(e,"reap"),await Ug(e),e.step="done";let o=Date.now();await W_(e.trackId,e.id,{...Qd(e),finishedAt:o}),await T2(e,o),e.finishedAt=o}async function S2(e,t){let n=z.join(e.dir,z.dirname(Tc));await V.mkdir(n,{recursive:!0});let r="";try{r=await f0(t.cwd,t.sessionId)}catch{}if(!r)try{r=await V.readFile(z.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}
248
252
 
249
253
  **Delegated task:** ${e.task}
250
254
 
@@ -255,15 +259,15 @@ ${a}`}async function lg(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<
255
259
  ## Conversation so far (lead \u2192 you)
256
260
 
257
261
  ${r}
258
- `;await ee.writeFile(oe.join(e.dir,yc),o)}async function o2(e,t){let n=await Q(),r=he(n,e.trackId);r&&(r.boxes.push({name:t.name,agent:t.agent,role:"subtask",state:"live",cwd:t.cwd,sessionId:t.sessionId,hookTokenHash:Ha(t.hookToken),createdAt:Date.now(),subtaskId:e.id,branch:e.branch,task:e.task}),$e(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]||{},...jd(e)},await ce())}async function s2(e,t=e.finishedAt){let n=await Q(),r=he(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),$e(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 ce()}async function a2(e){let t=await Q(),n=he(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"),$e(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]||{},...jd(e)},await ce()}async function i2(e,t,n){let r=`.bostrat/handoff/subtask-${e.id}.md`;try{let o=oe.join(t.cwd,r);await ee.mkdir(oe.dirname(o),{recursive:!0}),await ee.copyFile(n,o)}catch{}return r}async function Ag(e){if(e.dir&&await Qp(e.dir).catch(()=>{}),e.box&&await rn(e.box).catch(()=>{}),e.repos&&e.dir){for(let t of e.repos)await Ot(t.leadDir,oe.join(e.dir,t.name)).catch(()=>{});await ee.rm(e.dir,{recursive:!0,force:!0}).catch(()=>{})}else if(e.dir){let n=(await ke(e.leadBox).catch(()=>null))?.cwd;n&&await Ot(n,e.dir).catch(()=>{})}}async function c2(e,t){let n=(t.startedAt||Date.now())+X4;for(;;){if(t.canceled||t.forceMerge)return;try{await ee.access(e);return}catch{}if(Date.now()>n)throw new Error("subtask timed out without signaling completion (no result digest written)");await br(Z4)}}function br(e){return new Promise(t=>setTimeout(t,e))}var c_,Hn,l_,GU,gc,zU,Ed,Ac,oo,Yo,u_,VU,Sd,yc,JU,YU,Xt,Ew,he,_w,$e,Iw,$w,QU,so,t_,n4,r4,o4,s4,n_,hc,d4,ya,r_,g4,y4,b4,k4,x4,wa,bc,A4,_4,I4,O4,x_,kc,v_,P4,wc,Rw,D4,Ow,F4,vc,U4,H4,o_,Mw,jw,mg,xa,Ta,Lw,mn,Fw,wg,V4,Cw,X4,Z4,va,ma,Pt,Q4,es,jd,Mc,vg,Tc,cr=G(()=>{Xa();ct();om();Mx();bi();Er();zl();Bx();pt();Tn();fs();Gl();ym();Io();_m();$m();bv();vi();Hf();Vl();Xf();an();gu();Tr();Gt();ki();vu();Gv();Hm();iA();su();ru();lA();Nh();de();Bh();Xu();dd();qi();Do();ic();da();lw();yd();ww();Rn();od();HE();kw();VE();Cl();ZE();Sw();Aw();c_=KU(WU),Hn=process.env.BOSTRAT_STATE_DIR||oe.join(process.env.HOME||"/tmp",".bostrat"),l_=oe.join(Hn,"tracks.json"),GU=oe.join(Hn,"events.jsonl"),gc=oe.join(Hn,"workspaces"),zU=process.env.BOSTRAT_DEFAULT_REPO||null,Ed={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"}},Ac=Object.keys(Ed);oo={at:0,value:null};Yo=".bostrat/handoff/latest.md",u_=Number(process.env.BOSTRAT_HANDOFF_CHECKPOINT_TIMEOUT_MS)||9e4;VU=/\(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\.\)$/;Sd=".bostrat/handoff/subtask-result.md",yc=".bostrat/handoff/lead-context.md",JU=(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 ${yc} \u2014 read that first for context. Your scoped task:
262
+ `;await V.writeFile(z.join(e.dir,Tc),o)}async function A2(e,t){let n=await Q(),r=de(n,e.trackId);r&&(r.boxes.push({name:t.name,agent:t.agent,role:"subtask",state:"live",cwd:t.cwd,sessionId:t.sessionId,hookTokenHash:To(t.hookToken),createdAt:Date.now(),subtaskId:e.id,branch:e.branch,task:e.task}),Se(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]||{},...Qd(e)},await ae())}async function T2(e,t=e.finishedAt){let n=await Q(),r=de(n,e.trackId);if(!r)return;let o=r.boxes.find(s=>s.subtaskId===e.id);o&&(o.state=e.conflicts.length?"conflict":"merged",o.stat=e.stat),Se(r,"subtask-merged",{from:e.box,fromAgent:e.agent,task:e.task,subtaskId:e.id,stat:e.stat,conflicts:e.conflicts.length,files:e.files,durationMs:t?t-e.startedAt:null}),await ae()}async function E2(e){let t=await Q(),n=de(t,e.trackId);if(!n)return;let r=e.canceled||e.error==="canceled",o=n.boxes.find(s=>s.subtaskId===e.id);o&&(o.state=r?"canceled":"failed"),Se(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]||{},...Qd(e)},await ae()}async function _2(e,t,n){let r=`.bostrat/handoff/subtask-${e.id}.md`;try{let o=z.join(t.cwd,r);await V.mkdir(z.dirname(o),{recursive:!0}),await V.copyFile(n,o)}catch{}return r}async function Ug(e){if(e.dir&&await Ml(e.dir).catch(()=>{}),e.box&&await $t(e.box).catch(()=>{}),e.repos&&e.dir){for(let t of e.repos)await xt(t.leadDir,z.join(e.dir,t.name)).catch(()=>{});await V.rm(e.dir,{recursive:!0,force:!0}).catch(()=>{})}else if(e.dir){let n=(await be(e.leadBox).catch(()=>null))?.cwd;n&&await xt(n,e.dir).catch(()=>{})}}async function I2(e,t){let n=(t.startedAt||Date.now())+g2;for(;;){if(t.canceled||t.forceMerge)return;try{await V.access(e);return}catch{}if(Date.now()>n)throw new Error("subtask timed out without signaling completion (no result digest written)");await Ar(y2)}}function Ar(e){return new Promise(t=>setTimeout(t,e))}var Dd,Kn,T_,l4,Ac,u4,Bd,Mc,lo,uo,ng,d4,Rd,Tc,p4,f4,Mt,Ww,de,qw,Se,Kw,Gw,w4,Sr,g_,b4,k4,x4,v4,y_,xc,I4,_a,b_,N4,P4,D4,B4,j4,Ta,Ec,H4,q4,K4,V4,gg,Qw,yg,ht,hn,Md,_c,D_,e2,vc,Sc,t2,zw,o2,$c,s2,a2,x_,Vw,eg,Og,cs,Ca,Cg,wn,Nd,Ng,m2,$d,g2,y2,$a,Sa,Ct,b2,ps,Qd,Dc,ep,Oc,pr=G(()=>{si();ct();gm();Vx();Ei();Or();Zl();ev();ft();En();Ts();Xl();Mm();No();Um();Wm();Dv();$i();rm();Ql();pm();cn();Su();$r();Jt();_i();Iu();iS();oh();vT();uu();cu();AT();Yh();fe();Qh();rd();gd();Ji();Go();fc();ka();Ew();Ad();Cw();Cn();ud();n_();Bw();u_();jl();m_();Fw();Hw();Dd=c4(i4),Kn=process.env.BOSTRAT_STATE_DIR||z.join(process.env.HOME||"/tmp",".bostrat"),T_=z.join(Kn,"tracks.json"),l4=z.join(Kn,"events.jsonl"),Ac=z.join(Kn,"workspaces"),u4=process.env.BOSTRAT_DEFAULT_REPO||null,Bd={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"}},Mc=Object.keys(Bd);lo={at:0,value:null};uo=".bostrat/handoff/latest.md",ng=Number(process.env.BOSTRAT_HANDOFF_CHECKPOINT_TIMEOUT_MS)||9e4;d4=/\(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\.\)$/;Rd=".bostrat/handoff/subtask-result.md",Tc=".bostrat/handoff/lead-context.md",p4=(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 ${Tc} \u2014 read that first for context. Your scoped task:
259
263
 
260
264
  ${e}
261
265
 
262
- 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 ${Sd} (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 ${yc} \u2014 read that first for context. Your scoped task:
266
+ 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 ${Rd} (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 ${Tc} \u2014 read that first for context. Your scoped task:
263
267
 
264
268
  ${e}
265
269
 
266
- 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 ${Sd} 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.`,YU=(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."),Xt=null,Ew=null;he=(e,t)=>e.tracks.find(n=>n.id===t)||null,_w=Promise.resolve();$e=(e,t,n={})=>{let r={at:Date.now(),type:t,...n};return e.events.push(r),XU(e.id,r),Jv(e,r),r};t0(async({sessionName:e,from:t,to:n,version:r,status:o,error:s})=>{let i=(await Q()).tracks.find(c=>c.leadBox===e||(c.boxes||[]).some(l=>l.name===e));i&&($e(i,"codex-update",{box:e,from:t,to:r||n,status:o,...s?{error:s}:{}}),await ce().catch(()=>{}))});Iw=oe.join(Hn,"plane-link","update-notice.json");$w=(e,t,n)=>t!=null&&n.some(r=>e===r.box&&t>=r.from&&t<=r.to),QU=new Set(["stuck","wrong-approach","too-slow","want-different-model","context-refresh","cost","parallelize","other"]);so=new Set(["merged","conflict","canceled","failed","handed-off"]),t_=new Map;n4=5e3;r4={claude:[/^\[Request interrupted by user(?: for tool use)?\]$/i],codex:[/^\[?Request interrupted/i,/^Conversation interrupted/i],cursor:[/^\[?Request interrupted/i]};o4=[/^\/model(?:\s|$)/i,/<command-(?:name|message|args)>[^<]*\bmodel\b/i,/^Model changed to\b/i];s4=10*6e4;n_=400;hc=new Map;d4=1500,ya=new Map;r_="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.";g4=4e3,y4=3,b4=[300,350,400],k4=1e3,x4=12,wa=new Map,bc=new Map;A4=[250,400,500,600];_4=3e4,I4=[350,650,900];O4=12e4;x_=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}))});kc="# bostrat workspace",v_=`${kc}
270
+ 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 ${Rd} 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.`,f4=(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."),Mt=null,Ww=null;de=(e,t)=>e.tracks.find(n=>n.id===t)||null,qw=Promise.resolve();Se=(e,t,n={})=>{let r={at:Date.now(),type:t,...n};return e.events.push(r),m4(e.id,r),uS(e,r),r};g0(async({sessionName:e,from:t,to:n,version:r,status:o,error:s})=>{let i=(await Q()).tracks.find(c=>c.leadBox===e||(c.boxes||[]).some(l=>l.name===e));i&&(Se(i,"codex-update",{box:e,from:t,to:r||n,status:o,...s?{error:s}:{}}),await ae().catch(()=>{}))});Kw=z.join(Kn,"plane-link","update-notice.json");Gw=(e,t,n)=>t!=null&&n.some(r=>e===r.box&&t>=r.from&&t<=r.to),w4=new Set(["stuck","wrong-approach","too-slow","want-different-model","context-refresh","cost","parallelize","other"]);Sr=new Set(["merged","conflict","canceled","failed","handed-off"]),g_=new Map;b4=5e3;k4={claude:[/^\[Request interrupted by user(?: for tool use)?\]$/i],codex:[/^\[?Request interrupted/i,/^Conversation interrupted/i],cursor:[/^\[?Request interrupted/i]};x4=[/^\/model(?:\s|$)/i,/<command-(?:name|message|args)>[^<]*\bmodel\b/i,/^Model changed to\b/i];v4=10*6e4;y_=400;xc=new Map;I4=1500,_a=new Map;b_="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.";N4=4e3,P4=3,D4=[300,350,400],B4=1e3,j4=12,Ta=new Map,Ec=new Map;H4=[250,400,500,600];q4=3e4,K4=[350,650,900];V4=12e4;gg=e=>({branch:e.branch,kind:e.kind,repos:(e.repos??[]).filter(Boolean).map(({name:t,base:n,baseRef:r,repo:o})=>({name:t,base:n,baseRef:r,repo:o}))});Qw=new Map,yg=e=>Qw.get(e)||(Mt?de(Mt,e)?.reshape:null)||null,ht=(e,t=409)=>Object.assign(new Error(e),{status:t});hn=e=>V.access(e).then(()=>!0,()=>!1),Md=(e,t,n)=>Dd("git",["-C",e,"worktree","move","--end-of-options",t,n],{timeout:6e4});_c="# bostrat workspace",D_=`${_c}
267
271
 
268
272
  TRACK MEMORY: if \`.bostrat/memory/MEMORY.md\` exists in your workspace, read it
269
273
  before substantive work \u2014 it is the shared cross-provider memory for this repo
@@ -641,16 +645,16 @@ for the same follow-up at the same moment twice; run bostrat-followup ls first
641
645
  specifics (no PR numbers, URLs, SHAs, tags \u2014 the card supplies them), and HOLD
642
646
  HERE after proposing until the operator answers the card. Bostrat never runs a
643
647
  follow-up on its own; the operator's tap is the gate.
644
- `,P4=v_,wc=v_+W0;Rw=e=>typeof e=="string"&&(e===kc||e.startsWith(`${kc}
645
- `)),D4="# bostrat multi-repo workspace";Ow=wc.replace(`${kc}
646
- `,`${kc}
648
+ `,e2=D_,vc=D_+ax;Sc=e=>typeof e=="string"&&(e===_c||e.startsWith(`${_c}
649
+ `)),t2="# bostrat multi-repo workspace";zw=vc.replace(`${_c}
650
+ `,`${_c}
647
651
 
648
652
  (Global copy managed by bostrat \u2014 rewritten on service start; edits will be lost.)
649
653
  SCOPE: these instructions apply ONLY when your working directory is under
650
654
  ~/.bostrat/workspaces/ or ~/.bostrat/worktrees/ \u2014 a bostrat-orchestrated box.
651
655
  When working anywhere else, ignore everything below.
652
- `);F4=new Set(["claude","codex","cursor"]);vc=new Set,U4=e=>vc.has(e);H4=9e4;o_={merged:"merged",closed:"closed on GitHub WITHOUT merging",lost:"no longer found on GitHub (deleted, or its repo left the grant)"};Mw=new Map;jw=120;mg=(e,t,n)=>({name:e.name,agent:e.agent,role:t,state:n,cwd:e.cwd,sessionId:e.sessionId,pinned:e.pinned===!0,hookTokenHash:Ha(e.hookToken),createdAt:Date.now()});xa=new Map,Ta=e=>xa.get(e)||(Xt?he(Xt,e)?.handoff:null)||null;Lw=6e4,mn=(e,t,n=15e3)=>c_("git",["-C",e,...t],{timeout:n,maxBuffer:8*1024*1024}),Fw=new Map,wg=e=>Fw.get(e)||null;V4=/^[A-Za-z0-9][A-Za-z0-9._/-]{0,200}$/;Cw=new Map;X4=Number(process.env.BOSTRAT_SUBTASK_TIMEOUT_MS)||18e5,Z4=Number(process.env.BOSTRAT_SUBTASK_POLL_MS)||3e3,va=oe.join(Hn,"worktrees"),ma=[yc,Sd],Pt=new Map,Q4=e=>Pt.get(e)||(Xt?Xt.tracks.map(t=>t.subtasks?.[e]).find(Boolean):null)||null,es=e=>{let t=new Map([...Pt.values()].filter(r=>r.trackId===e).map(r=>[r.id,r])),n=Xt?he(Xt,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)},jd=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});Mc=e=>I_(e.trackId,e.id,jd(e));vg=e=>e.trim().replace(/\s+/g,"-").replace(/[^A-Za-z0-9._-]/g,"").toLowerCase()||"track",Tc=class extends Error{}});ct();import Te from"node:path";import gt from"node:fs";import r6 from"node:readline";import{fileURLToPath as o6}from"node:url";import Ut from"express";import s6 from"node:http";import a6 from"node:https";import $p from"node:os";import{randomUUID as i6}from"node:crypto";import{WebSocketServer as c6}from"ws";ct();import tN from"node-pty";async function $k(e,t,n={}){if(!je(t)){Wl(e,`invalid session name: ${t}`),e.close(1008,"invalid session name");return}if(!await Rr()){Wl(e,`host tmux server not running on ${Rt}`),e.close(1011,"tmux server unavailable");return}if(!await ke(t)){Wl(e,`session "${t}" not found`),e.close(1008,"session not found");return}let r=Ik(n.cols,120,Rk),o=Ik(n.rows,32,Ok),s;try{s=tN.spawn(Y,["-S",Rt,"attach-session","-d","-t",t],{name:"xterm-256color",cols:r,rows:o,cwd:process.env.HOME||"/",env:{...process.env,TERM:"xterm-256color"}})}catch(a){Wl(e,`failed to spawn tmux attach: ${a.message}`),e.close(1011,"spawn failed");return}s.onData(a=>{e.readyState===e.OPEN&&hf(e,{type:"data",data:a})}),s.onExit(({exitCode:a,signal:i})=>{e.readyState===e.OPEN&&(hf(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"&&sN(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{}oN(t)})}var nN=6,rN=250;async function oN(e,t=nN,n=rN){for(let r=0;r<t;r++){if(await Ao(e).catch(()=>!0))return!0;await new Promise(o=>setTimeout(o,n))}return!1}var Rk=20,Ok=6;function sN(e,t){return Number.isFinite(Number(e))&&Number.isFinite(Number(t))&&Number(e)>=Rk&&Number(t)>=Ok}function Ik(e,t,n){let r=Number(e);return!Number.isFinite(r)||r<n?t:Math.min(500,r|0)}function hf(e,t){try{e.send(JSON.stringify(t))}catch{}}function Wl(e,t){hf(e,{type:"error",message:t})}function Mk(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}}an();Gl();om();cr();import{createRequire as l6}from"node:module";var l2=e=>!!e&&!e.finishedAt&&!e.canceled&&!e.error;function Eg({tracks:e=[],views:t=[],queuedOf:n=()=>[],jobsOf:r=()=>[],prPendingOf:o=()=>[]}={}){let s=[];for(let a of e)!a||a.archivedAt&&!a.archiving||a.transferredTo||(a.working&&s.push(`working:${a.id}`),a.prompted&&s.push(`prompted:${a.id}`),(n(a.id)??[]).length&&s.push(`queued:${a.id}`),(a.boxes||[]).some(i=>i?.role==="subtask"&&i?.state==="live")&&s.push(`subtask:${a.id}`),(r(a.id)??[]).length&&s.push(`job:${a.id}`),Object.values(a.subtasks||{}).some(l2)&&s.push(`merge-back:${a.id}`),(o(a.id)??[]).length&&s.push(`pr:${a.id}`));return t.some(a=>a?.state==="live"||a?.state==="starting")&&s.push("views"),{busy:s.length>0,reasons:s}}de();ym();ct();import f2 from"node:fs/promises";import _g from"node:fs/promises";var u2=100;async function d2(e){let t;try{t=await _g.readFile(`/proc/${e}/stat`,"utf8")}catch{return null}let n=t.lastIndexOf(")");if(n<0)return null;let r=t.slice(n+2).split(" "),o=Number(r[1]),s=Number(r[11])+Number(r[12]);return!Number.isFinite(o)||!Number.isFinite(s)?null:{ppid:o,cpuMs:s/u2*1e3,ioBytes:await p2(e)}}async function p2(e){let t;try{t=await _g.readFile(`/proc/${e}/io`,"utf8")}catch{return 0}let n=r=>Number(t.match(new RegExp(`^${r}: (\\d+)$`,"m"))?.[1]||0);return n("rchar")+n("wchar")}async function N_(e){let t=[...new Set((e||[]).map(Number).filter(l=>Number.isFinite(l)&&l>0))];if(!t.length)return{procs:0,cpuMs:0,ioBytes:0};let n;try{n=await _g.readdir("/proc")}catch{return null}let r=new Map;await Promise.all(n.map(async l=>{if(!/^\d+$/.test(l))return;let u=await d2(l);u&&r.set(Number(l),u)}));let o=new Map;for(let[l,u]of r)o.has(u.ppid)||o.set(u.ppid,[]),o.get(u.ppid).push(l);let s=new Set,a=t.filter(l=>r.has(l));for(let l of a)s.add(l);let i=0,c=0;for(let l=0;l<a.length;l++){let u=a[l];i+=r.get(u).cpuMs,c+=r.get(u).ioBytes;for(let d of o.get(u)||[])s.has(d)||(s.add(d),a.push(d))}return{procs:s.size,cpuMs:Math.round(i),ioBytes:c}}var m2=Number(process.env.BOSTRAT_JOB_CHECK_MS)||15*6e4,h2=Number(process.env.BOSTRAT_JOB_STALL_CHECKS)||3,w2=Number(process.env.BOSTRAT_JOB_CPU_RATE_MIN)||25,g2=Number(process.env.BOSTRAT_JOB_IO_RATE_MIN)||64*1024,y2=5*6e4,D_={readOpenJobs:rv,statFile:async e=>{try{let t=await f2.stat(e);return{size:t.size,mtimeMs:Math.round(t.mtimeMs)}}catch{return null}},updatedAt:e=>Ur(e.agent).updatedAt(e),panePids:Tk,treeStats:N_,appendEvent:M},hn=new Map,P_=new Map,Ig=new Map,$g=(e,t,n)=>`${e}|${t}|${n}`;function B_(e){let t=[];for(let n of e||[])if(!(!n||n.archivedAt&&!n.archiving||n.transferredTo))for(let r of n.boxes||[])r?.state==="live"&&r.name&&t.push({track:n,box:r});return t}async function j_(e,t,n){let r=null;try{r=await n.updatedAt(e)}catch{r=null}let o=P_.get(e.name);if(o&&o.mtime===r&&t-o.at<y2)return o.jobs;let s=[];try{s=await n.readOpenJobs(e)}catch{s=[]}return P_.set(e.name,{at:t,mtime:r,jobs:s}),s}async function b2(e,t,n){let r=await n.panePids(e.name),o=r.length?await n.treeStats(r):null,s=null;try{s=await n.updatedAt(e)}catch{s=null}return{at:t,cpuMs:o?.cpuMs??null,ioBytes:o?.ioBytes??null,procs:o?.procs??null,mtime:s}}async function k2(e,t){return e?.outputFile?await t.statFile(e.outputFile):null}function x2(e,t){if(!e)return!0;let n=Math.max(1,(t.at-e.at)/1e3);return t.mtime!=null&&e.mtime!=null&&t.mtime>e.mtime||t.procs!=null&&e.procs!=null&&t.procs>e.procs||t.cpuMs!=null&&e.cpuMs!=null&&(t.cpuMs-e.cpuMs)/n>=w2||t.ioBytes!=null&&e.ioBytes!=null&&(t.ioBytes-e.ioBytes)/n>=g2}function L_(e,t,n,r){let o=[];for(let s of n){let a=$g(e.id,t.name,s.id),i=hn.get(a);i?i.job=s:hn.set(a,{trackId:e.id,boxName:t.name,agent:t.agent||null,job:s,firstSeenAt:r,quiet:0,stalled:!1}),o.push(a)}return o}async function F_(e,{now:t=Date.now(),deps:n=D_}={}){let r=new Map,o=new Set;for(let{track:s,box:a}of B_(e)){let i=await j_(a,t,n);for(let l of i)o.add($g(s.id,a.name,l.id));let c=L_(s,a,i,t).filter(l=>!hn.get(l).stalled).map(l=>hn.get(l).job);c.length&&r.set(s.id,[...r.get(s.id)??[],...c])}for(let s of[...hn.keys()])o.has(s)||hn.delete(s);return r}async function v2(e,{now:t=Date.now(),deps:n=D_}={}){let r={checked:0,progressing:0,quiet:0,stalled:[]},o=B_(e),s=new Set(o.map(({box:a})=>a.name));for(let[a,i]of[...hn])s.has(i.boxName)||hn.delete(a);for(let{track:a,box:i}of o){let c=await j_(i,t,n),l=new Set(c.map(w=>$g(a.id,i.name,w.id)));for(let[w,m]of[...hn])m.boxName===i.name&&!l.has(w)&&hn.delete(w);if(!c.length){Ig.delete(i.name);continue}let u=L_(a,i,c,t),d=await b2(i,t,n),p=Ig.get(i.name);Ig.set(i.name,d);let f=x2(p,d);for(let w of u){let m=hn.get(w);r.checked++;let g=await k2(m.job,n),y=!!g&&!!m.file&&(g.size>m.file.size||g.mtimeMs>m.file.mtimeMs),x=!!g&&!m.file;if(m.file=g??m.file,f||y||x){m.quiet=0,m.lastProgressAt=t,m.stalled=!1,r.progressing++;continue}if(m.stalled||(m.quiet++,r.quiet++,m.quiet<h2))continue;m.stalled=!0,m.stalledAt=t,r.stalled.push(w);let O=t-(m.lastProgressAt??m.firstSeenAt);try{await n.appendEvent(a,{type:"job.stalled",actor:"orchestrator",source:"orchestrator",boxId:i.name,provider:i.agent||null,payload:{id:m.job.id,kind:m.job.kind||"agent",name:m.job.name||null,detail:m.job.detail||null,startedTs:m.job.ts??m.firstSeenAt,quietMs:O,checks:m.quiet}})}catch{}console.log(`[job-watch] ${a.id}/${i.name} job ${m.job.id} (${m.job.name||m.job.kind}) quiet for ${Math.round(O/6e4)}m over ${m.quiet} check(s) \u2014 released; the node may sleep`)}}return r}function U_({listTracks:e,intervalMs:t=m2}={}){let n=!1,o=setInterval(async()=>{if(!n){n=!0;try{await v2(await e())}catch(s){console.error(`[job-watch] sweep: ${s?.message||s}`)}finally{n=!1}}},t);return o.unref?.(),o}de();ic();Rn();ed();Gt();var Fd=60*6e4,S2=1440*6e4,T2=new Set(["merged","closed","lost"]),Cc=(e,t,n)=>Number.isFinite(Number(e))&&n-Number(e)<=t;function A2({trackId:e,shipPending:t=null,links:n=[],observers:r=0,now:o=Date.now()}={}){let s=[];t&&Number.isFinite(Number(t.ts))&&o-Number(t.ts)<=Qh&&s.push("ship"),r>0&&s.push("create-net");for(let a of n||[]){if(!a||T2.has(a.state))continue;let i=[a.ciFix,a.reconcile,a.ciFixAwait,a.reconcileAwait];if(!(a.trackId===e||i.some(d=>d?.trackId===e)))continue;let l=a.number??"?";a.ciFix&&Cc(a.ciFix.delegatedAt,Fd,o)&&s.push(`ci-fix#${l}`),a.reconcile&&Cc(a.reconcile.delegatedAt,Fd,o)&&s.push(`reconcile#${l}`),a.ciFixAwait&&Cc(a.ciFixAwait.since,Fd,o)&&s.push(`ci-fix-await#${l}`),a.reconcileAwait&&Cc(a.reconcileAwait.since,Fd,o)&&s.push(`reconcile-await#${l}`);let u=a.autoMerge?.armedAt??a.armedAt??null;a.trackId===e&&(a.autoMerge||a.armedAt)&&Cc(u,S2,o)&&s.push(`auto-merge#${l}`)}return s}var Ud=new Map;Je.on("event",e=>{e?.trackId&&Ud.delete(e.trackId)});async function E2(e){if(Ud.has(e.id))return Ud.get(e.id);let t=await K(e).catch(()=>[]),n=ca(t,-1/0);return Ud.set(e.id,n),n}async function H_(e,{now:t=Date.now()}={}){let n=new Map,r=await un().catch(()=>[]);for(let o of e||[]){if(!o||De(o))continue;let s=A2({trackId:o.id,shipPending:await E2(o),links:r,observers:RT(o.id),now:t});s.length&&n.set(o.id,s)}return n}Sw();import eI from"node:fs";import io from"node:fs/promises";import q2 from"node:os";import dt from"node:path";import{spawn as W2}from"node:child_process";import{createRequire as K2}from"node:module";de();vu();import X_ from"node:fs";import Pc from"node:fs/promises";import $2 from"node:http";import gn from"node:path";import qd from"node:os";import{createRequire as R2}from"node:module";import Og from"ws";import _2 from"node:path";import I2 from"node:os";var Nc=process.env.BOSTRAT_STATE_DIR||_2.join(process.env.HOME||I2.tmpdir(),".bostrat");function Rg(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 q_(e=process.env){if(!e.BOSTRAT_PLANE_URL)return null;let t=Rg(e);return t==="127.0.0.1"||t==="::1"||t==="localhost"?null:{host:t}}function W_(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 wn=(()=>{try{return R2(import.meta.url)("../package.json").version||null}catch{return null}})(),K_=process.env.BOSTRAT_STATE_DIR||gn.join(process.env.HOME||qd.tmpdir(),".bostrat");function ts({env:e=process.env,pkgDir:t=gn.resolve(gn.dirname(new URL(import.meta.url).pathname),".."),exists:n=X_.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(gn.join(t,"..",".git"))?"git-checkout":"dev"}function Dc(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 Hd(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 O2({home:e=process.env.HOME||qd.homedir(),env:t=process.env}={}){let n=r=>{try{return X_.statSync(r),!0}catch{return!1}};return{claude:n(gn.join(e,".claude",".credentials.json")),codex:n(gn.join(t.CODEX_HOME||gn.join(e,".codex"),"auth.json"))}}var ut=1,G_=1e3,z_=3e4,M2=6e4,C2=1500,N2=500,ao=100,P2=2e3,D2=25e3,B2=6e4,Z_=(e,t)=>{let n=Number(e);return Number.isFinite(n)&&n>0?n:t},j2=Z_(process.env.BOSTRAT_PLANE_DELIVERY_TIMEOUT_MS,18e4),L2=3e4,V_=10*6e4,F2=400,J_=250,U2=Z_(process.env.BOSTRAT_PLANE_INGEST_TIMEOUT_MS,1e4),Mg=4,H2=6e4,Y_=6e4;function Q_({url:e,token:t,nodeId:n=qd.hostname(),name:r=qd.hostname(),listTracks:o,detectAgents:s=null,onTracksTransferred:a=null,sampleMetrics:i=null,deliverySample:c=null,onHashKey:l=null,metricsMs:u=H2,onUpdateAvailable:d=null,onUpdatePolicy:p=null,onHelloRefused:f=null,updatePolicy:w=null,installKind:m=ts(),selfUrl:g=`http://127.0.0.1:${process.env.PORT||3362}`,apiToken:y=null,onDegraded:x=null,onRecovered:b=null,onConnected:O=null,ingestMode:$=["ws","http","auto"].includes(process.env.BOSTRAT_PLANE_INGEST)?process.env.BOSTRAT_PLANE_INGEST:"auto",deliveryTimeoutMs:C=j2,unackedRetryMs:L=B2,pingMs:q=D2,maxInflightEvents:I=F2,httpTimeoutMs:_=U2,stallBackoffMinMs:F=L2,fetchImpl:V=globalThis.fetch,log:A=console}){if(!e||!t)throw new Error("plane-link: url and token are required");if(typeof o!="function")throw new Error("plane-link: listTracks is required");e=W_(e);let E=g.replace(/^http/,"ws"),N=new Set,H=new Map,z=new Map,fe=gn.join(K_,"plane-link","cursor.json"),me=gn.join(K_,"plane-link","dead-letter.ndjson"),Se=e.replace(/^ws(s?):\/\//,"http$1://").replace(/\/v1\/node\/?$/,""),Ae={},W={},te=new Map,le=null,J=null,ye=0,Ce=0,Ne=0,R=Promise.resolve(),D="ws",ue=0,Le=!1,Me=0,Ht=!1,St=ao,Gn=new Set,xn=[],yt=null,k=null,h=!1,v=!1,P=G_,ne=null,ge=null,Oe=null,tt=null,Ge=null,qt=!1,pl=0;async function CO(){try{Ae=JSON.parse(await Pc.readFile(fe,"utf8"))}catch{Ae={}}}function NO(){qt=!0,!Oe&&(Oe=setTimeout(async()=>{if(Oe=null,!!qt){qt=!1;try{await Pc.mkdir(gn.dirname(fe),{recursive:!0}),await Pc.writeFile(fe,JSON.stringify(Ae))}catch(j){A.error("[plane-link] cursor flush failed:",j?.message||j)}}},P2),Oe.unref?.())}function it(j){return!k||k.readyState!==Og.OPEN?!1:(k.send(JSON.stringify(j)),!0)}function La(j){let U=Date.now();for(let{trackId:T,event:B}of j){let X=te.get(B.id);te.set(B.id,{trackId:T,seq:B.seq,event:B,sentAt:U,firstSentAt:X?.firstSentAt??U,retryAt:U+L,tries:(X?.tries??0)+1,nacks:X?.nacks??0})}return D==="http"?(jO(j),!0):it({v:ut,ch:"events",type:"append",events:j})}function PO(j){let U=null;for(let T of te.values())T.trackId===j&&(U==null||T.seq<U)&&(U=T.seq);return U}function Mp(j){let U=W[j];if(U==null)return;let T=PO(j),B=T==null?U:Math.min(U,T-1);B>(Ae[j]??0)&&(Ae[j]=B,NO())}function Fa(){if(le=Date.now(),J!=null){let j=Date.now()-J;A.log(`[plane-link] spine sync recovered after ${Math.round(j/1e3)}s degraded (${ye} stall redial(s))`);let U=J;J=null,ye=0,Ce=0,Le=!1,Me=0;try{b?.({since:U,downMs:j})}catch(T){A.error(`[plane-link] onRecovered failed: ${T?.message||T}`)}}}function Cp(j){if(!Array.isArray(j)||!j.length)return;let U=new Set;for(let T of j){let B=te.get(T);B&&(te.delete(T),(W[B.trackId]??0)<B.seq&&(W[B.trackId]=B.seq),U.add(B.trackId))}for(let T of U)Mp(T);Fa()}function tb(j,U){Ne++;let T={at:Date.now(),trackId:j.trackId,seq:j.seq,id:j.event?.id??null,type:j.event?.type??null,reason:U,event:j.event??null};A.error(`[plane-link] DEAD-LETTER ${j.trackId} seq ${j.seq} (${T.type??"?"}): plane rejected it permanently (${U}) \u2014 kept in ${me}`),R=R.then(async()=>{await Pc.mkdir(gn.dirname(me),{recursive:!0}),await Pc.appendFile(me,JSON.stringify(T)+`
653
- `)}).catch(B=>A.error(`[plane-link] dead-letter write failed: ${B?.message||B}`))}function nb(j,U,T,B=null){if(!Array.isArray(j)||!j.length)return;let X=new Set,xe=Date.now();for(let Ee of j){let qe=te.get(Ee);qe&&(T?(te.delete(Ee),tb(qe,U),(W[qe.trackId]??0)<qe.seq&&(W[qe.trackId]=qe.seq),X.add(qe.trackId)):(qe.nacks++,qe.retryAt=xe+Math.max(1e3,Number(B)||L)))}for(let Ee of X)Mp(Ee);Fa()}function rb(j=Date.now()){let U=1/0;for(let T of te.values())T.firstSentAt<U&&(U=T.firstSentAt);return U===1/0?0:j-U}function ob(){if(!h||!te.size)return;let j=Date.now(),U=rb(j);if(U<C||le!=null&&j-le<C||D==="http"&&Le||Ce>j)return;ye++;let T=Math.min(F*2**(ye-1),V_);if(J==null){J=j-U,A.error(`[plane-link] DEGRADED: no ack or nack for ${Math.round(U/1e3)}s with ${te.size} event(s) in flight (${D} door) \u2014 the plane is not answering appends`);try{x?.({since:J,unacked:te.size,oldestAgeMs:U,mode:D})}catch(B){A.error(`[plane-link] onDegraded failed: ${B?.message||B}`)}}if(D==="http"){Le=!0,Me=j+T,A.error(`[plane-link] ingest circuit OPEN (stall #${ye}); probing /v1/ingest/health in ${Math.round(T/1e3)}s`);return}Ce=j+T,A.error(`[plane-link] closing the link and redialing in ${Math.round(T/1e3)}s (stall redial #${ye})`);try{k?.terminate()}catch{}}function Np(){if(!h)return;let j=Date.now();if(D==="http"&&Le)return;let U=[...te.values()].filter(B=>B.event&&B.retryAt<=j&&!(D==="http"&&Gn.has(B.trackId)));if(!U.length)return;U.sort((B,X)=>B.trackId===X.trackId?B.seq-X.seq:B.trackId<X.trackId?-1:1),A.log(`[plane-link] re-sending ${U.length} unacked event(s) the plane never confirmed`);let T=D==="http"?St:ao;if(D==="http"){let B=new Map;for(let X of U)(B.get(X.trackId)??B.set(X.trackId,[]).get(X.trackId)).push(X);for(let[,X]of B){if(ue>=Mg)return;La(X.slice(0,T).map(xe=>({trackId:xe.trackId,event:xe.event})))}return}for(let B=0;B<U.length;B+=T){let X=U.slice(B,B+T).map(xe=>({trackId:xe.trackId,event:xe.event}));if(!La(X))return}}async function DO(j=null){for(;;){if(!h)return!1;let U=te.size<I,T=D!=="http"||ue<Mg&&!Le&&(!j||!Gn.has(j));if(U&&T)return!0;await new Promise(B=>setTimeout(B,100))}}function Pp(){if(yt=null,!h||!xn.length)return;let j=xn;if(xn=[],D!=="http"){for(let T=0;T<j.length;T+=ao)La(j.slice(T,T+ao));return}let U=new Map;for(let T of j)(U.get(T.trackId)??U.set(T.trackId,[]).get(T.trackId)).push(T);for(let[T,B]of U){if(Gn.has(T)||ue>=Mg||Le){xn.push(...B);continue}for(let X=0;X<B.length;X+=St)La(B.slice(X,X+St))}xn.length&&!yt&&(yt=setTimeout(Pp,J_),yt.unref?.())}let BO=j=>{let U=new Map;for(let{trackId:T,event:B}of j)(U.get(T)??U.set(T,[]).get(T)).push(B);return[...U].map(([T,B])=>({trackId:T,events:B}))},ps=(j,U,T,{progress:B})=>{let X=Date.now();for(let{event:xe}of j){let Ee=te.get(xe.id);Ee&&(Ee.nacks++,Ee.retryAt=X+Math.max(1e3,T||L))}B&&Fa()};async function jO(j){let U=new Set(j.map(T=>T.trackId));for(let T of U)Gn.add(T);ue++;try{let T=await V(`${Se}/v1/ingest`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/json"},body:JSON.stringify({node:n,batches:BO(j)}),signal:AbortSignal.timeout(_)}),B=(Number(T.headers.get("retry-after"))||0)*1e3;if(T.status===200){let X=await T.json();St=ao;for(let xe of X.results??[]){Cp(xe.acked??[]);let Ee=(qe,Tt)=>{let Wt=new Map;for(let nt of qe??[])(Wt.get(nt.reason)??Wt.set(nt.reason,[]).get(nt.reason)).push(nt.id);for(let[nt,lb]of Wt)nb(lb,nt,Tt,X.retryAfterMs??null)};Ee(xe.rejected,!0),Ee(xe.deferred,!1)}Cp(X.discarded??[]),Fa();return}if(T.status===429){ps(j,"overloaded",B||5e3,{progress:!0});return}if(T.status===413&&j.length>1){St=Math.max(1,Math.floor(j.length/2)),A.error(`[plane-link] ingest request too large (${j.length} events) \u2014 halving batches to ${St}`),ps(j,"too_large",1e3,{progress:!0});return}if(T.status===413){let X=te.get(j[0].event.id);X&&(te.delete(X.event.id),tb(X,"too_large"),(W[X.trackId]??0)<X.seq&&(W[X.trackId]=X.seq),Mp(X.trackId)),Fa();return}if(T.status===401||T.status===403){if(Date.now()-pl>=Y_){pl=Date.now();let X="";try{X=(await T.json())?.error??""}catch{}A.error(`[plane-link] plane refused ingest (HTTP ${T.status}${X?`: ${X}`:""}) \u2014 events are held locally and retried; check this node's token/binding`)}ps(j,`http_${T.status}`,6e4,{progress:!1});return}if(T.status===400){A.error(`[plane-link] plane rejected an ingest request as malformed (400) \u2014 holding ${j.length} event(s) for retry; this is a bug, not data`),ps(j,"http_400",6e4,{progress:!1});return}ps(j,`http_${T.status}`,B||5e3,{progress:!1})}catch(T){let B=T?.name==="TimeoutError"||T?.name==="AbortError";B&&j.length>1&&(St=Math.max(1,Math.floor(j.length/2)),A.error(`[plane-link] ingest request of ${j.length} event(s) outlived its ${_} ms deadline \u2014 halving batches to ${St}`)),ps(j,B?"timeout":"network",5e3,{progress:!1})}finally{ue--;for(let T of U)Gn.delete(T)}}async function LO(){if(D!=="http"||!Le||!h||Ht)return;let j=Date.now();if(!(Me>j)){Ht=!0;try{let U=await V(`${Se}/v1/ingest/health`,{headers:{authorization:`Bearer ${t}`},signal:AbortSignal.timeout(_)});if(!U.ok)throw new Error(`HTTP ${U.status}`);A.log("[plane-link] ingest door answering \u2014 closing the circuit and re-sending"),Le=!1,Me=0,Ce=Date.now()+_+L+1e3;for(let T of te.values())T.retryAt=Math.min(T.retryAt,Date.now());Np()}catch(U){ye++;let T=Math.min(F*2**(ye-1),V_);Me=Date.now()+T,A.error(`[plane-link] ingest door still not answering (${U?.message||U}); next probe in ${Math.round(T/1e3)}s`)}finally{Ht=!1}}}function sb(){let j=Date.now();return{mode:D,unacked:te.size,oldestUnackedAgeMs:rb(j),lastProgressAt:le,degradedSince:J,stallRedials:ye,deadLettered:Ne,http:D==="http"?{inFlight:ue,circuitOpen:Le,nextProbeInMs:Le?Math.max(0,Me-j):0,batchCap:St}:null}}async function ab(){if(!i)return;let j;try{j=await i()}catch(T){A.error("[plane-link] metrics sample failed:",T?.message||T);return}let U=null;try{U=c?.()??null}catch{}j&&it({v:ut,ch:"ctl",type:"metrics",metrics:{...j,planeLink:sb(),...U?{delivery:U}:{}}})}function FO(){i&&(Ge&&clearInterval(Ge),ab(),Ge=setInterval(ab,u),Ge.unref?.())}async function UO(){let j;try{j=await o()}catch(U){A.error("[plane-link] backfill listTracks failed:",U?.message||U);return}it({v:ut,ch:"ctl",type:"tracks",ids:j.filter(U=>!U.transferredTo).map(U=>U.id).filter(U=>typeof U=="string")});for(let U of j){if(!h)return;let T;try{T=await K(U)}catch{continue}let B=Ae[U.id]??0,X=T.filter(Ee=>Ee.seq>B&&typeof Ee.id=="string"),xe=D==="http"?St:ao;for(let Ee=0;Ee<X.length;Ee+=xe){if(!await DO(U.id))return;let qe=X.slice(Ee,Ee+Math.min(xe,D==="http"?St:ao)).map(Tt=>({trackId:U.id,event:Tt}));if(!La(qe))return}}}function ib(j){!h||!j?.trackId||typeof j.id!="string"||(xn.push({trackId:j.trackId,event:j}),yt||(yt=setTimeout(Pp,J_),yt.unref?.()))}let Ua=new Map;async function HO(j){let{reqId:U,method:T,path:B,headers:X={},body:xe}=j,Ee=Object.fromEntries(Object.entries(X).filter(([,Tt])=>Tt!=null)),qe=new AbortController;Ua.set(U,qe);try{if(j.host){await qO(j,Ee,qe);return}y&&(Ee["x-bostrat-token"]=y);let Tt=await fetch(g+B,{method:T,headers:Ee,body:xe?Buffer.from(xe,"base64"):void 0,signal:qe.signal}),Wt=Object.fromEntries(Tt.headers);for(let nt of["connection","keep-alive","transfer-encoding","upgrade","content-encoding","content-length"])delete Wt[nt];if(Wt["content-type"]||(Wt["content-type"]="application/octet-stream"),it({v:ut,ch:"control",type:"http_head",reqId:U,status:Tt.status,headers:Wt}),Tt.body){for await(let nt of Tt.body)if(!it({v:ut,ch:"control",type:"http_data",reqId:U,data:Buffer.from(nt).toString("base64")}))break}it({v:ut,ch:"control",type:"http_end",reqId:U,error:null})}finally{Ua.delete(U)}}function qO(j,U,T){let{reqId:B,method:X,path:xe,body:Ee}=j,qe=new URL(g);return new Promise(Tt=>{let Wt=$2.request({host:qe.hostname,port:qe.port,method:X,path:xe,headers:{...U,host:j.host},signal:T.signal},nt=>{let{connection:lb,"keep-alive":_6,"transfer-encoding":I6,upgrade:$6,...WO}=nt.headers;it({v:ut,ch:"control",type:"http_head",reqId:B,status:nt.statusCode||502,headers:WO}),nt.on("data",KO=>{it({v:ut,ch:"control",type:"http_data",reqId:B,data:Buffer.from(KO).toString("base64")})||nt.destroy()}),nt.on("end",()=>{it({v:ut,ch:"control",type:"http_end",reqId:B,error:null}),Tt()}),nt.on("error",()=>{it({v:ut,ch:"control",type:"http_end",reqId:B,error:"view upstream error"}),Tt()})});Wt.on("error",nt=>{it({v:ut,ch:"control",type:"http_end",reqId:B,error:nt?.message||"view request failed"}),Tt()}),Ee&&Wt.write(Buffer.from(Ee,"base64")),Wt.end()})}function cb(){if(v)return;k=new Og(e,{headers:{authorization:`Bearer ${t}`}}),k.on("open",async()=>{let U=null;try{U=await s?.()||null}catch{U=null}it({v:ut,ch:"ctl",type:"hello",nodeId:n,name:r,platform:process.platform,version:wn,installKind:m,...typeof w=="function"?{updatePolicy:w()}:w?{updatePolicy:w}:{},providers:O2(),...U?{agents:U}:{}})}),k.on("message",U=>{let T;try{T=JSON.parse(U)}catch{return}if(T.ch==="ctl"&&T.type==="hello_ok"){h=!0,P=G_,ne=null,A.log(`[plane-link] connected to plane as ${n}`);try{O?.()}catch{}if(typeof T.hashKey=="string"&&T.hashKey)try{l?.(T.hashKey)}catch{}T.minNodeVersion&&wn&&Dc(wn,T.minNodeVersion)&&A.error(`[plane-link] this node is bostrat-node ${wn}; the plane asks for \u2265${T.minNodeVersion} \u2014 update with: ${Hd(m)}`);try{p?.(typeof T.updatePolicy=="string"?T.updatePolicy:null)}catch{}let B=typeof T.latestNodeVersion=="string"?T.latestNodeVersion:null;if(B&&wn&&Dc(wn,B)&&!N.has(B)){N.add(B),A.log(`[plane-link] bostrat-node ${B} is available (this node runs ${wn}) \u2014 ${Hd(m)}`);try{d?.({current:wn,latest:B,min:T.minNodeVersion??null,installKind:m,required:!!(T.minNodeVersion&&Dc(wn,T.minNodeVersion))})}catch(xe){A.error(`[plane-link] update notice failed: ${xe?.message||xe}`)}}let X=T.ingest==="http";D=$==="ws"?"ws":$==="http"||X?"http":"ws",$==="http"&&!X&&A.error("[plane-link] BOSTRAT_PLANE_INGEST=http but this plane offers no HTTPS ingest door \u2014 events will fail until it does"),D==="http"&&A.log("[plane-link] spine rides the HTTPS ingest door"),Le=!1,Me=0,St=ao,tt&&clearInterval(tt),tt=setInterval(()=>{it({v:ut,ch:"ctl",type:"ping"}),ob(),LO().catch(()=>{}),Np(),xn.length&&!yt&&Pp()},q),tt.unref?.(),FO(),UO().catch(xe=>A.error("[plane-link] backfill failed:",xe?.message||xe));return}if(T.ch==="ctl"&&T.type==="hello_refused"){let B=typeof T.minNodeVersion=="string"?T.minNodeVersion:null,X=typeof T.latestNodeVersion=="string"?T.latestNodeVersion:null;A.error(`[plane-link] plane REFUSED this node: bostrat-node ${wn??"?"} is below its minimum ${B??"?"} \u2014 ${T.fix||Hd(m)}`),P=z_,ne=0;try{f?.({current:wn,min:B,latest:X,fix:T.fix||Hd(m),installKind:m})}catch(xe){A.error(`[plane-link] refusal handler failed: ${xe?.message||xe}`)}return}if(T.ch==="ctl"&&T.type==="update_policy"){try{p?.(typeof T.mode=="string"?T.mode:null)}catch{}return}if(T.ch==="ctl"&&T.type==="usage_caps"){xu(T.caps??{},{source:"plane",updatedAt:T.updatedAt??Date.now()}).then(B=>A.log(`[plane-link] spend caps ${Object.keys(B.caps).length?`updated (${Object.keys(B.caps).join(", ")})`:"cleared"} from plane`)).catch(B=>A.error("[plane-link] spend-caps push rejected:",B?.message||B));return}if(T.ch==="ctl"&&T.type==="transferred"&&Array.isArray(T.tracks)){Promise.resolve().then(()=>a?.(T.tracks)).catch(B=>A.error("[plane-link] transfer notice failed:",B?.message||B));return}if(T.ch==="events"&&T.type==="ack"&&Array.isArray(T.ids)){Cp(T.ids);return}if(T.ch==="events"&&T.type==="nack"&&Array.isArray(T.ids)){nb(T.ids,T.reason,T.permanent===!0,T.retryAfterMs??null);return}if(T.ch==="control"&&T.type==="http_open"){HO(T).catch(B=>it({v:ut,ch:"control",type:"http_end",reqId:T.reqId,error:B?.message||"tunnel error"}));return}if(T.ch==="control"&&T.type==="http_cancel"){Ua.get(T.reqId)?.abort();return}if(T.ch==="attach"&&T.type==="open"){let B=new Og(E+T.path,Array.isArray(T.protocols)?T.protocols:[],T.host?{headers:{host:T.host}}:void 0);H.set(T.streamId,B),z.set(T.streamId,[]),B.on("open",()=>{let xe=z.get(T.streamId)||[];z.delete(T.streamId);for(let{buf:Ee,bin:qe}of xe)B.send(Ee,{binary:qe})}),B.on("message",(xe,Ee)=>{let qe=Ee?xe:Buffer.from(String(xe));it({v:ut,ch:"attach",type:"data",streamId:T.streamId,data:qe.toString("base64"),...Ee?{bin:!0}:{}})});let X=()=>{z.delete(T.streamId),H.delete(T.streamId)&&it({v:ut,ch:"attach",type:"close",streamId:T.streamId})};B.on("close",X),B.on("error",X);return}if(T.ch==="attach"&&T.type==="data"){let B=H.get(T.streamId);if(!B)return;let X=Buffer.from(T.data,"base64"),xe=T.bin===!0,Ee=z.get(T.streamId);Ee?Ee.push({buf:X,bin:xe}):B.send(X,{binary:xe});return}if(T.ch==="attach"&&T.type==="close"){let B=H.get(T.streamId);H.delete(T.streamId),z.delete(T.streamId),B?.close();return}});let j=()=>{h&&A.log("[plane-link] disconnected from plane"),h=!1,tt&&(clearInterval(tt),tt=null),Ge&&(clearInterval(Ge),Ge=null),te.clear(),W={},xn=[],yt&&(clearTimeout(yt),yt=null),Gn.clear();for(let B of H.values())B.close();H.clear(),z.clear();for(let B of Ua.values())B.abort();if(Ua.clear(),v||ge)return;ne==null&&(ne=Date.now());let U=Date.now()-ne<M2,T=Math.max(U?C2+Math.random()*N2:P,Ce-Date.now());ge=setTimeout(()=>{ge=null,cb()},T),ge.unref?.(),U||(P=Math.min(P*2,z_))};k.on("close",j),k.on("error",U=>{let T=/Unexpected server response: (\d+)/.exec(U?.message||"")?.[1];(T==="401"||T==="403")&&Date.now()-pl>=Y_&&(pl=Date.now(),A.error(`[plane-link] plane refused this node's credentials (HTTP ${T}) \u2014 the token was revoked or is unknown to the plane; mint a new node token and update this node's BOSTRAT_PLANE_TOKEN (still retrying)`)),j()})}return Je.on("event",ib),CO().then(cb),{stop:()=>{v=!0,Je.off("event",ib),ge&&clearTimeout(ge),Oe&&clearTimeout(Oe),tt&&clearInterval(tt),Ge&&clearInterval(Ge),yt&&clearTimeout(yt),it({v:ut,ch:"ctl",type:"bye",reason:"shutdown"}),k?.close()},status:()=>({connected:h,nodeId:n,cursor:{...Ae},inflight:te.size,...sb()}),_tick:()=>{ob(),Np()}}}zl();var Wd=(()=>{try{return K2(import.meta.url)("../package.json").version||null}catch{return null}})(),G2=process.env.BOSTRAT_STATE_DIR||dt.join(process.env.HOME||q2.tmpdir(),".bostrat"),tI=dt.join(G2,"self-update"),Kd=dt.join(tI,"status.json"),z2=1440*6e4,V2=6e4,Bc=new Set(["npm-global","git-checkout"]);function nI({kind:e=ts(),env:t=process.env}={}){let n=String(t.BOSTRAT_UPDATE_POLICY||"").trim();return["auto","prompt","off"].includes(n)?n:Bc.has(e)?e==="git-checkout"||J2(t)?"auto":"prompt":"off"}function J2(e=process.env){return!!(e.INVOCATION_ID||e.XPC_SERVICE_NAME&&e.XPC_SERVICE_NAME!=="0")}var jt=e=>`'${String(e).replace(/'/g,"'\\''")}'`;function Y2({kind:e,to:t,from:n=Wd,statusFile:r=Kd,logFile:o=dt.join(tI,"last.log"),port:s=Number(process.env.PORT)||3362,npmPrefix:a=null,serviceName:i=process.platform==="darwin"?"com.bostrat.node":"bostrat-node.service",uid:c=typeof process.getuid=="function"?process.getuid():0,liveDir:l=process.env.BOSTRAT_LIVE_CHECKOUT||dt.resolve(dt.dirname(new URL(import.meta.url).pathname),"..",".."),startedAt:u=Date.now()}={}){if(!Bc.has(e))throw new Error(`self-update: install kind "${e}" is not actionable here`);if(!/^\d+\.\d+\.\d+$/.test(String(t)))throw new Error(`self-update: bad target version "${t}"`);if(n&&!/^\d+\.\d+\.\d+$/.test(String(n)))throw new Error(`self-update: bad current version "${n}"`);let d=(g,y="")=>`write_status ${jt(g)} ${y}`,p=process.platform==="darwin"?`launchctl kickstart -k gui/${c}/${i}`:`systemctl --user restart ${jt(i)}`,f=`
656
+ `);o2=new Set(["claude","codex","cursor"]);$c=new Set,s2=e=>$c.has(e);a2=9e4;x_={merged:"merged",closed:"closed on GitHub WITHOUT merging",lost:"no longer found on GitHub (deleted, or its repo left the grant)"};Vw=new Map;eg=120;Og=(e,t,n)=>({name:e.name,agent:e.agent,role:t,state:n,cwd:e.cwd,sessionId:e.sessionId,pinned:e.pinned===!0,hookTokenHash:To(e.hookToken),createdAt:Date.now()});cs=new Map,Ca=e=>cs.get(e)||(Mt?de(Mt,e)?.handoff:null)||null;Cg=6e4,wn=(e,t,n=15e3)=>Dd("git",["-C",e,...t],{timeout:n,maxBuffer:8*1024*1024}),Nd=new Map,Ng=e=>Nd.get(e)||null;m2=/^[A-Za-z0-9][A-Za-z0-9._/-]{0,200}$/;$d=new Map;g2=Number(process.env.BOSTRAT_SUBTASK_TIMEOUT_MS)||18e5,y2=Number(process.env.BOSTRAT_SUBTASK_POLL_MS)||3e3,$a=z.join(Kn,"worktrees"),Sa=[Tc,Rd],Ct=new Map,b2=e=>Ct.get(e)||(Mt?Mt.tracks.map(t=>t.subtasks?.[e]).find(Boolean):null)||null,ps=e=>{let t=new Map([...Ct.values()].filter(r=>r.trackId===e).map(r=>[r.id,r])),n=Mt?de(Mt,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)},Qd=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});Dc=e=>W_(e.trackId,e.id,Qd(e));ep=e=>e.trim().replace(/\s+/g,"-").replace(/[^A-Za-z0-9._-]/g,"").toLowerCase()||"track",Oc=class extends Error{}});ct();import Te from"node:path";import yt from"node:fs";import S6 from"node:readline";import{fileURLToPath as A6}from"node:url";import qt from"express";import T6 from"node:http";import E6 from"node:https";import Kp from"node:os";import{randomUUID as _6}from"node:crypto";import{WebSocketServer as I6}from"ws";ct();import gN from"node-pty";async function Kk(e,t,n={}){if(!De(t)){Jl(e,`invalid session name: ${t}`),e.close(1008,"invalid session name");return}if(!await Pr()){Jl(e,`host tmux server not running on ${Dt}`),e.close(1011,"tmux server unavailable");return}if(!await be(t)){Jl(e,`session "${t}" not found`),e.close(1008,"session not found");return}let r=qk(n.cols,120,Gk),o=qk(n.rows,32,zk),s;try{s=gN.spawn(ee,["-S",Dt,"attach-session","-d","-t",t],{name:"xterm-256color",cols:r,rows:o,cwd:process.env.HOME||"/",env:{...process.env,TERM:"xterm-256color"}})}catch(a){Jl(e,`failed to spawn tmux attach: ${a.message}`),e.close(1011,"spawn failed");return}s.onData(a=>{e.readyState===e.OPEN&&Rf(e,{type:"data",data:a})}),s.onExit(({exitCode:a,signal:i})=>{e.readyState===e.OPEN&&(Rf(e,{type:"exit",code:a??null,signal:i??null}),e.close(1e3,"tmux exited"))}),e.on("message",a=>{let i;try{i=JSON.parse(a.toString())}catch{return}if(!(!i||typeof i!="object")){if(i.type==="data"&&typeof i.data=="string")s.write(i.data);else if(i.type==="resize"&&xN(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{}kN(t)})}var yN=6,bN=250;async function kN(e,t=yN,n=bN){for(let r=0;r<t;r++){if(await Oo(e).catch(()=>!0))return!0;await new Promise(o=>setTimeout(o,n))}return!1}var Gk=20,zk=6;function xN(e,t){return Number.isFinite(Number(e))&&Number.isFinite(Number(t))&&Number(e)>=Gk&&Number(t)>=zk}function qk(e,t,n){let r=Number(e);return!Number.isFinite(r)||r<n?t:Math.min(500,r|0)}function Rf(e,t){try{e.send(JSON.stringify(t))}catch{}}function Jl(e,t){Rf(e,{type:"error",message:t})}function Vk(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}}cn();Xl();gm();pr();import{createRequire as $6}from"node:module";var $2=e=>!!e&&!e.finishedAt&&!e.canceled&&!e.error;function Hg({tracks:e=[],views:t=[],queuedOf:n=()=>[],jobsOf:r=()=>[],prPendingOf:o=()=>[]}={}){let s=[];for(let a of e)!a||a.archivedAt&&!a.archiving||a.transferredTo||(a.working&&s.push(`working:${a.id}`),a.prompted&&s.push(`prompted:${a.id}`),(n(a.id)??[]).length&&s.push(`queued:${a.id}`),(a.boxes||[]).some(i=>i?.role==="subtask"&&i?.state==="live")&&s.push(`subtask:${a.id}`),(r(a.id)??[]).length&&s.push(`job:${a.id}`),Object.values(a.subtasks||{}).some($2)&&s.push(`merge-back:${a.id}`),(o(a.id)??[]).length&&s.push(`pr:${a.id}`));return t.some(a=>a?.state==="live"||a?.state==="starting")&&s.push("views"),{busy:s.length>0,reasons:s}}fe();Mm();ct();import C2 from"node:fs/promises";import Wg from"node:fs/promises";var R2=100;async function O2(e){let t;try{t=await Wg.readFile(`/proc/${e}/stat`,"utf8")}catch{return null}let n=t.lastIndexOf(")");if(n<0)return null;let r=t.slice(n+2).split(" "),o=Number(r[1]),s=Number(r[11])+Number(r[12]);return!Number.isFinite(o)||!Number.isFinite(s)?null:{ppid:o,cpuMs:s/R2*1e3,ioBytes:await M2(e)}}async function M2(e){let t;try{t=await Wg.readFile(`/proc/${e}/io`,"utf8")}catch{return 0}let n=r=>Number(t.match(new RegExp(`^${r}: (\\d+)$`,"m"))?.[1]||0);return n("rchar")+n("wchar")}async function J_(e){let t=[...new Set((e||[]).map(Number).filter(l=>Number.isFinite(l)&&l>0))];if(!t.length)return{procs:0,cpuMs:0,ioBytes:0};let n;try{n=await Wg.readdir("/proc")}catch{return null}let r=new Map;await Promise.all(n.map(async l=>{if(!/^\d+$/.test(l))return;let u=await O2(l);u&&r.set(Number(l),u)}));let o=new Map;for(let[l,u]of r)o.has(u.ppid)||o.set(u.ppid,[]),o.get(u.ppid).push(l);let s=new Set,a=t.filter(l=>r.has(l));for(let l of a)s.add(l);let i=0,c=0;for(let l=0;l<a.length;l++){let u=a[l];i+=r.get(u).cpuMs,c+=r.get(u).ioBytes;for(let d of o.get(u)||[])s.has(d)||(s.add(d),a.push(d))}return{procs:s.size,cpuMs:Math.round(i),ioBytes:c}}var N2=Number(process.env.BOSTRAT_JOB_CHECK_MS)||15*6e4,P2=Number(process.env.BOSTRAT_JOB_STALL_CHECKS)||3,D2=Number(process.env.BOSTRAT_JOB_CPU_RATE_MIN)||25,B2=Number(process.env.BOSTRAT_JOB_IO_RATE_MIN)||64*1024,j2=5*6e4,X_={readOpenJobs:kv,statFile:async e=>{try{let t=await C2.stat(e);return{size:t.size,mtimeMs:Math.round(t.mtimeMs)}}catch{return null}},updatedAt:e=>Kr(e.agent).updatedAt(e),panePids:Fk,treeStats:J_,appendEvent:M},gn=new Map,Y_=new Map,qg=new Map,Kg=(e,t,n)=>`${e}|${t}|${n}`;function Z_(e){let t=[];for(let n of e||[])if(!(!n||n.archivedAt&&!n.archiving||n.transferredTo))for(let r of n.boxes||[])r?.state==="live"&&r.name&&t.push({track:n,box:r});return t}async function Q_(e,t,n){let r=null;try{r=await n.updatedAt(e)}catch{r=null}let o=Y_.get(e.name);if(o&&o.mtime===r&&t-o.at<j2)return o.jobs;let s=[];try{s=await n.readOpenJobs(e)}catch{s=[]}return Y_.set(e.name,{at:t,mtime:r,jobs:s}),s}async function L2(e,t,n){let r=await n.panePids(e.name),o=r.length?await n.treeStats(r):null,s=null;try{s=await n.updatedAt(e)}catch{s=null}return{at:t,cpuMs:o?.cpuMs??null,ioBytes:o?.ioBytes??null,procs:o?.procs??null,mtime:s}}async function F2(e,t){return e?.outputFile?await t.statFile(e.outputFile):null}function U2(e,t){if(!e)return!0;let n=Math.max(1,(t.at-e.at)/1e3);return t.mtime!=null&&e.mtime!=null&&t.mtime>e.mtime||t.procs!=null&&e.procs!=null&&t.procs>e.procs||t.cpuMs!=null&&e.cpuMs!=null&&(t.cpuMs-e.cpuMs)/n>=D2||t.ioBytes!=null&&e.ioBytes!=null&&(t.ioBytes-e.ioBytes)/n>=B2}function eI(e,t,n,r){let o=[];for(let s of n){let a=Kg(e.id,t.name,s.id),i=gn.get(a);i?i.job=s:gn.set(a,{trackId:e.id,boxName:t.name,agent:t.agent||null,job:s,firstSeenAt:r,quiet:0,stalled:!1}),o.push(a)}return o}async function tI(e,{now:t=Date.now(),deps:n=X_}={}){let r=new Map,o=new Set;for(let{track:s,box:a}of Z_(e)){let i=await Q_(a,t,n);for(let l of i)o.add(Kg(s.id,a.name,l.id));let c=eI(s,a,i,t).filter(l=>!gn.get(l).stalled).map(l=>gn.get(l).job);c.length&&r.set(s.id,[...r.get(s.id)??[],...c])}for(let s of[...gn.keys()])o.has(s)||gn.delete(s);return r}async function H2(e,{now:t=Date.now(),deps:n=X_}={}){let r={checked:0,progressing:0,quiet:0,stalled:[]},o=Z_(e),s=new Set(o.map(({box:a})=>a.name));for(let[a,i]of[...gn])s.has(i.boxName)||gn.delete(a);for(let{track:a,box:i}of o){let c=await Q_(i,t,n),l=new Set(c.map(w=>Kg(a.id,i.name,w.id)));for(let[w,m]of[...gn])m.boxName===i.name&&!l.has(w)&&gn.delete(w);if(!c.length){qg.delete(i.name);continue}let u=eI(a,i,c,t),d=await L2(i,t,n),p=qg.get(i.name);qg.set(i.name,d);let f=U2(p,d);for(let w of u){let m=gn.get(w);r.checked++;let g=await F2(m.job,n),y=!!g&&!!m.file&&(g.size>m.file.size||g.mtimeMs>m.file.mtimeMs),x=!!g&&!m.file;if(m.file=g??m.file,f||y||x){m.quiet=0,m.lastProgressAt=t,m.stalled=!1,r.progressing++;continue}if(m.stalled||(m.quiet++,r.quiet++,m.quiet<P2))continue;m.stalled=!0,m.stalledAt=t,r.stalled.push(w);let R=t-(m.lastProgressAt??m.firstSeenAt);try{await n.appendEvent(a,{type:"job.stalled",actor:"orchestrator",source:"orchestrator",boxId:i.name,provider:i.agent||null,payload:{id:m.job.id,kind:m.job.kind||"agent",name:m.job.name||null,detail:m.job.detail||null,startedTs:m.job.ts??m.firstSeenAt,quietMs:R,checks:m.quiet}})}catch{}console.log(`[job-watch] ${a.id}/${i.name} job ${m.job.id} (${m.job.name||m.job.kind}) quiet for ${Math.round(R/6e4)}m over ${m.quiet} check(s) \u2014 released; the node may sleep`)}}return r}function nI({listTracks:e,intervalMs:t=N2}={}){let n=!1,o=setInterval(async()=>{if(!n){n=!0;try{await H2(await e())}catch(s){console.error(`[job-watch] sweep: ${s?.message||s}`)}finally{n=!1}}},t);return o.unref?.(),o}fe();fc();Cn();ad();Jt();var np=60*6e4,W2=1440*6e4,q2=new Set(["merged","closed","lost"]),Bc=(e,t,n)=>Number.isFinite(Number(e))&&n-Number(e)<=t;function K2({trackId:e,shipPending:t=null,links:n=[],observers:r=0,now:o=Date.now()}={}){let s=[];t&&Number.isFinite(Number(t.ts))&&o-Number(t.ts)<=ww&&s.push("ship"),r>0&&s.push("create-net");for(let a of n||[]){if(!a||q2.has(a.state))continue;let i=[a.ciFix,a.reconcile,a.ciFixAwait,a.reconcileAwait];if(!(a.trackId===e||i.some(d=>d?.trackId===e)))continue;let l=a.number??"?";a.ciFix&&Bc(a.ciFix.delegatedAt,np,o)&&s.push(`ci-fix#${l}`),a.reconcile&&Bc(a.reconcile.delegatedAt,np,o)&&s.push(`reconcile#${l}`),a.ciFixAwait&&Bc(a.ciFixAwait.since,np,o)&&s.push(`ci-fix-await#${l}`),a.reconcileAwait&&Bc(a.reconcileAwait.since,np,o)&&s.push(`reconcile-await#${l}`);let u=a.autoMerge?.armedAt??a.armedAt??null;a.trackId===e&&(a.autoMerge||a.armedAt)&&Bc(u,W2,o)&&s.push(`auto-merge#${l}`)}return s}var rp=new Map;Je.on("event",e=>{e?.trackId&&rp.delete(e.trackId)});async function G2(e){if(rp.has(e.id))return rp.get(e.id);let t=await K(e).catch(()=>[]),n=ga(t,-1/0);return rp.set(e.id,n),n}async function rI(e,{now:t=Date.now()}={}){let n=new Map,r=await dn().catch(()=>[]);for(let o of e||[]){if(!o||je(o))continue;let s=K2({trackId:o.id,shipPending:await G2(o),links:r,observers:KA(o.id),now:t});s.length&&n.set(o.id,s)}return n}Fw();import hI from"node:fs";import fo from"node:fs/promises";import lH from"node:os";import pt from"node:path";import{spawn as uH}from"node:child_process";import{createRequire as dH}from"node:module";fe();Iu();import pI from"node:fs";import Lc from"node:fs/promises";import J2 from"node:http";import bn from"node:path";import sp from"node:os";import{createRequire as Y2}from"node:module";import zg from"ws";import z2 from"node:path";import V2 from"node:os";var jc=process.env.BOSTRAT_STATE_DIR||z2.join(process.env.HOME||V2.tmpdir(),".bostrat");function Gg(e=process.env){let t=(e.BOSTRAT_HOST||"").trim();if(t!=="all")return t||(e.BOSTRAT_PLANE_URL?"127.0.0.1":void 0)}function oI(e=process.env){if(!e.BOSTRAT_PLANE_URL)return null;let t=Gg(e);return t==="127.0.0.1"||t==="::1"||t==="localhost"?null:{host:t}}function sI(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 yn=(()=>{try{return Y2(import.meta.url)("../package.json").version||null}catch{return null}})(),aI=process.env.BOSTRAT_STATE_DIR||bn.join(process.env.HOME||sp.tmpdir(),".bostrat");function fs({env:e=process.env,pkgDir:t=bn.resolve(bn.dirname(new URL(import.meta.url).pathname),".."),exists:n=pI.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(bn.join(t,"..",".git"))?"git-checkout":"dev"}function Fc(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 op(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 X2({home:e=process.env.HOME||sp.homedir(),env:t=process.env}={}){let n=r=>{try{return pI.statSync(r),!0}catch{return!1}};return{claude:n(bn.join(e,".claude",".credentials.json")),codex:n(bn.join(t.CODEX_HOME||bn.join(e,".codex"),"auth.json"))}}var dt=1,iI=1e3,cI=3e4,Z2=6e4,Q2=1500,eH=500,po=100,tH=2e3,nH=25e3,rH=6e4,fI=(e,t)=>{let n=Number(e);return Number.isFinite(n)&&n>0?n:t},oH=fI(process.env.BOSTRAT_PLANE_DELIVERY_TIMEOUT_MS,18e4),sH=3e4,lI=10*6e4,aH=400,uI=250,iH=fI(process.env.BOSTRAT_PLANE_INGEST_TIMEOUT_MS,1e4),Vg=4,cH=6e4,dI=6e4;function mI({url:e,token:t,nodeId:n=sp.hostname(),name:r=sp.hostname(),listTracks:o,detectAgents:s=null,onTracksTransferred:a=null,sampleMetrics:i=null,deliverySample:c=null,onHashKey:l=null,metricsMs:u=cH,onUpdateAvailable:d=null,onUpdatePolicy:p=null,onHelloRefused:f=null,updatePolicy:w=null,installKind:m=fs(),selfUrl:g=`http://127.0.0.1:${process.env.PORT||3362}`,apiToken:y=null,onDegraded:x=null,onRecovered:b=null,onConnected:R=null,ingestMode:_=["ws","http","auto"].includes(process.env.BOSTRAT_PLANE_INGEST)?process.env.BOSTRAT_PLANE_INGEST:"auto",deliveryTimeoutMs:C=oH,unackedRetryMs:U=rH,pingMs:B=nH,maxInflightEvents:T=aH,httpTimeoutMs:$=iH,stallBackoffMinMs:L=sH,fetchImpl:J=globalThis.fetch,log:A=console}){if(!e||!t)throw new Error("plane-link: url and token are required");if(typeof o!="function")throw new Error("plane-link: listTracks is required");e=sI(e);let S=g.replace(/^http/,"ws"),N=new Set,H=new Map,q=new Map,re=bn.join(aI,"plane-link","cursor.json"),we=bn.join(aI,"plane-link","dead-letter.ndjson"),Re=e.replace(/^ws(s?):\/\//,"http$1://").replace(/\/v1\/node\/?$/,""),Ee={},Z={},ye=new Map,X=null,Y=null,ie=0,ve=0,Ne=0,O=Promise.resolve(),D="ws",pe=0,Le=!1,Ce=0,Kt=!1,Tt=po,Jn=new Set,Sn=[],bt=null,k=null,h=!1,v=!1,P=iI,oe=null,ge=null,Me=null,tt=null,Ge=null,Gt=!1,wl=0;async function JO(){try{Ee=JSON.parse(await Lc.readFile(re,"utf8"))}catch{Ee={}}}function YO(){Gt=!0,!Me&&(Me=setTimeout(async()=>{if(Me=null,!!Gt){Gt=!1;try{await Lc.mkdir(bn.dirname(re),{recursive:!0}),await Lc.writeFile(re,JSON.stringify(Ee))}catch(F){A.error("[plane-link] cursor flush failed:",F?.message||F)}}},tH),Me.unref?.())}function it(F){return!k||k.readyState!==zg.OPEN?!1:(k.send(JSON.stringify(F)),!0)}function Va(F){let W=Date.now();for(let{trackId:I,event:j}of F){let te=ye.get(j.id);ye.set(j.id,{trackId:I,seq:j.seq,event:j,sentAt:W,firstSentAt:te?.firstSentAt??W,retryAt:W+U,tries:(te?.tries??0)+1,nacks:te?.nacks??0})}return D==="http"?(eM(F),!0):it({v:dt,ch:"events",type:"append",events:F})}function XO(F){let W=null;for(let I of ye.values())I.trackId===F&&(W==null||I.seq<W)&&(W=I.seq);return W}function Vp(F){let W=Z[F];if(W==null)return;let I=XO(F),j=I==null?W:Math.min(W,I-1);j>(Ee[F]??0)&&(Ee[F]=j,YO())}function Ja(){if(X=Date.now(),Y!=null){let F=Date.now()-Y;A.log(`[plane-link] spine sync recovered after ${Math.round(F/1e3)}s degraded (${ie} stall redial(s))`);let W=Y;Y=null,ie=0,ve=0,Le=!1,Ce=0;try{b?.({since:W,downMs:F})}catch(I){A.error(`[plane-link] onRecovered failed: ${I?.message||I}`)}}}function Jp(F){if(!Array.isArray(F)||!F.length)return;let W=new Set;for(let I of F){let j=ye.get(I);j&&(ye.delete(I),(Z[j.trackId]??0)<j.seq&&(Z[j.trackId]=j.seq),W.add(j.trackId))}for(let I of W)Vp(I);Ja()}function gb(F,W){Ne++;let I={at:Date.now(),trackId:F.trackId,seq:F.seq,id:F.event?.id??null,type:F.event?.type??null,reason:W,event:F.event??null};A.error(`[plane-link] DEAD-LETTER ${F.trackId} seq ${F.seq} (${I.type??"?"}): plane rejected it permanently (${W}) \u2014 kept in ${we}`),O=O.then(async()=>{await Lc.mkdir(bn.dirname(we),{recursive:!0}),await Lc.appendFile(we,JSON.stringify(I)+`
657
+ `)}).catch(j=>A.error(`[plane-link] dead-letter write failed: ${j?.message||j}`))}function yb(F,W,I,j=null){if(!Array.isArray(F)||!F.length)return;let te=new Set,xe=Date.now();for(let Ie of F){let We=ye.get(Ie);We&&(I?(ye.delete(Ie),gb(We,W),(Z[We.trackId]??0)<We.seq&&(Z[We.trackId]=We.seq),te.add(We.trackId)):(We.nacks++,We.retryAt=xe+Math.max(1e3,Number(j)||U)))}for(let Ie of te)Vp(Ie);Ja()}function bb(F=Date.now()){let W=1/0;for(let I of ye.values())I.firstSentAt<W&&(W=I.firstSentAt);return W===1/0?0:F-W}function kb(){if(!h||!ye.size)return;let F=Date.now(),W=bb(F);if(W<C||X!=null&&F-X<C||D==="http"&&Le||ve>F)return;ie++;let I=Math.min(L*2**(ie-1),lI);if(Y==null){Y=F-W,A.error(`[plane-link] DEGRADED: no ack or nack for ${Math.round(W/1e3)}s with ${ye.size} event(s) in flight (${D} door) \u2014 the plane is not answering appends`);try{x?.({since:Y,unacked:ye.size,oldestAgeMs:W,mode:D})}catch(j){A.error(`[plane-link] onDegraded failed: ${j?.message||j}`)}}if(D==="http"){Le=!0,Ce=F+I,A.error(`[plane-link] ingest circuit OPEN (stall #${ie}); probing /v1/ingest/health in ${Math.round(I/1e3)}s`);return}ve=F+I,A.error(`[plane-link] closing the link and redialing in ${Math.round(I/1e3)}s (stall redial #${ie})`);try{k?.terminate()}catch{}}function Yp(){if(!h)return;let F=Date.now();if(D==="http"&&Le)return;let W=[...ye.values()].filter(j=>j.event&&j.retryAt<=F&&!(D==="http"&&Jn.has(j.trackId)));if(!W.length)return;W.sort((j,te)=>j.trackId===te.trackId?j.seq-te.seq:j.trackId<te.trackId?-1:1),A.log(`[plane-link] re-sending ${W.length} unacked event(s) the plane never confirmed`);let I=D==="http"?Tt:po;if(D==="http"){let j=new Map;for(let te of W)(j.get(te.trackId)??j.set(te.trackId,[]).get(te.trackId)).push(te);for(let[,te]of j){if(pe>=Vg)return;Va(te.slice(0,I).map(xe=>({trackId:xe.trackId,event:xe.event})))}return}for(let j=0;j<W.length;j+=I){let te=W.slice(j,j+I).map(xe=>({trackId:xe.trackId,event:xe.event}));if(!Va(te))return}}async function ZO(F=null){for(;;){if(!h)return!1;let W=ye.size<T,I=D!=="http"||pe<Vg&&!Le&&(!F||!Jn.has(F));if(W&&I)return!0;await new Promise(j=>setTimeout(j,100))}}function Xp(){if(bt=null,!h||!Sn.length)return;let F=Sn;if(Sn=[],D!=="http"){for(let I=0;I<F.length;I+=po)Va(F.slice(I,I+po));return}let W=new Map;for(let I of F)(W.get(I.trackId)??W.set(I.trackId,[]).get(I.trackId)).push(I);for(let[I,j]of W){if(Jn.has(I)||pe>=Vg||Le){Sn.push(...j);continue}for(let te=0;te<j.length;te+=Tt)Va(j.slice(te,te+Tt))}Sn.length&&!bt&&(bt=setTimeout(Xp,uI),bt.unref?.())}let QO=F=>{let W=new Map;for(let{trackId:I,event:j}of F)(W.get(I)??W.set(I,[]).get(I)).push(j);return[...W].map(([I,j])=>({trackId:I,events:j}))},As=(F,W,I,{progress:j})=>{let te=Date.now();for(let{event:xe}of F){let Ie=ye.get(xe.id);Ie&&(Ie.nacks++,Ie.retryAt=te+Math.max(1e3,I||U))}j&&Ja()};async function eM(F){let W=new Set(F.map(I=>I.trackId));for(let I of W)Jn.add(I);pe++;try{let I=await J(`${Re}/v1/ingest`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/json"},body:JSON.stringify({node:n,batches:QO(F)}),signal:AbortSignal.timeout($)}),j=(Number(I.headers.get("retry-after"))||0)*1e3;if(I.status===200){let te=await I.json();Tt=po;for(let xe of te.results??[]){Jp(xe.acked??[]);let Ie=(We,Et)=>{let zt=new Map;for(let nt of We??[])(zt.get(nt.reason)??zt.set(nt.reason,[]).get(nt.reason)).push(nt.id);for(let[nt,Tb]of zt)yb(Tb,nt,Et,te.retryAfterMs??null)};Ie(xe.rejected,!0),Ie(xe.deferred,!1)}Jp(te.discarded??[]),Ja();return}if(I.status===429){As(F,"overloaded",j||5e3,{progress:!0});return}if(I.status===413&&F.length>1){Tt=Math.max(1,Math.floor(F.length/2)),A.error(`[plane-link] ingest request too large (${F.length} events) \u2014 halving batches to ${Tt}`),As(F,"too_large",1e3,{progress:!0});return}if(I.status===413){let te=ye.get(F[0].event.id);te&&(ye.delete(te.event.id),gb(te,"too_large"),(Z[te.trackId]??0)<te.seq&&(Z[te.trackId]=te.seq),Vp(te.trackId)),Ja();return}if(I.status===401||I.status===403){if(Date.now()-wl>=dI){wl=Date.now();let te="";try{te=(await I.json())?.error??""}catch{}A.error(`[plane-link] plane refused ingest (HTTP ${I.status}${te?`: ${te}`:""}) \u2014 events are held locally and retried; check this node's token/binding`)}As(F,`http_${I.status}`,6e4,{progress:!1});return}if(I.status===400){A.error(`[plane-link] plane rejected an ingest request as malformed (400) \u2014 holding ${F.length} event(s) for retry; this is a bug, not data`),As(F,"http_400",6e4,{progress:!1});return}As(F,`http_${I.status}`,j||5e3,{progress:!1})}catch(I){let j=I?.name==="TimeoutError"||I?.name==="AbortError";j&&F.length>1&&(Tt=Math.max(1,Math.floor(F.length/2)),A.error(`[plane-link] ingest request of ${F.length} event(s) outlived its ${$} ms deadline \u2014 halving batches to ${Tt}`)),As(F,j?"timeout":"network",5e3,{progress:!1})}finally{pe--;for(let I of W)Jn.delete(I)}}async function tM(){if(D!=="http"||!Le||!h||Kt)return;let F=Date.now();if(!(Ce>F)){Kt=!0;try{let W=await J(`${Re}/v1/ingest/health`,{headers:{authorization:`Bearer ${t}`},signal:AbortSignal.timeout($)});if(!W.ok)throw new Error(`HTTP ${W.status}`);A.log("[plane-link] ingest door answering \u2014 closing the circuit and re-sending"),Le=!1,Ce=0,ve=Date.now()+$+U+1e3;for(let I of ye.values())I.retryAt=Math.min(I.retryAt,Date.now());Yp()}catch(W){ie++;let I=Math.min(L*2**(ie-1),lI);Ce=Date.now()+I,A.error(`[plane-link] ingest door still not answering (${W?.message||W}); next probe in ${Math.round(I/1e3)}s`)}finally{Kt=!1}}}function xb(){let F=Date.now();return{mode:D,unacked:ye.size,oldestUnackedAgeMs:bb(F),lastProgressAt:X,degradedSince:Y,stallRedials:ie,deadLettered:Ne,http:D==="http"?{inFlight:pe,circuitOpen:Le,nextProbeInMs:Le?Math.max(0,Ce-F):0,batchCap:Tt}:null}}async function vb(){if(!i)return;let F;try{F=await i()}catch(I){A.error("[plane-link] metrics sample failed:",I?.message||I);return}let W=null;try{W=c?.()??null}catch{}F&&it({v:dt,ch:"ctl",type:"metrics",metrics:{...F,planeLink:xb(),...W?{delivery:W}:{}}})}function nM(){i&&(Ge&&clearInterval(Ge),vb(),Ge=setInterval(vb,u),Ge.unref?.())}async function rM(){let F;try{F=await o()}catch(W){A.error("[plane-link] backfill listTracks failed:",W?.message||W);return}it({v:dt,ch:"ctl",type:"tracks",ids:F.filter(W=>!W.transferredTo).map(W=>W.id).filter(W=>typeof W=="string")});for(let W of F){if(!h)return;let I;try{I=await K(W)}catch{continue}let j=Ee[W.id]??0,te=I.filter(Ie=>Ie.seq>j&&typeof Ie.id=="string"),xe=D==="http"?Tt:po;for(let Ie=0;Ie<te.length;Ie+=xe){if(!await ZO(W.id))return;let We=te.slice(Ie,Ie+Math.min(xe,D==="http"?Tt:po)).map(Et=>({trackId:W.id,event:Et}));if(!Va(We))return}}}function Sb(F){!h||!F?.trackId||typeof F.id!="string"||(Sn.push({trackId:F.trackId,event:F}),bt||(bt=setTimeout(Xp,uI),bt.unref?.()))}let Ya=new Map;async function oM(F){let{reqId:W,method:I,path:j,headers:te={},body:xe}=F,Ie=Object.fromEntries(Object.entries(te).filter(([,Et])=>Et!=null)),We=new AbortController;Ya.set(W,We);try{if(F.host){await sM(F,Ie,We);return}y&&(Ie["x-bostrat-token"]=y);let Et=await fetch(g+j,{method:I,headers:Ie,body:xe?Buffer.from(xe,"base64"):void 0,signal:We.signal}),zt=Object.fromEntries(Et.headers);for(let nt of["connection","keep-alive","transfer-encoding","upgrade","content-encoding","content-length"])delete zt[nt];if(zt["content-type"]||(zt["content-type"]="application/octet-stream"),it({v:dt,ch:"control",type:"http_head",reqId:W,status:Et.status,headers:zt}),Et.body){for await(let nt of Et.body)if(!it({v:dt,ch:"control",type:"http_data",reqId:W,data:Buffer.from(nt).toString("base64")}))break}it({v:dt,ch:"control",type:"http_end",reqId:W,error:null})}finally{Ya.delete(W)}}function sM(F,W,I){let{reqId:j,method:te,path:xe,body:Ie}=F,We=new URL(g);return new Promise(Et=>{let zt=J2.request({host:We.hostname,port:We.port,method:te,path:xe,headers:{...W,host:F.host},signal:I.signal},nt=>{let{connection:Tb,"keep-alive":z6,"transfer-encoding":V6,upgrade:J6,...aM}=nt.headers;it({v:dt,ch:"control",type:"http_head",reqId:j,status:nt.statusCode||502,headers:aM}),nt.on("data",iM=>{it({v:dt,ch:"control",type:"http_data",reqId:j,data:Buffer.from(iM).toString("base64")})||nt.destroy()}),nt.on("end",()=>{it({v:dt,ch:"control",type:"http_end",reqId:j,error:null}),Et()}),nt.on("error",()=>{it({v:dt,ch:"control",type:"http_end",reqId:j,error:"view upstream error"}),Et()})});zt.on("error",nt=>{it({v:dt,ch:"control",type:"http_end",reqId:j,error:nt?.message||"view request failed"}),Et()}),Ie&&zt.write(Buffer.from(Ie,"base64")),zt.end()})}function Ab(){if(v)return;k=new zg(e,{headers:{authorization:`Bearer ${t}`}}),k.on("open",async()=>{let W=null;try{W=await s?.()||null}catch{W=null}it({v:dt,ch:"ctl",type:"hello",nodeId:n,name:r,platform:process.platform,version:yn,installKind:m,...typeof w=="function"?{updatePolicy:w()}:w?{updatePolicy:w}:{},providers:X2(),...W?{agents:W}:{}})}),k.on("message",W=>{let I;try{I=JSON.parse(W)}catch{return}if(I.ch==="ctl"&&I.type==="hello_ok"){h=!0,P=iI,oe=null,A.log(`[plane-link] connected to plane as ${n}`);try{R?.()}catch{}if(typeof I.hashKey=="string"&&I.hashKey)try{l?.(I.hashKey)}catch{}I.minNodeVersion&&yn&&Fc(yn,I.minNodeVersion)&&A.error(`[plane-link] this node is bostrat-node ${yn}; the plane asks for \u2265${I.minNodeVersion} \u2014 update with: ${op(m)}`);try{p?.(typeof I.updatePolicy=="string"?I.updatePolicy:null)}catch{}let j=typeof I.latestNodeVersion=="string"?I.latestNodeVersion:null;if(j&&yn&&Fc(yn,j)&&!N.has(j)){N.add(j),A.log(`[plane-link] bostrat-node ${j} is available (this node runs ${yn}) \u2014 ${op(m)}`);try{d?.({current:yn,latest:j,min:I.minNodeVersion??null,installKind:m,required:!!(I.minNodeVersion&&Fc(yn,I.minNodeVersion))})}catch(xe){A.error(`[plane-link] update notice failed: ${xe?.message||xe}`)}}let te=I.ingest==="http";D=_==="ws"?"ws":_==="http"||te?"http":"ws",_==="http"&&!te&&A.error("[plane-link] BOSTRAT_PLANE_INGEST=http but this plane offers no HTTPS ingest door \u2014 events will fail until it does"),D==="http"&&A.log("[plane-link] spine rides the HTTPS ingest door"),Le=!1,Ce=0,Tt=po,tt&&clearInterval(tt),tt=setInterval(()=>{it({v:dt,ch:"ctl",type:"ping"}),kb(),tM().catch(()=>{}),Yp(),Sn.length&&!bt&&Xp()},B),tt.unref?.(),nM(),rM().catch(xe=>A.error("[plane-link] backfill failed:",xe?.message||xe));return}if(I.ch==="ctl"&&I.type==="hello_refused"){let j=typeof I.minNodeVersion=="string"?I.minNodeVersion:null,te=typeof I.latestNodeVersion=="string"?I.latestNodeVersion:null;A.error(`[plane-link] plane REFUSED this node: bostrat-node ${yn??"?"} is below its minimum ${j??"?"} \u2014 ${I.fix||op(m)}`),P=cI,oe=0;try{f?.({current:yn,min:j,latest:te,fix:I.fix||op(m),installKind:m})}catch(xe){A.error(`[plane-link] refusal handler failed: ${xe?.message||xe}`)}return}if(I.ch==="ctl"&&I.type==="update_policy"){try{p?.(typeof I.mode=="string"?I.mode:null)}catch{}return}if(I.ch==="ctl"&&I.type==="usage_caps"){_u(I.caps??{},{source:"plane",updatedAt:I.updatedAt??Date.now()}).then(j=>A.log(`[plane-link] spend caps ${Object.keys(j.caps).length?`updated (${Object.keys(j.caps).join(", ")})`:"cleared"} from plane`)).catch(j=>A.error("[plane-link] spend-caps push rejected:",j?.message||j));return}if(I.ch==="ctl"&&I.type==="transferred"&&Array.isArray(I.tracks)){Promise.resolve().then(()=>a?.(I.tracks)).catch(j=>A.error("[plane-link] transfer notice failed:",j?.message||j));return}if(I.ch==="events"&&I.type==="ack"&&Array.isArray(I.ids)){Jp(I.ids);return}if(I.ch==="events"&&I.type==="nack"&&Array.isArray(I.ids)){yb(I.ids,I.reason,I.permanent===!0,I.retryAfterMs??null);return}if(I.ch==="control"&&I.type==="http_open"){oM(I).catch(j=>it({v:dt,ch:"control",type:"http_end",reqId:I.reqId,error:j?.message||"tunnel error"}));return}if(I.ch==="control"&&I.type==="http_cancel"){Ya.get(I.reqId)?.abort();return}if(I.ch==="attach"&&I.type==="open"){let j=new zg(S+I.path,Array.isArray(I.protocols)?I.protocols:[],I.host?{headers:{host:I.host}}:void 0);H.set(I.streamId,j),q.set(I.streamId,[]),j.on("open",()=>{let xe=q.get(I.streamId)||[];q.delete(I.streamId);for(let{buf:Ie,bin:We}of xe)j.send(Ie,{binary:We})}),j.on("message",(xe,Ie)=>{let We=Ie?xe:Buffer.from(String(xe));it({v:dt,ch:"attach",type:"data",streamId:I.streamId,data:We.toString("base64"),...Ie?{bin:!0}:{}})});let te=()=>{q.delete(I.streamId),H.delete(I.streamId)&&it({v:dt,ch:"attach",type:"close",streamId:I.streamId})};j.on("close",te),j.on("error",te);return}if(I.ch==="attach"&&I.type==="data"){let j=H.get(I.streamId);if(!j)return;let te=Buffer.from(I.data,"base64"),xe=I.bin===!0,Ie=q.get(I.streamId);Ie?Ie.push({buf:te,bin:xe}):j.send(te,{binary:xe});return}if(I.ch==="attach"&&I.type==="close"){let j=H.get(I.streamId);H.delete(I.streamId),q.delete(I.streamId),j?.close();return}});let F=()=>{h&&A.log("[plane-link] disconnected from plane"),h=!1,tt&&(clearInterval(tt),tt=null),Ge&&(clearInterval(Ge),Ge=null),ye.clear(),Z={},Sn=[],bt&&(clearTimeout(bt),bt=null),Jn.clear();for(let j of H.values())j.close();H.clear(),q.clear();for(let j of Ya.values())j.abort();if(Ya.clear(),v||ge)return;oe==null&&(oe=Date.now());let W=Date.now()-oe<Z2,I=Math.max(W?Q2+Math.random()*eH:P,ve-Date.now());ge=setTimeout(()=>{ge=null,Ab()},I),ge.unref?.(),W||(P=Math.min(P*2,cI))};k.on("close",F),k.on("error",W=>{let I=/Unexpected server response: (\d+)/.exec(W?.message||"")?.[1];(I==="401"||I==="403")&&Date.now()-wl>=dI&&(wl=Date.now(),A.error(`[plane-link] plane refused this node's credentials (HTTP ${I}) \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)`)),F()})}return Je.on("event",Sb),JO().then(Ab),{stop:()=>{v=!0,Je.off("event",Sb),ge&&clearTimeout(ge),Me&&clearTimeout(Me),tt&&clearInterval(tt),Ge&&clearInterval(Ge),bt&&clearTimeout(bt),it({v:dt,ch:"ctl",type:"bye",reason:"shutdown"}),k?.close()},status:()=>({connected:h,nodeId:n,cursor:{...Ee},inflight:ye.size,...xb()}),_tick:()=>{kb(),Yp()}}}Zl();var ap=(()=>{try{return dH(import.meta.url)("../package.json").version||null}catch{return null}})(),pH=process.env.BOSTRAT_STATE_DIR||pt.join(process.env.HOME||lH.tmpdir(),".bostrat"),wI=pt.join(pH,"self-update"),ip=pt.join(wI,"status.json"),fH=1440*6e4,mH=6e4,Uc=new Set(["npm-global","git-checkout"]);function gI({kind:e=fs(),env:t=process.env}={}){let n=String(t.BOSTRAT_UPDATE_POLICY||"").trim();return["auto","prompt","off"].includes(n)?n:Uc.has(e)?e==="git-checkout"||hH(t)?"auto":"prompt":"off"}function hH(e=process.env){return!!(e.INVOCATION_ID||e.XPC_SERVICE_NAME&&e.XPC_SERVICE_NAME!=="0")}var Ut=e=>`'${String(e).replace(/'/g,"'\\''")}'`;function wH({kind:e,to:t,from:n=ap,statusFile:r=ip,logFile:o=pt.join(wI,"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||pt.resolve(pt.dirname(new URL(import.meta.url).pathname),"..",".."),startedAt:u=Date.now()}={}){if(!Uc.has(e))throw new Error(`self-update: install kind "${e}" is not actionable here`);if(!/^\d+\.\d+\.\d+$/.test(String(t)))throw new Error(`self-update: bad target version "${t}"`);if(n&&!/^\d+\.\d+\.\d+$/.test(String(n)))throw new Error(`self-update: bad current version "${n}"`);let d=(g,y="")=>`write_status ${Ut(g)} ${y}`,p=process.platform==="darwin"?`launchctl kickstart -k gui/${c}/${i}`:`systemctl --user restart ${Ut(i)}`,f=`
654
658
  health() {
655
659
  for i in $(seq 1 45); do
656
660
  sleep 1
@@ -661,20 +665,20 @@ health() {
661
665
  # bostrat-node self-update one-shot \u2014 written by agent/src/self-update.js.
662
666
  # ${n??"?"} \u2192 ${t} (${e}). Status: ${r}
663
667
  set -u
664
- FROM=${jt(n??"")}
665
- TO=${jt(t)}
666
- STATUS_FILE=${jt(r)}
668
+ FROM=${Ut(n??"")}
669
+ TO=${Ut(t)}
670
+ STATUS_FILE=${Ut(r)}
667
671
  STARTED_AT=${Number(u)}
668
672
  write_status() { # <status> [error]
669
673
  local err="\${2:-}"
670
674
  err="\${err//\\\\/\\\\\\\\}"; err="\${err//\\"/\\\\\\"}"
671
675
  printf '{"status":"%s","from":"%s","to":"%s","kind":"%s","startedAt":%s,"updatedAt":%s%s}\\n' \\
672
- "$1" "$FROM" "$TO" ${jt(e)} "$STARTED_AT" "$(date +%s000)" \\
676
+ "$1" "$FROM" "$TO" ${Ut(e)} "$STARTED_AT" "$(date +%s000)" \\
673
677
  "\${err:+,\\"error\\":\\"$err\\"}" > "$STATUS_FILE.tmp" && mv "$STATUS_FILE.tmp" "$STATUS_FILE"
674
678
  }
675
679
  ${f}
676
- `;if(e==="npm-global"){let g=a?dt.join(a,"bin","npm"):"npm",y=a?`export PATH=${jt(dt.join(a,"bin"))}:"$PATH"
677
- `:"",x=a?` --prefix ${jt(a)}`:"",b=O=>`${jt(g)} install -g "bostrat-node@${O}" --no-audit --no-fund${x}`;return w+y+`
680
+ `;if(e==="npm-global"){let g=a?pt.join(a,"bin","npm"):"npm",y=a?`export PATH=${Ut(pt.join(a,"bin"))}:"$PATH"
681
+ `:"",x=a?` --prefix ${Ut(a)}`:"",b=R=>`${Ut(g)} install -g "bostrat-node@${R}" --no-audit --no-fund${x}`;return w+y+`
678
682
  ${d("updating",'"" ')}
679
683
  if ! ${b("$TO")}; then
680
684
  ${d("failed",'"npm install failed"')}
@@ -697,8 +701,8 @@ if [ -n "$FROM" ] && ${b("$FROM")} && ${p} && health; then
697
701
  fi
698
702
  ${d("failed",'"agent did not answer after the update AND the rollback"')}
699
703
  exit 1
700
- `}let m=g=>`( cd ${jt(l)} && git fetch -q origin main --tags && git show origin/main:scripts/deploy-pi.sh > "$TMP_SCRIPT" && bash "$TMP_SCRIPT" "v${g}" )`;return w+`
701
- LIVE=${jt(l)}
704
+ `}let m=g=>`( cd ${Ut(l)} && git fetch -q origin main --tags && git show origin/main:scripts/deploy-pi.sh > "$TMP_SCRIPT" && bash "$TMP_SCRIPT" "v${g}" )`;return w+`
705
+ LIVE=${Ut(l)}
702
706
  TMP_SCRIPT="$(mktemp)"
703
707
  trap 'rm -f "$TMP_SCRIPT"' EXIT
704
708
  # "restarting" is written BEFORE deploy-pi.sh runs (it does fetch \u2192 build \u2192
@@ -715,65 +719,65 @@ if [ -n "$FROM" ] && ${m("$FROM")}; then
715
719
  fi
716
720
  ${d("failed",'"deploy-pi.sh v$TO failed AND the rollback failed"')}
717
721
  exit 1
718
- `}async function jc(e=Kd){try{return JSON.parse(await io.readFile(e,"utf8"))}catch{return null}}var X2=new Set(["updating","restarting","rolling-back"]),Gd=e=>!!(e&&X2.has(e.status));async function zd({to:e,from:t=Wd,kind:n=ts(),reason:r="manual",statusFile:o=Kd,spawnImpl:s=W2,now:a=Date.now,npmPrefix:i=void 0,log:c=console}={}){if(!e)return{ok:!1,reason:"no target version"};if(!Bc.has(n))return{ok:!1,reason:`install kind "${n}" updates elsewhere`};if(t&&!Dc(t,e))return{ok:!1,reason:`already on ${t} (target ${e})`};let l=await jc(o);if(Gd(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 io.mkdir(dt.dirname(o),{recursive:!0});let u=i!==void 0?i:n==="npm-global"?Mf(await Z2())||dt.resolve(dt.dirname(process.execPath),".."):null,d=Y2({kind:n,to:e,from:t,statusFile:o,npmPrefix:u,startedAt:a()}),p=dt.join(dt.dirname(o),`update-${e}.sh`),f=dt.join(dt.dirname(o),"last.log");await io.writeFile(p,d,{mode:448}),await io.writeFile(o,JSON.stringify({status:"updating",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a()}));let w=eI.existsSync("/run/systemd/system")&&await Q2("systemd-run")?["systemd-run",["--user","--collect","--quiet",`--unit=bostrat-self-update-${e}`,"--property=KillMode=process","bash",p]]:["setsid",["-f","bash","-c",`exec bash ${jt(p)} >> ${jt(f)} 2>&1`]];try{s(w[0],w[1],{detached:!0,stdio:"ignore"}).unref?.()}catch(m){return await io.writeFile(o,JSON.stringify({status:"failed",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a(),error:`could not spawn updater: ${m?.message||m}`})),{ok:!1,reason:`could not spawn updater: ${m?.message||m}`}}return c.log?.(`[self-update] ${t??"?"} \u2192 ${e} (${n}, ${r}) started \u2014 status ${o}`),{ok:!0,to:e,from:t,kind:n,scriptFile:p,statusFile:o}}async function Z2(){try{return await io.realpath(new URL(import.meta.url).pathname)}catch{return""}}async function Q2(e){for(let t of String(process.env.PATH||"").split(dt.delimiter))try{return await io.access(dt.join(t,e),eI.constants.X_OK),!0}catch{}return!1}var eH=45*6e4;async function rI({statusFile:e=Kd,current:t=Wd,now:n=Date.now,staleMs:r=eH}={}){let o=await jc(e);if(!o)return null;let s=a=>io.writeFile(e,JSON.stringify(a)).catch(()=>{});if(Gd(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 oI({isBusy:e,start:t=zd,onStuck:n=null,onStarted:r=null,tickMs:o=V2,stuckMs:s=z2,now:a=Date.now,setIntervalImpl:i=setInterval,clearIntervalImpl:c=clearInterval,log:l=console}={}){let u=null,d=()=>{u?.timer&&c(u.timer),u=null},p=async()=>{if(!u)return;let f=!0;try{f=await e()!==!1}catch{f=!0}if(f){if(!u.stuckFired&&a()-u.since>=s){u.stuckFired=!0;try{await n?.({to:u.to,from:u.from,since:u.since})}catch{}}return}let w=u;d();let m=await t({to:w.to,from:w.from,kind:w.kind,reason:"auto"});l.log?.(`[self-update] stasis reached \u2192 ${m.ok?"started":`not started: ${m.reason}`}`);try{await r?.({...w,result:m})}catch{}};return{arm({to:f,from:w=Wd,kind:m=ts()}){return u?.to===f?!1:(d(),u={to:f,from:w,kind:m,since:a(),stuckFired:!1,timer:i(p,o)},u.timer.unref?.(),!0)},tick:p,cancel:d,get armed(){return u?{to:u.to,from:u.from,kind:u.kind,since:u.since}:null}}}de();pt();var sI=(...e)=>fetch(...e);function aI(e=process.env){return!!(Re(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Cg(e=process.env){if(!aI(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 sI(`${Re(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 Ng(e=process.env){if(!aI(e))throw new Error("no plane configured \u2014 the roadmap lives on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let t=new AbortController,n=setTimeout(()=>t.abort(),1e4);try{let r=await sI(`${Re(e)}/v1/roadmap`,{headers:{authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN}`},signal:t.signal}),o=await r.json().catch(()=>({}));if(!r.ok)throw new Error(o?.error||`plane answered ${r.status}`);return{people:Array.isArray(o.people)?o.people:[],slots:Array.isArray(o.slots)?o.slots:[],reservations:Array.isArray(o.reservations)?o.reservations:[],tray:Array.isArray(o.tray)?o.tray:[],circuits:Array.isArray(o.circuits)?o.circuits:[]}}finally{clearTimeout(n)}}async function Aa(e,t=process.env){let n=String(e??"").trim();if(!n)throw new Error("a circuit name or id is required");let r=await Cg(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 Vd(e,t,{source:n="chat"}={}){return M(e,{type:"track.circuit.tagged",actor:"orchestrator",source:"orchestrator",payload:t?{circuitId:t.id,circuitName:t.name??null,source:n}:{circuitId:null,source:n}})}de();pt();var tH=(...e)=>fetch(...e);async function Jd(e,t,n,r=process.env){if(!(Re(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 tH(`${Re(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 nH(e,t=process.env){return Jd("POST","/v1/circuits",{name:e},t).then(n=>n.circuit)}async function iI({circuitRef:e,newCircuitName:t,name:n,markdown:r},o=process.env){let s=t?await nH(t,o):await Aa(e,o),a=await Jd("POST","/v1/blueprints",{circuitId:s.id,name:n,markdown:r},o);return{circuit:s,...a}}async function Pg(e,t=process.env){let n=await Aa(e,t),r=await Jd("GET",`/v1/blueprints/${encodeURIComponent(n.id)}`,null,t);return{circuit:n,...r}}async function Dg(e,t=process.env){return(await Jd("GET","/v1/circuits",null,t)).memberships?.[e]??null}async function cI(e,t,n,r=process.env){let{blueprint:o,items:s}=await Pg(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 M(e,{type:"blueprint.item.bound",actor:"orchestrator",source:"orchestrator",payload:{itemIds:n,blueprintId:o.id,source:"cli"}}),{blueprint:o,itemIds:n}}de();pt();var rH=(...e)=>fetch(...e);async function oH(e,t,n,r=process.env){if(!(Re(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 rH(`${Re(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 lI=72,Bg=160;async function uI(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>lI)throw new Error(`the title is the choice as a LABEL \u2014 ${lI} 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 ${Bg} chars) a reader can act on without opening the record`);if(c.length>Bg)throw new Error(`the summary is one sentence \u2014 ${Bg} 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 M(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 dI(e,t=process.env){return oH("GET",`/v1/decisions?track=${encodeURIComponent(e)}`,null,t)}ww();de();import Wc from"node:fs/promises";import op from"node:path";import JH from"node:os";Er();import sH from"node:fs/promises";import pI from"node:path";import aH from"node:os";var fI=()=>pI.join(process.env.BOSTRAT_STATE_DIR||pI.join(process.env.HOME||aH.tmpdir(),".bostrat"),"integrations.json");async function kr(){try{return JSON.parse(await sH.readFile(fI(),"utf8"))||{}}catch{return{}}}var Yd=["linked","prOpened","prMerged","create"],jg=["prompt","auto","off"],iH={create:["prompt","off"]},mI=e=>iH[e]??jg;function Xd(e){let t=e.linear||{},n=t.transitions===!0?"auto":"prompt",r={};for(let o of Yd){let s=mI(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 ns(){let e=await kr(),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:Xd(e),defaultTeam:n}:null}async function Zd(){let e=await kr(),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:Xd(e)}}async function Lg(){return Xd(await kr())}async function hI(e){let t=Object.entries(e||{});if(!t.length)throw new Error(`nothing to set \u2014 phases: ${Yd.join(", ")}`);for(let[r,o]of t){if(!Yd.includes(r))throw new Error(`unknown phase "${r}" \u2014 configurable phases: ${Yd.join(", ")}`);let s=mI(r);if(!s.includes(o))throw new Error(s.length<jg.length?`mode "${o}" not allowed for "${r}" \u2014 ${r} is always confirmed (modes: ${s.join(", ")})`:`unknown mode "${o}" \u2014 modes: ${jg.join(", ")}`)}let n=await kr();return n.ticketFlow={...Xd(n),...Object.fromEntries(t)},n.linear&&(delete n.linear.ticketFlow,delete n.linear.transitions),await Et(fI(),n,{mode:384}),n.ticketFlow}async function Lc(){let e=(await kr()).deepgram||{},t=process.env.DEEPGRAM_API_KEY||e.apiKey;return t?{apiKey:t}:null}async function cH(){let e=(await kr()).openai||{},t=process.env.BOSTRAT_OPENAI_API_KEY||e.apiKey;return t?{apiKey:t}:null}var lH={openai:{model:"gpt-realtime-2.1-mini",voice:"marin"}};async function Qd(){let t=(await kr()).voiceChat||{},n=t.provider||"openai",r=lH[n];if(!r)return null;let o=n==="openai"?await cH():null;return o?{provider:n,model:t.model||r.model,voice:t.voice||r.voice,apiKey:o.apiKey}:null}async function wI(){let e=(await kr()).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 rs(){let e=(await kr()).slack||{},t=process.env.BOSTRAT_SLACK_BOT_TOKEN||e.botToken,n=process.env.BOSTRAT_SLACK_APP_TOKEN||e.appToken;return!t||!n?null:{botToken:t,appToken:n,channel:process.env.BOSTRAT_SLACK_CHANNEL||e.channel||null,maxConcurrent:Number.isInteger(e.maxConcurrent)&&e.maxConcurrent>0?e.maxConcurrent:2}}de();Ir();Lr();da();import Uc from"node:fs/promises";import AI from"node:path";import NH from"node:os";import{randomUUID as EI}from"node:crypto";var Ug={};Dp(Ug,{createComment:()=>yH,findIssueUrl:()=>fH,issueStates:()=>xH,mdToAdf:()=>bI,moveIssue:()=>vH,parseIssueRef:()=>pH,resolveIssue:()=>mH,uploadImage:()=>bH,upsertCard:()=>hH,whoami:()=>Fg});var Ea=e=>String(e.baseUrl||"").replace(/\/$/,""),yI=e=>`Basic ${Buffer.from(`${e.email}:${e.apiToken}`).toString("base64")}`;async function os(e,t,n,r){let o=await fetch(`${Ea(e)}${n}`,{method:t,headers:{authorization:yI(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 uH=/\/browse\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,dH=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function pH(e){let t=String(e||"").trim();if(/^https?:\/\//i.test(t)){let r=t.match(uH);return r?r[1].toUpperCase():null}let n=t.match(dH);return n?n[1]:null}function fH(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 mH(e,t){let n;try{n=await os(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:`${Ea(e)}/browse/${n.key}`,state:n.fields?.status?.name??null}}async function hH(e,t,{url:n,title:r,subtitle:o}){await os(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 wH=/(!\[[^\]]*\]\([^)\s]+\)|\*\*[^*\n]+\*\*|`[^`\n]+`|_[^_\n]+_|https?:\/\/[^\s)]+)/g;function gH(e){let t=[],n=0;for(let r of e.matchAll(wH)){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 bI(e){let t=String(e??"").split(/\n{2,}/).map(n=>n.trim()).filter(Boolean).map(n=>{let r=[];return n.split(`
719
- `).forEach((o,s)=>{s>0&&r.push({type:"hardBreak"}),r.push(...gH(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 yH(e,t,n){let r=await os(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/comment`,{body:bI(n)});return r?.id?`${Ea(e)}/browse/${t.key}?focusedCommentId=${r.id}`:null}async function Fg(e){let t=await os(e,"GET","/rest/api/3/myself"),n=null;try{n=new URL(Ea(e)).host}catch{n=e.baseUrl??null}return{user:t?.displayName??t?.emailAddress??null,org:n}}async function bH(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(`${Ea(e)}/rest/api/3/issue/${encodeURIComponent(t)}/attachments`,{method:"POST",headers:{authorization:yI(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??`${Ea(e)}/rest/api/3/attachment/content/${c.id}`}var kH={new:"unstarted",indeterminate:"started",done:"completed"},gI=e=>kH[e?.key]??"started";async function xH(e,t){let n=encodeURIComponent(t.key),[r,o]=await Promise.all([os(e,"GET",`/rest/api/3/issue/${n}?fields=status`),os(e,"GET",`/rest/api/3/issue/${n}/transitions`)]),s=r?.fields?.status??null,a=s?{id:`status:${s.id}`,name:s.name,type:gI(s.statusCategory)}:null,i=(o?.transitions??[]).map((c,l)=>({id:c.id,name:c.to?.name??c.name,type:gI(c.to?.statusCategory),position:l}));return{current:a,states:i}}async function vH(e,t,n){await os(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/transitions`,{transition:{id:String(n)}})}var Kg={};Dp(Kg,{createComment:()=>RH,createIssue:()=>Wg,createProject:()=>qg,findIssueUrl:()=>_H,issueStates:()=>MH,moveIssue:()=>CH,parseIssueRef:()=>EH,resolveIssue:()=>IH,teams:()=>_a,uploadImage:()=>OH,upsertCard:()=>$H,whoami:()=>Hg});var SH=()=>process.env.BOSTRAT_LINEAR_API_URL||"https://api.linear.app/graphql";async function Wn(e,t,n={}){let r=await fetch(SH(),{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 TH=/linear\.app\/[^/\s]+\/issue\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,AH=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function EH(e){let t=String(e||"").trim(),n=t.match(TH);if(n)return n[1].toUpperCase();let r=t.match(AH);return r?r[1]:null}function _H(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 IH(e,t){let r=(await Wn(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 $H(e,t,{url:n,title:r,subtitle:o}){let s=await Wn(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 RH(e,t,n){let r=await Wn(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 Hg(e){let t=await Wn(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 OH(e,{filename:t,contentType:n,buffer:r}){let o=await Wn(e,`mutation($contentType: String!, $filename: String!, $size: Int!) {
722
+ `}async function Hc(e=ip){try{return JSON.parse(await fo.readFile(e,"utf8"))}catch{return null}}var gH=new Set(["updating","restarting","rolling-back"]),cp=e=>!!(e&&gH.has(e.status));async function lp({to:e,from:t=ap,kind:n=fs(),reason:r="manual",statusFile:o=ip,spawnImpl:s=uH,now:a=Date.now,npmPrefix:i=void 0,log:c=console}={}){if(!e)return{ok:!1,reason:"no target version"};if(!Uc.has(n))return{ok:!1,reason:`install kind "${n}" updates elsewhere`};if(t&&!Fc(t,e))return{ok:!1,reason:`already on ${t} (target ${e})`};let l=await Hc(o);if(cp(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 fo.mkdir(pt.dirname(o),{recursive:!0});let u=i!==void 0?i:n==="npm-global"?zf(await yH())||pt.resolve(pt.dirname(process.execPath),".."):null,d=wH({kind:n,to:e,from:t,statusFile:o,npmPrefix:u,startedAt:a()}),p=pt.join(pt.dirname(o),`update-${e}.sh`),f=pt.join(pt.dirname(o),"last.log");await fo.writeFile(p,d,{mode:448}),await fo.writeFile(o,JSON.stringify({status:"updating",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a()}));let w=hI.existsSync("/run/systemd/system")&&await bH("systemd-run")?["systemd-run",["--user","--collect","--quiet",`--unit=bostrat-self-update-${e}`,"--property=KillMode=process","bash",p]]:["setsid",["-f","bash","-c",`exec bash ${Ut(p)} >> ${Ut(f)} 2>&1`]];try{s(w[0],w[1],{detached:!0,stdio:"ignore"}).unref?.()}catch(m){return await fo.writeFile(o,JSON.stringify({status:"failed",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a(),error:`could not spawn updater: ${m?.message||m}`})),{ok:!1,reason:`could not spawn updater: ${m?.message||m}`}}return c.log?.(`[self-update] ${t??"?"} \u2192 ${e} (${n}, ${r}) started \u2014 status ${o}`),{ok:!0,to:e,from:t,kind:n,scriptFile:p,statusFile:o}}async function yH(){try{return await fo.realpath(new URL(import.meta.url).pathname)}catch{return""}}async function bH(e){for(let t of String(process.env.PATH||"").split(pt.delimiter))try{return await fo.access(pt.join(t,e),hI.constants.X_OK),!0}catch{}return!1}var kH=45*6e4;async function yI({statusFile:e=ip,current:t=ap,now:n=Date.now,staleMs:r=kH}={}){let o=await Hc(e);if(!o)return null;let s=a=>fo.writeFile(e,JSON.stringify(a)).catch(()=>{});if(cp(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 bI({isBusy:e,start:t=lp,onStuck:n=null,onStarted:r=null,tickMs:o=mH,stuckMs:s=fH,now:a=Date.now,setIntervalImpl:i=setInterval,clearIntervalImpl:c=clearInterval,log:l=console}={}){let u=null,d=()=>{u?.timer&&c(u.timer),u=null},p=async()=>{if(!u)return;let f=!0;try{f=await e()!==!1}catch{f=!0}if(f){if(!u.stuckFired&&a()-u.since>=s){u.stuckFired=!0;try{await n?.({to:u.to,from:u.from,since:u.since})}catch{}}return}let w=u;d();let m=await t({to:w.to,from:w.from,kind:w.kind,reason:"auto"});l.log?.(`[self-update] stasis reached \u2192 ${m.ok?"started":`not started: ${m.reason}`}`);try{await r?.({...w,result:m})}catch{}};return{arm({to:f,from:w=ap,kind:m=fs()}){return u?.to===f?!1:(d(),u={to:f,from:w,kind:m,since:a(),stuckFired:!1,timer:i(p,o)},u.timer.unref?.(),!0)},tick:p,cancel:d,get armed(){return u?{to:u.to,from:u.from,kind:u.kind,since:u.since}:null}}}fe();ft();var kI=(...e)=>fetch(...e);function xI(e=process.env){return!!(Oe(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Jg(e=process.env){if(!xI(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 kI(`${Oe(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 Yg(e=process.env){if(!xI(e))throw new Error("no plane configured \u2014 the roadmap lives on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let t=new AbortController,n=setTimeout(()=>t.abort(),1e4);try{let r=await kI(`${Oe(e)}/v1/roadmap`,{headers:{authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN}`},signal:t.signal}),o=await r.json().catch(()=>({}));if(!r.ok)throw new Error(o?.error||`plane answered ${r.status}`);return{people:Array.isArray(o.people)?o.people:[],slots:Array.isArray(o.slots)?o.slots:[],reservations:Array.isArray(o.reservations)?o.reservations:[],tray:Array.isArray(o.tray)?o.tray:[],circuits:Array.isArray(o.circuits)?o.circuits:[]}}finally{clearTimeout(n)}}async function Na(e,t=process.env){let n=String(e??"").trim();if(!n)throw new Error("a circuit name or id is required");let r=await Jg(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 up(e,t,{source:n="chat"}={}){return M(e,{type:"track.circuit.tagged",actor:"orchestrator",source:"orchestrator",payload:t?{circuitId:t.id,circuitName:t.name??null,source:n}:{circuitId:null,source:n}})}fe();ft();var xH=(...e)=>fetch(...e);async function dp(e,t,n,r=process.env){if(!(Oe(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 xH(`${Oe(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 vH(e,t=process.env){return dp("POST","/v1/circuits",{name:e},t).then(n=>n.circuit)}async function vI({circuitRef:e,newCircuitName:t,name:n,markdown:r},o=process.env){let s=t?await vH(t,o):await Na(e,o),a=await dp("POST","/v1/blueprints",{circuitId:s.id,name:n,markdown:r},o);return{circuit:s,...a}}async function Xg(e,t=process.env){let n=await Na(e,t),r=await dp("GET",`/v1/blueprints/${encodeURIComponent(n.id)}`,null,t);return{circuit:n,...r}}async function Zg(e,t=process.env){return(await dp("GET","/v1/circuits",null,t)).memberships?.[e]??null}async function SI(e,t,n,r=process.env){let{blueprint:o,items:s}=await Xg(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 M(e,{type:"blueprint.item.bound",actor:"orchestrator",source:"orchestrator",payload:{itemIds:n,blueprintId:o.id,source:"cli"}}),{blueprint:o,itemIds:n}}fe();ft();var SH=(...e)=>fetch(...e);async function AH(e,t,n,r=process.env){if(!(Oe(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 SH(`${Oe(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 AI=72,Qg=160;async function TI(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>AI)throw new Error(`the title is the choice as a LABEL \u2014 ${AI} 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 ${Qg} chars) a reader can act on without opening the record`);if(c.length>Qg)throw new Error(`the summary is one sentence \u2014 ${Qg} 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 M(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 EI(e,t=process.env){return AH("GET",`/v1/decisions?track=${encodeURIComponent(e)}`,null,t)}Cw();fe();import Vc from"node:fs/promises";import kp from"node:path";import hW from"node:os";Or();import TH from"node:fs/promises";import _I from"node:path";import EH from"node:os";var II=()=>_I.join(process.env.BOSTRAT_STATE_DIR||_I.join(process.env.HOME||EH.tmpdir(),".bostrat"),"integrations.json");async function Tr(){try{return JSON.parse(await TH.readFile(II(),"utf8"))||{}}catch{return{}}}var pp=["linked","prOpened","prMerged","create"],ey=["prompt","auto","off"],_H={create:["prompt","off"]},$I=e=>_H[e]??ey;function fp(e){let t=e.linear||{},n=t.transitions===!0?"auto":"prompt",r={};for(let o of pp){let s=$I(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 ms(){let e=await Tr(),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:fp(e),defaultTeam:n}:null}async function mp(){let e=await Tr(),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:fp(e)}}async function ty(){return fp(await Tr())}async function RI(e){let t=Object.entries(e||{});if(!t.length)throw new Error(`nothing to set \u2014 phases: ${pp.join(", ")}`);for(let[r,o]of t){if(!pp.includes(r))throw new Error(`unknown phase "${r}" \u2014 configurable phases: ${pp.join(", ")}`);let s=$I(r);if(!s.includes(o))throw new Error(s.length<ey.length?`mode "${o}" not allowed for "${r}" \u2014 ${r} is always confirmed (modes: ${s.join(", ")})`:`unknown mode "${o}" \u2014 modes: ${ey.join(", ")}`)}let n=await Tr();return n.ticketFlow={...fp(n),...Object.fromEntries(t)},n.linear&&(delete n.linear.ticketFlow,delete n.linear.transitions),await It(II(),n,{mode:384}),n.ticketFlow}async function Wc(){let e=(await Tr()).deepgram||{},t=process.env.DEEPGRAM_API_KEY||e.apiKey;return t?{apiKey:t}:null}async function IH(){let e=(await Tr()).openai||{},t=process.env.BOSTRAT_OPENAI_API_KEY||e.apiKey;return t?{apiKey:t}:null}var $H={openai:{model:"gpt-realtime-2.1-mini",voice:"marin"}};async function hp(){let t=(await Tr()).voiceChat||{},n=t.provider||"openai",r=$H[n];if(!r)return null;let o=n==="openai"?await IH():null;return o?{provider:n,model:t.model||r.model,voice:t.voice||r.voice,apiKey:o.apiKey}:null}async function OI(){let e=(await Tr()).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 hs(){let e=(await Tr()).slack||{},t=process.env.BOSTRAT_SLACK_BOT_TOKEN||e.botToken,n=process.env.BOSTRAT_SLACK_APP_TOKEN||e.appToken;return!t||!n?null:{botToken:t,appToken:n,channel:process.env.BOSTRAT_SLACK_CHANNEL||e.channel||null,maxConcurrent:Number.isInteger(e.maxConcurrent)&&e.maxConcurrent>0?e.maxConcurrent:2}}fe();Cr();Wr();ka();import Kc from"node:fs/promises";import FI from"node:path";import eW from"node:os";import{randomUUID as UI}from"node:crypto";var ry={};Zp(ry,{createComment:()=>jH,findIssueUrl:()=>CH,issueStates:()=>UH,mdToAdf:()=>NI,moveIssue:()=>HH,parseIssueRef:()=>MH,resolveIssue:()=>NH,uploadImage:()=>LH,upsertCard:()=>PH,whoami:()=>ny});var Pa=e=>String(e.baseUrl||"").replace(/\/$/,""),CI=e=>`Basic ${Buffer.from(`${e.email}:${e.apiToken}`).toString("base64")}`;async function ws(e,t,n,r){let o=await fetch(`${Pa(e)}${n}`,{method:t,headers:{authorization:CI(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 RH=/\/browse\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,OH=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function MH(e){let t=String(e||"").trim();if(/^https?:\/\//i.test(t)){let r=t.match(RH);return r?r[1].toUpperCase():null}let n=t.match(OH);return n?n[1]:null}function CH(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 NH(e,t){let n;try{n=await ws(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:`${Pa(e)}/browse/${n.key}`,state:n.fields?.status?.name??null}}async function PH(e,t,{url:n,title:r,subtitle:o}){await ws(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 DH=/(!\[[^\]]*\]\([^)\s]+\)|\*\*[^*\n]+\*\*|`[^`\n]+`|_[^_\n]+_|https?:\/\/[^\s)]+)/g;function BH(e){let t=[],n=0;for(let r of e.matchAll(DH)){r.index>n&&t.push({type:"text",text:e.slice(n,r.index)});let o=r[0];if(o.startsWith("![")){let[,s,a]=o.match(/^!\[([^\]]*)\]\(([^)\s]+)\)$/);t.push({type:"text",text:s||a,marks:[{type:"link",attrs:{href:a}}]})}else o.startsWith("**")?t.push({type:"text",text:o.slice(2,-2),marks:[{type:"strong"}]}):o.startsWith("`")?t.push({type:"text",text:o.slice(1,-1),marks:[{type:"code"}]}):o.startsWith("_")?t.push({type:"text",text:o.slice(1,-1),marks:[{type:"em"}]}):t.push({type:"text",text:o,marks:[{type:"link",attrs:{href:o}}]});n=r.index+o.length}return n<e.length&&t.push({type:"text",text:e.slice(n)}),t}function NI(e){let t=String(e??"").split(/\n{2,}/).map(n=>n.trim()).filter(Boolean).map(n=>{let r=[];return n.split(`
723
+ `).forEach((o,s)=>{s>0&&r.push({type:"hardBreak"}),r.push(...BH(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 jH(e,t,n){let r=await ws(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/comment`,{body:NI(n)});return r?.id?`${Pa(e)}/browse/${t.key}?focusedCommentId=${r.id}`:null}async function ny(e){let t=await ws(e,"GET","/rest/api/3/myself"),n=null;try{n=new URL(Pa(e)).host}catch{n=e.baseUrl??null}return{user:t?.displayName??t?.emailAddress??null,org:n}}async function LH(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(`${Pa(e)}/rest/api/3/issue/${encodeURIComponent(t)}/attachments`,{method:"POST",headers:{authorization:CI(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??`${Pa(e)}/rest/api/3/attachment/content/${c.id}`}var FH={new:"unstarted",indeterminate:"started",done:"completed"},MI=e=>FH[e?.key]??"started";async function UH(e,t){let n=encodeURIComponent(t.key),[r,o]=await Promise.all([ws(e,"GET",`/rest/api/3/issue/${n}?fields=status`),ws(e,"GET",`/rest/api/3/issue/${n}/transitions`)]),s=r?.fields?.status??null,a=s?{id:`status:${s.id}`,name:s.name,type:MI(s.statusCategory)}:null,i=(o?.transitions??[]).map((c,l)=>({id:c.id,name:c.to?.name??c.name,type:MI(c.to?.statusCategory),position:l}));return{current:a,states:i}}async function HH(e,t,n){await ws(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/transitions`,{transition:{id:String(n)}})}var iy={};Zp(iy,{createComment:()=>YH,createIssue:()=>ay,createProject:()=>sy,findIssueUrl:()=>zH,issueStates:()=>ZH,moveIssue:()=>QH,parseIssueRef:()=>GH,resolveIssue:()=>VH,teams:()=>Da,uploadImage:()=>XH,upsertCard:()=>JH,whoami:()=>oy});var WH=()=>process.env.BOSTRAT_LINEAR_API_URL||"https://api.linear.app/graphql";async function zn(e,t,n={}){let r=await fetch(WH(),{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 qH=/linear\.app\/[^/\s]+\/issue\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,KH=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function GH(e){let t=String(e||"").trim(),n=t.match(qH);if(n)return n[1].toUpperCase();let r=t.match(KH);return r?r[1]:null}function zH(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 VH(e,t){let r=(await zn(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 JH(e,t,{url:n,title:r,subtitle:o}){let s=await zn(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 YH(e,t,n){let r=await zn(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 oy(e){let t=await zn(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 XH(e,{filename:t,contentType:n,buffer:r}){let o=await zn(e,`mutation($contentType: String!, $filename: String!, $size: Int!) {
720
724
  fileUpload(contentType: $contentType, filename: $filename, size: $size) {
721
725
  success
722
726
  uploadFile { uploadUrl assetUrl headers { key value } }
723
727
  }
724
- }`,{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 MH(e,t){let n=await Wn(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 CH(e,t,n){if(!(await Wn(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 _a(e){return((await Wn(e,"query { teams(first: 100) { nodes { id key name } } }")).teams?.nodes??[]).map(n=>({id:n.id,key:n.key,name:n.name}))}var kI=255;async function qg(e,{teamId:t,name:n,description:r}){let o=r||null,s=!!o&&o.length>kI,a=s?`${o.slice(0,kI-1).trimEnd()}\u2026`:o,i=await Wn(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 Wg(e,{teamId:t,title:n,description:r,projectId:o,priority:s}){let a=await Wn(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}}Vi();var _I={linear:{api:Kg,config:ns},jira:{api:Ug,config:Zd}};async function Zg(){let e=[];for(let[t,{api:n,config:r}]of Object.entries(_I)){let o=await r();o&&e.push({name:t,api:n,cfg:o})}return e}async function ss(e){let t=_I[e?.provider];if(!t)return null;let n=await t.config();return n?{name:e.provider,api:t.api,cfg:n}:null}function Qg(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 II=()=>process.env.BOSTRAT_STATE_DIR||AI.join(process.env.HOME||NH.tmpdir(),".bostrat"),Jg=()=>AI.join(II(),"tickets.json"),$I=()=>(process.env.BOSTRAT_PUBLIC_URL||"http://bostrat.globopi").replace(/\/$/,""),ep=e=>`${$I()}/track/${e}`,co=null,Gg=null,zg=Promise.resolve();async function qc(){return co||(Gg??=Uc.readFile(Jg(),"utf8").then(e=>({tickets:JSON.parse(e)?.tickets??{},existed:!0})).catch(()=>({tickets:{},existed:!1})).then(async({tickets:e,existed:t})=>{if(co=e,!t&&He()){let{records:n,source:r}=await st("tickets").catch(()=>({records:[],source:"error"}));if(r==="plane"){for(let o of n){if(o.deletedAt||!o.data?.id)continue;let{id:s,updatedAt:a,...i}=o.data;co[s]=i}Object.keys(co).length&&await Yg().catch(()=>{})}}return co}).finally(()=>Gg=null),Gg)}async function Yg(){let e=JSON.stringify({tickets:co},null,2),t=`${Jg()}.${process.pid}.tmp`;await Uc.mkdir(II(),{recursive:!0}),await Uc.writeFile(t,e),await Uc.rename(t,Jg())}async function lo(e=null){if(zg=zg.then(Yg,Yg),await zg.catch(()=>{}),!e)return;let t=co?.[e];t?bt("tickets",{id:e,updatedAt:Date.now(),...t},{trackId:e}).catch(()=>{}):tn("tickets",e).catch(()=>{})}async function Kn(e){return(await qc())[e]??null}async function RI(){return{...await qc()}}async function OI(){return(await Zg()).length>0}async function Ia(e,t,{source:n="api"}={}){let r=await Zg();if(!r.length)throw new Error("no ticketing integration configured \u2014 add a linear or jira entry to ~/.bostrat/integrations.json");let o=null,s=null,a=null;for(let u of r){let d=u.api.parseIssueRef(t);if(d)try{s=await u.api.resolveIssue(u.cfg,d),o=u;break}catch(p){a=p}}if(!o)throw a||new Error(`"${t}" is not a Linear or Jira issue URL or key (ABC-123)`);let i=(e.boxes||[]).find(u=>u.name===e.leadBox),c={provider:o.name,key:s.key,issueId:s.issueId,url:s.url,title:s.title,state:s.state,source:n,linkedAt:Date.now(),track:{name:e.name,branch:e.workspace?.branch??null,leadAgent:i?.agent??null,cwd:e.cwd??null,...e.workspace?.kind==="multi"?{repos:(e.workspace.repos??[]).map(u=>u?.name).filter(Boolean)}:{}},pr:null};(await qc())[e.id]=c,await lo(e.id),await M({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 Hc(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 Fc(c,`**Bostrat** \u2014 Track **${c.track.name}** linked${l.length?` (${l.join(", ")})`:""}.`),await NI(e.id,c,"linked"),c}async function ey(e){let t=await qc();return t[e]?(delete t[e],await lo(e),!0):!1}var Xg=e=>`$${e>=100?Math.round(e):e.toFixed(2)}`;async function MI(e,t){if(!e.track?.cwd)return null;let n=jr(await K({id:t,cwd:e.track.cwd}));return!n.totalUsd||n.totalUsd<.01?null:n}function PH(e){let t=Object.entries(e.byProvider).sort((r,o)=>o[1].usd-r[1].usd).map(([r,o])=>`${r} ${Xg(o.usd)}`).join(" \xB7 "),n=Object.keys(e.byBox).length;return`${Xg(e.totalUsd)}${t?` (${t})`:""}${n>1?` across ${n} boxes`:""}`}function DH(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(Xg(t.totalUsd)),n.join(" \xB7 ")||"linked"}async function Hc(e,t){let n=await ss(t);if(!n)return;let r=await MI(t,e).catch(()=>null);await n.api.upsertCard(n.cfg,t,{url:ep(e),title:`Bostrat Track: ${t.track.name}`,subtitle:DH(t,r)})}function tp(e){let t=new URL($I());return`${t.protocol}//${e}.${t.host}/`}var BH={linked:"linked",opened:"prOpened",merged:"prMerged"};function jH(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 CI(e,t,{from:n,to:r,mode:o,phase:s=null,actor:a="user"}){t.state=r,await lo(e),await M({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 NI(e,t,n){let r=await ss(t);if(!r)return;let o=r.cfg.ticketFlow?.[BH[n]]??"prompt";if(o==="off")return;let{current:s,states:a}=await r.api.issueStates(r.cfg,t),i=Qg(s,a),c=jH(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 CI(e,t,{from:l,to:c.name,mode:"auto",phase:n,actor:"system"});return}await M({id:e,cwd:t.track?.cwd},{type:"ticket.move.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),offerId:EI(),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 PI(e){let t=await Kn(e);if(!t)throw new Error("no ticket linked to this Track");let n=await ss(t);if(!n)throw new Error("no ticketing integration configured");let{current:r,states:o}=await n.api.issueStates(n.cfg,t),s=Qg(r,o);return s?.name&&t.state!==s.name&&(t.state=s.name,await lo(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 ty(e,t,{mode:n="manual"}={}){if(!t)throw new Error("stateId required");let r=await Kn(e);if(!r)throw new Error("no ticket linked to this Track");let o=await ss(r);if(!o)throw new Error("no ticketing integration configured");let{current:s,states:a}=await o.api.issueStates(o.cfg,r),i=Qg(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 lo(e)),{key:r.key,from:l,to:c.name,moved:!1}):(await o.api.moveIssue(o.cfg,r,c.id),await CI(e,r,{from:l,to:c.name,mode:n}),{key:r.key,from:l,to:c.name,moved:!0})}async function DI(e,t){let n=await Kn(e);if(!n)throw new Error("no ticket linked to this Track");let r=await ss(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 M({id:e,cwd:n.track?.cwd},{type:"ticket.commented",actor:"user",source:"orchestrator",payload:{ts:Date.now(),key:n.key,url:s??n.url,excerpt:o.length>280?`${o.slice(0,279)}\u2026`:o}}).catch(()=>{}),{key:n.key,url:s??n.url}}async function BI(e,t,n){if(!t)throw new Error("offerId required");return eo(`tkt:${e.id}:${t}`,()=>LH(e,t,n))}async function LH(e,t,n){let r=await K({id:e.id,cwd:e.cwd}),o=r.find(a=>a.type==="ticket.move.offered"&&a.payload?.offerId===t);if(!o)throw new Error("unknown offer");if(r.some(a=>a.type==="ticket.move.answered"&&a.payload?.offerId===t))throw new Error("offer already answered");let s=null;return n&&(s=await ty(e.id,o.payload.to?.id,{mode:"offer"})),await M({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 xI=50;async function jI(){let e=await ns();if(!e)throw new Error("no ticketing integration configured");return _a(e)}function FH(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>xI)throw new Error(`too many issues (${n.length}); cap is ${xI} per proposal`);return{epic:r,issues:n,team:t.team?String(t.team).trim():null,linkCurrentTrack:t.linkCurrentTrack===!0}}async function UH(e,t,n,r){let o=r??await _a(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 Kn(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 LI(e,t){let n=await ns();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=FH(t),o=await _a(n),s=await UH(n,r,e,o),a=s?{id:s.id,key:s.key,name:s.name}:null,i=EI();return await M({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 FI(e,t,n,{teamId:r=null}={}){if(!t)throw new Error("proposalId required");let o=await K({id:e.id,cwd:e.cwd}),s=o.find(w=>w.type==="ticket.create.offered"&&w.payload?.proposalId===t);if(!s)throw new Error("unknown proposal");if(o.some(w=>w.type==="ticket.create.answered"&&w.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await M({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 ns();if(!a)throw new Error("no ticketing integration configured");let i=s.payload,c=i.team??null;if(!c&&r){let w=(await _a(a)).find(m=>m.id===r);if(!w)throw new Error("unknown team");c={id:w.id,key:w.key,name:w.name}}if(!c)throw new Error("a team is required to create \u2014 pick one");let l=[],u=[],d=null;if(i.epic){let w=await qg(a,{teamId:c.id,name:i.epic.name,description:i.epic.description});d=w.id,l.push({kind:"epic",title:w.name,url:w.url})}for(let w of i.issues||[])try{let m=await Wg(a,{teamId:c.id,title:w.title,description:w.description,projectId:d,priority:w.priority});l.push({kind:"issue",key:m.key,title:m.title,url:m.url})}catch(m){u.push({title:w.title,message:m?.message||String(m)})}await M({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 M({id:e.id,cwd:e.cwd},{type:"ticket.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",createdCount:l.length,failedCount:u.length}});let p=l.filter(w=>w.kind==="issue"),f=null;return i.linkCurrentTrack&&p.length===1&&!await Kn(e.id)&&(f=await Ia(e,p[0].key,{source:"created"}).catch(()=>null)),{proposalId:t,action:"created",created:l,failed:u,linked:f?f.key:null}}async function Fc(e,t){let n=await ss(e);n&&await n.api.createComment(n.cfg,e,t)}async function HH(e,t,n){let r=await ss(e);if(!r)return null;let o=await pr(t);if(!o)return null;let s=pn(o,n);if(!s)return null;let a=await Uc.readFile(Yt(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 vI=()=>Number(process.env.BOSTRAT_TICKET_COST_SYNC_MS??12e4),Vg=new Map;function qH(e,t){if(vI()<=0)return Hc(e,t);if(Vg.has(e))return;let n=setTimeout(()=>{Vg.delete(e),Kn(e).then(r=>r?Hc(e,r):null).catch(()=>{})},vI());n.unref?.(),Vg.set(e,n)}var SI=new Map;async function TI(e,t,n){let r=SI.get(e)??0;Date.now()-r<600*1e3||(SI.set(e,Date.now()),await M({id:e,cwd:t},{type:"ticket.sync.failed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),message:n?.message||String(n)}}).catch(()=>{}))}async function WH(e,{resolveTrack:t=null}={}){let n=await Kn(e.trackId),r=e.payload||{};if(!n){if(e.type!=="turn.user"||e.actor!=="user")return;let o=null;for(let a of await Zg())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 Ia(s,o,{source:"chat"})}catch(a){await TI(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 lo(e.trackId))}try{switch(e.type){case"handoff.done":n.track.leadAgent=r.toAgent??n.track.leadAgent,await lo(e.trackId),await Hc(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 lo(e.trackId),await Hc(e.trackId,n),r.change==="opened"||r.change==="merged"){let o=r.change==="merged"?await MI(n,e.trackId).catch(()=>null):null;await Fc(n,`**Bostrat** \u2014 PR ${r.change} for **${n.track.name}**${r.url?`: ${r.url}`:r.number?` (#${r.number})`:""}`+(o?`
728
+ }`,{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 ZH(e,t){let n=await zn(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 QH(e,t,n){if(!(await zn(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 Da(e){return((await zn(e,"query { teams(first: 100) { nodes { id key name } } }")).teams?.nodes??[]).map(n=>({id:n.id,key:n.key,name:n.name}))}var PI=255;async function sy(e,{teamId:t,name:n,description:r}){let o=r||null,s=!!o&&o.length>PI,a=s?`${o.slice(0,PI-1).trimEnd()}\u2026`:o,i=await zn(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 ay(e,{teamId:t,title:n,description:r,projectId:o,priority:s}){let a=await zn(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}}ec();var HI={linear:{api:iy,config:ms},jira:{api:ry,config:mp}};async function my(){let e=[];for(let[t,{api:n,config:r}]of Object.entries(HI)){let o=await r();o&&e.push({name:t,api:n,cfg:o})}return e}async function gs(e){let t=HI[e?.provider];if(!t)return null;let n=await t.config();return n?{name:e.provider,api:t.api,cfg:n}:null}function hy(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 WI=()=>process.env.BOSTRAT_STATE_DIR||FI.join(process.env.HOME||eW.tmpdir(),".bostrat"),dy=()=>FI.join(WI(),"tickets.json"),qI=()=>(process.env.BOSTRAT_PUBLIC_URL||"http://bostrat.globopi").replace(/\/$/,""),wp=e=>`${qI()}/track/${e}`,mo=null,cy=null,ly=Promise.resolve();async function zc(){return mo||(cy??=Kc.readFile(dy(),"utf8").then(e=>({tickets:JSON.parse(e)?.tickets??{},existed:!0})).catch(()=>({tickets:{},existed:!1})).then(async({tickets:e,existed:t})=>{if(mo=e,!t&&He()){let{records:n,source:r}=await st("tickets").catch(()=>({records:[],source:"error"}));if(r==="plane"){for(let o of n){if(o.deletedAt||!o.data?.id)continue;let{id:s,updatedAt:a,...i}=o.data;mo[s]=i}Object.keys(mo).length&&await py().catch(()=>{})}}return mo}).finally(()=>cy=null),cy)}async function py(){let e=JSON.stringify({tickets:mo},null,2),t=`${dy()}.${process.pid}.tmp`;await Kc.mkdir(WI(),{recursive:!0}),await Kc.writeFile(t,e),await Kc.rename(t,dy())}async function ho(e=null){if(ly=ly.then(py,py),await ly.catch(()=>{}),!e)return;let t=mo?.[e];t?kt("tickets",{id:e,updatedAt:Date.now(),...t},{trackId:e}).catch(()=>{}):rn("tickets",e).catch(()=>{})}async function Vn(e){return(await zc())[e]??null}async function KI(){return{...await zc()}}async function GI(){return(await my()).length>0}async function Ba(e,t,{source:n="api"}={}){let r=await my();if(!r.length)throw new Error("no ticketing integration configured \u2014 add a linear or jira entry to ~/.bostrat/integrations.json");let o=null,s=null,a=null;for(let u of r){let d=u.api.parseIssueRef(t);if(d)try{s=await u.api.resolveIssue(u.cfg,d),o=u;break}catch(p){a=p}}if(!o)throw a||new Error(`"${t}" is not a Linear or Jira issue URL or key (ABC-123)`);let i=(e.boxes||[]).find(u=>u.name===e.leadBox),c={provider:o.name,key:s.key,issueId:s.issueId,url:s.url,title:s.title,state:s.state,source:n,linkedAt:Date.now(),track:{name:e.name,branch:e.workspace?.branch??null,leadAgent:i?.agent??null,cwd:e.cwd??null,...e.workspace?.kind==="multi"?{repos:(e.workspace.repos??[]).map(u=>u?.name).filter(Boolean)}:{}},pr:null};(await zc())[e.id]=c,await ho(e.id),await M({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 Gc(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 qc(c,`**Bostrat** \u2014 Track **${c.track.name}** linked${l.length?` (${l.join(", ")})`:""}.`),await JI(e.id,c,"linked"),c}async function wy(e){let t=await zc();return t[e]?(delete t[e],await ho(e),!0):!1}var fy=e=>`$${e>=100?Math.round(e):e.toFixed(2)}`;async function zI(e,t){if(!e.track?.cwd)return null;let n=Hr(await K({id:t,cwd:e.track.cwd}));return!n.totalUsd||n.totalUsd<.01?null:n}function tW(e){let t=Object.entries(e.byProvider).sort((r,o)=>o[1].usd-r[1].usd).map(([r,o])=>`${r} ${fy(o.usd)}`).join(" \xB7 "),n=Object.keys(e.byBox).length;return`${fy(e.totalUsd)}${t?` (${t})`:""}${n>1?` across ${n} boxes`:""}`}function nW(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(fy(t.totalUsd)),n.join(" \xB7 ")||"linked"}async function Gc(e,t){let n=await gs(t);if(!n)return;let r=await zI(t,e).catch(()=>null);await n.api.upsertCard(n.cfg,t,{url:wp(e),title:`Bostrat Track: ${t.track.name}`,subtitle:nW(t,r)})}function gp(e){let t=new URL(qI());return`${t.protocol}//${e}.${t.host}/`}var rW={linked:"linked",opened:"prOpened",merged:"prMerged"};function oW(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 VI(e,t,{from:n,to:r,mode:o,phase:s=null,actor:a="user"}){t.state=r,await ho(e),await M({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 JI(e,t,n){let r=await gs(t);if(!r)return;let o=r.cfg.ticketFlow?.[rW[n]]??"prompt";if(o==="off")return;let{current:s,states:a}=await r.api.issueStates(r.cfg,t),i=hy(s,a),c=oW(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 VI(e,t,{from:l,to:c.name,mode:"auto",phase:n,actor:"system"});return}await M({id:e,cwd:t.track?.cwd},{type:"ticket.move.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),offerId:UI(),provider:t.provider,key:t.key,url:t.url,phase:n,from:l,to:{id:c.id,name:c.name,type:c.type},...t.pr?.number?{prNumber:t.pr.number}:{}}}).catch(()=>{})}async function YI(e){let t=await Vn(e);if(!t)throw new Error("no ticket linked to this Track");let n=await gs(t);if(!n)throw new Error("no ticketing integration configured");let{current:r,states:o}=await n.api.issueStates(n.cfg,t),s=hy(r,o);return s?.name&&t.state!==s.name&&(t.state=s.name,await ho(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 gy(e,t,{mode:n="manual"}={}){if(!t)throw new Error("stateId required");let r=await Vn(e);if(!r)throw new Error("no ticket linked to this Track");let o=await gs(r);if(!o)throw new Error("no ticketing integration configured");let{current:s,states:a}=await o.api.issueStates(o.cfg,r),i=hy(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 ho(e)),{key:r.key,from:l,to:c.name,moved:!1}):(await o.api.moveIssue(o.cfg,r,c.id),await VI(e,r,{from:l,to:c.name,mode:n}),{key:r.key,from:l,to:c.name,moved:!0})}async function XI(e,t){let n=await Vn(e);if(!n)throw new Error("no ticket linked to this Track");let r=await gs(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 M({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 ZI(e,t,n){if(!t)throw new Error("offerId required");return so(`tkt:${e.id}:${t}`,()=>sW(e,t,n))}async function sW(e,t,n){let r=await K({id:e.id,cwd:e.cwd}),o=r.find(a=>a.type==="ticket.move.offered"&&a.payload?.offerId===t);if(!o)throw new Error("unknown offer");if(r.some(a=>a.type==="ticket.move.answered"&&a.payload?.offerId===t))throw new Error("offer already answered");let s=null;return n&&(s=await gy(e.id,o.payload.to?.id,{mode:"offer"})),await M({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 DI=50;async function QI(){let e=await ms();if(!e)throw new Error("no ticketing integration configured");return Da(e)}function aW(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>DI)throw new Error(`too many issues (${n.length}); cap is ${DI} per proposal`);return{epic:r,issues:n,team:t.team?String(t.team).trim():null,linkCurrentTrack:t.linkCurrentTrack===!0}}async function iW(e,t,n,r){let o=r??await Da(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 Vn(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 e$(e,t){let n=await ms();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=aW(t),o=await Da(n),s=await iW(n,r,e,o),a=s?{id:s.id,key:s.key,name:s.name}:null,i=UI();return await M({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 t$(e,t,n,{teamId:r=null}={}){if(!t)throw new Error("proposalId required");let o=await K({id:e.id,cwd:e.cwd}),s=o.find(w=>w.type==="ticket.create.offered"&&w.payload?.proposalId===t);if(!s)throw new Error("unknown proposal");if(o.some(w=>w.type==="ticket.create.answered"&&w.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await M({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 ms();if(!a)throw new Error("no ticketing integration configured");let i=s.payload,c=i.team??null;if(!c&&r){let w=(await Da(a)).find(m=>m.id===r);if(!w)throw new Error("unknown team");c={id:w.id,key:w.key,name:w.name}}if(!c)throw new Error("a team is required to create \u2014 pick one");let l=[],u=[],d=null;if(i.epic){let w=await sy(a,{teamId:c.id,name:i.epic.name,description:i.epic.description});d=w.id,l.push({kind:"epic",title:w.name,url:w.url})}for(let w of i.issues||[])try{let m=await ay(a,{teamId:c.id,title:w.title,description:w.description,projectId:d,priority:w.priority});l.push({kind:"issue",key:m.key,title:m.title,url:m.url})}catch(m){u.push({title:w.title,message:m?.message||String(m)})}await M({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 M({id:e.id,cwd:e.cwd},{type:"ticket.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",createdCount:l.length,failedCount:u.length}});let p=l.filter(w=>w.kind==="issue"),f=null;return i.linkCurrentTrack&&p.length===1&&!await Vn(e.id)&&(f=await Ba(e,p[0].key,{source:"created"}).catch(()=>null)),{proposalId:t,action:"created",created:l,failed:u,linked:f?f.key:null}}async function qc(e,t){let n=await gs(e);n&&await n.api.createComment(n.cfg,e,t)}async function cW(e,t,n){let r=await gs(e);if(!r)return null;let o=await wr(t);if(!o)return null;let s=fn(o,n);if(!s)return null;let a=await Kc.readFile(Qt(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 BI=()=>Number(process.env.BOSTRAT_TICKET_COST_SYNC_MS??12e4),uy=new Map;function lW(e,t){if(BI()<=0)return Gc(e,t);if(uy.has(e))return;let n=setTimeout(()=>{uy.delete(e),Vn(e).then(r=>r?Gc(e,r):null).catch(()=>{})},BI());n.unref?.(),uy.set(e,n)}var jI=new Map;async function LI(e,t,n){let r=jI.get(e)??0;Date.now()-r<600*1e3||(jI.set(e,Date.now()),await M({id:e,cwd:t},{type:"ticket.sync.failed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),message:n?.message||String(n)}}).catch(()=>{}))}async function uW(e,{resolveTrack:t=null}={}){let n=await Vn(e.trackId),r=e.payload||{};if(!n){if(e.type!=="turn.user"||e.actor!=="user")return;let o=null;for(let a of await my())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 Ba(s,o,{source:"chat"})}catch(a){await LI(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 ho(e.trackId))}try{switch(e.type){case"handoff.done":n.track.leadAgent=r.toAgent??n.track.leadAgent,await ho(e.trackId),await Gc(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 ho(e.trackId),await Gc(e.trackId,n),r.change==="opened"||r.change==="merged"){let o=r.change==="merged"?await zI(n,e.trackId).catch(()=>null):null;await qc(n,`**Bostrat** \u2014 PR ${r.change} for **${n.track.name}**${r.url?`: ${r.url}`:r.number?` (#${r.number})`:""}`+(o?`
725
729
 
726
- Agent cost for this Track: ${PH(o)}.`:"")),await NI(e.trackId,n,r.change)}break}case"mock.state.changed":{if(r.change==="ready"&&r.mockId){let o=await HH(n,r.mockId,r.version??null);if(!o)break;let s=(r.version??1)>1?` revised (v${r.version})`:"";await Fc(n,`**Bostrat** \u2014 mock **${r.name}**${s}${r.group?` (group \`${r.group}\`)`:""}:
730
+ Agent cost for this Track: ${tW(o)}.`:"")),await JI(e.trackId,n,r.change)}break}case"mock.state.changed":{if(r.change==="ready"&&r.mockId){let o=await cW(n,r.mockId,r.version??null);if(!o)break;let s=(r.version??1)>1?` revised (v${r.version})`:"";await qc(n,`**Bostrat** \u2014 mock **${r.name}**${s}${r.group?` (group \`${r.group}\`)`:""}:
727
731
 
728
- ![${r.name}](${o})`)}else if(r.change==="picked"){let o=(r.siblings??[]).map(s=>`**${s.name}**`).join(", ");await Fc(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 Fc(n,`**Bostrat** \u2014 live preview **${r.name}**: ${tp(r.slug)}
729
- _(runs on the Track's branch; reachable on the operator's private network only)_`);break}case"cost.recorded":await qH(e.trackId,n);break;default:break}}catch(o){let s=t?await t(e.trackId).catch(()=>null):null;await TI(e.trackId,s?.cwd??null,o)}}function UI({resolveTrack:e}){Je.on("event",t=>{WH(t,{resolveTrack:e}).catch(()=>{})})}async function HI(){if(!He())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("tickets");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await qc(),r=0;for(let[o,s]of Object.entries(n))await bt("tickets",{id:o,updatedAt:Date.now(),...s},{trackId:o}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}Do();da();import KH from"ws";var qI=()=>process.env.BOSTRAT_SLACK_API_BASE||"https://slack.com/api";async function np(e,t,n={}){let r=await fetch(`${qI()}/${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 ny=(e,t)=>np("chat.postMessage",e,t),as=(e,t)=>np("chat.update",e,t);async function xt(e,t){await fetch(e,{method:"POST",headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify(t)}).catch(()=>{})}async function GH(e,t,n={}){let r=await fetch(`${qI()}/${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 WI(e,{filename:t,buffer:n,title:r,channelId:o,threadTs:s,initialComment:a}){let{upload_url:i,file_id:c}=await GH("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 np("files.completeUploadExternal",e,{files:[{id:c,title:r}],channel_id:o,thread_ts:s,...a?{initial_comment:a}:{}})}var zH=2200;function KI({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 np("apps.connections.open",u))}catch(u){return n(`connections.open failed: ${u?.message||u}`),c()}o=new KH(l),o.on("message",u=>{let d;try{d=JSON.parse(u)}catch{return}if(d.type==="hello"){a=1e3,n("socket connected");return}if(d.type==="disconnect"){try{o.close()}catch{}return}if(!d.envelope_id)return;let p=m=>{try{o.send(JSON.stringify(m?{envelope_id:d.envelope_id,payload:m}:{envelope_id:d.envelope_id}))}catch{}},f=!1,w=setTimeout(()=>{f=!0,p()},zH);Promise.resolve().then(()=>t(d)).then(m=>{clearTimeout(w),!f&&(f=!0,p(d.accepts_response_payload?m:void 0))},m=>{clearTimeout(w),f||(f=!0,p()),n(`envelope handler failed: ${m?.message||m}`)})}),o.on("close",c),o.on("error",u=>{n(`socket error: ${u?.message||u}`);try{o.close()}catch{}})}function c(){if(r||s)return;let l=a;a=Math.min(a*2,6e4),s=setTimeout(()=>{s=null,i()},l)}return i(),()=>{r=!0,s&&clearTimeout(s);try{o?.close()}catch{}}}var VI=()=>process.env.BOSTRAT_STATE_DIR||op.join(process.env.HOME||JH.tmpdir(),".bostrat"),iy=()=>op.join(VI(),"slack.json"),rp=null,ry=null,oy=Promise.resolve();async function ly(){return rp||(ry??=Wc.readFile(iy(),"utf8").then(e=>JSON.parse(e)?.threads??{}).catch(()=>({})).then(e=>rp=e).finally(()=>ry=null),ry)}async function GI(){let e=JSON.stringify({threads:rp},null,2),t=`${iy()}.${process.pid}.tmp`;await Wc.mkdir(VI(),{recursive:!0}),await Wc.writeFile(t,e),await Wc.rename(t,iy())}async function yn(){oy=oy.then(GI,GI),await oy.catch(()=>{})}async function uy(e){return(await ly())[e]??null}async function YH(e,t){let n=await ly();for(let[r,o]of Object.entries(n))if(o.channel===e&&o.ts===t)return{trackId:r,rec:o};return null}var ve=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");function Kc(e,t){let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1).trimEnd()}\u2026`}function XH(e,t=500){let n=String(e??"").trim().split(/\n\s*\n/)[0]??"";return Kc(n.replace(/\n+/g," "),t)}function JI(e){let t=`*${ve(e.name)}*${e.archivedAt?" \xB7 _archived_":""}`,n=`${ve(e.repoLabel)} \xB7 \`${ve(e.branch||"?")}\` \xB7 lead *${ve(e.lead)}*`,r=e.kickoff?`> ${ve(Kc(e.kickoff,300))}`:"_no kickoff yet \u2014 reply in this thread to steer the lead_";return[{type:"section",text:{type:"mrkdwn",text:`${t}
730
- ${n}`}},{type:"section",text:{type:"mrkdwn",text:r}},{type:"context",elements:[{type:"mrkdwn",text:`<${ep(e.trackId)}|open the Track> \xB7 reachable on the operator's private network only`}]}]}async function cy(e,t){await as(e.botToken,{channel:t.channel,ts:t.ts,text:`Track: ${t.name}`,blocks:JI(t)})}async function po(e,t,n,r=void 0){return ny(e.botToken,{channel:t.channel,thread_ts:t.ts,text:n,...r?{blocks:r}:{},unfurl_links:!1})}var zI=new Set;function uo(e){zI.add(e),e.catch(()=>{}).finally(()=>zI.delete(e))}var Ue=e=>({response_type:"ephemeral",text:e}),ZH="*/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._",QH=["claude","cursor","codex"];function sy(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 ay=(e,t)=>Ue(`No live Track matches \u201C${ve(t)}\u201D. Live: ${e.map(n=>`\`${ve(n.name)}\``).join(" \xB7 ")||"none"}`);async function YI(e,t,{name:n,repo:r,responseUrl:o}){let s=e.deps;try{let a=(await s.listTracks()).filter(d=>!d.archivedAt);if(a.length>=t.maxConcurrent){await xt(o,{...Ue(`At capacity \u2014 ${a.length} live Tracks (limit ${t.maxConcurrent}). Archive or stop something first.`),replace_original:!0});return}if(!t.channel){await xt(o,{...Ue("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?op.basename(c.base):"fresh workspace"),lead:"claude"},u=await ny(t.botToken,{channel:t.channel,text:`Track started: ${l.name}`,blocks:JI(l),unfurl_links:!1});l.ts=u.ts,(await ly())[i.id]=l,await yn(),await xt(o,{...Ue(`\u2713 *${ve(l.name)}* started \u2014 root message posted.`),replace_original:!0})}catch(a){await xt(o,{...Ue(`Start failed: ${a?.message||a}`),replace_original:!0})}}async function eq(e,t,{track:n,responseUrl:r}){let o=e.deps;try{await o.archiveTrack(n.id);let s=await uy(n.id);s&&(s.archivedAt=Date.now(),await yn(),await cy(t,s).catch(()=>{})),await xt(r,{...Ue(`\u2713 *${ve(n.name)}* archived.`),replace_original:!0})}catch(s){await xt(r,{...Ue(`Archive failed: ${s?.message||s}`),replace_original:!0})}}async function tq(e,t,{track:n,agent:r,responseUrl:o}){try{await e.deps.startLeadHandoff(n.id,r),await xt(o,{...Ue(`\u2713 Handing *${ve(n.name)}* to ${ve(r)} \u2014 the root message updates when the baton lands.`),replace_original:!0})}catch(s){await xt(o,{...Ue(`Handoff failed: ${s?.message||s}`),replace_original:!0})}}async function nq(e,t,{track:n,responseUrl:r}){let o=e.deps;try{await o.interruptLead(n.id);let s=(o.listSubtaskJobs?.(n.id)??[]).filter(a=>!a.finishedAt);for(let a of s)try{o.cancelSubtask(a.id)}catch{}await xt(r,{...Ue(`\u2713 Stopped *${ve(n.name)}*${s.length?` (+ ${s.length} subtask${s.length>1?"s":""} canceled)`:""} \u2014 Track parked, resume from the Track page.`),replace_original:!0})}catch(s){await xt(r,{...Ue(`Stop failed: ${s?.message||s}`),replace_original:!0})}}function rq(e,t){let n=[...t.slice(0,99).map(r=>({text:{type:"plain_text",text:Kc(`${r.name} (${r.branch})`,75)},value:r.path})),{text:{type:"plain_text",text:"fresh workspace"},value:"__fresh__"}];return[{type:"section",block_id:JSON.stringify({name:e}),text:{type:"mrkdwn",text:`Repo for *${ve(e)}*:`},accessory:{type:"static_select",action_id:"bostrat-start-repo",placeholder:{type:"plain_text",text:"Choose a repo"},options:n}}]}async function oq(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?op.basename(a.base):"fresh"),c=[...s.boxes||[]].reverse().find(u=>u.role==="lead")?.agent||"?",l=s.prompted?"\u26A0 needs an answer":s.working?"working":"idle";return`\u2022 *${ve(s.name)}* \u2014 ${ve(i)}${a.branch?` \`${ve(a.branch)}\``:""} \xB7 lead ${ve(c)} \xB7 ${l}`}),o=t.length-n.length;return r.join(`
732
+ ![${r.name}](${o})`)}else if(r.change==="picked"){let o=(r.siblings??[]).map(s=>`**${s.name}**`).join(", ");await qc(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 qc(n,`**Bostrat** \u2014 live preview **${r.name}**: ${gp(r.slug)}
733
+ _(runs on the Track's branch; reachable on the operator's private network only)_`);break}case"cost.recorded":await lW(e.trackId,n);break;default:break}}catch(o){let s=t?await t(e.trackId).catch(()=>null):null;await LI(e.trackId,s?.cwd??null,o)}}function n$({resolveTrack:e}){Je.on("event",t=>{uW(t,{resolveTrack:e}).catch(()=>{})})}async function r$(){if(!He())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("tickets");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await zc(),r=0;for(let[o,s]of Object.entries(n))await kt("tickets",{id:o,updatedAt:Date.now(),...s},{trackId:o}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}Go();ka();import dW from"ws";var o$=()=>process.env.BOSTRAT_SLACK_API_BASE||"https://slack.com/api";async function yp(e,t,n={}){let r=await fetch(`${o$()}/${e}`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/json; charset=utf-8"},body:JSON.stringify(n)}),o=await r.json().catch(()=>null);if(!o?.ok)throw new Error(`slack ${e}: ${o?.error||`http ${r.status}`}`);return o}var yy=(e,t)=>yp("chat.postMessage",e,t),ys=(e,t)=>yp("chat.update",e,t);async function St(e,t){await fetch(e,{method:"POST",headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify(t)}).catch(()=>{})}async function pW(e,t,n={}){let r=await fetch(`${o$()}/${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 s$(e,{filename:t,buffer:n,title:r,channelId:o,threadTs:s,initialComment:a}){let{upload_url:i,file_id:c}=await pW("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 yp("files.completeUploadExternal",e,{files:[{id:c,title:r}],channel_id:o,thread_ts:s,...a?{initial_comment:a}:{}})}var fW=2200;function a$({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 yp("apps.connections.open",u))}catch(u){return n(`connections.open failed: ${u?.message||u}`),c()}o=new dW(l),o.on("message",u=>{let d;try{d=JSON.parse(u)}catch{return}if(d.type==="hello"){a=1e3,n("socket connected");return}if(d.type==="disconnect"){try{o.close()}catch{}return}if(!d.envelope_id)return;let p=m=>{try{o.send(JSON.stringify(m?{envelope_id:d.envelope_id,payload:m}:{envelope_id:d.envelope_id}))}catch{}},f=!1,w=setTimeout(()=>{f=!0,p()},fW);Promise.resolve().then(()=>t(d)).then(m=>{clearTimeout(w),!f&&(f=!0,p(d.accepts_response_payload?m:void 0))},m=>{clearTimeout(w),f||(f=!0,p()),n(`envelope handler failed: ${m?.message||m}`)})}),o.on("close",c),o.on("error",u=>{n(`socket error: ${u?.message||u}`);try{o.close()}catch{}})}function c(){if(r||s)return;let l=a;a=Math.min(a*2,6e4),s=setTimeout(()=>{s=null,i()},l)}return i(),()=>{r=!0,s&&clearTimeout(s);try{o?.close()}catch{}}}var l$=()=>process.env.BOSTRAT_STATE_DIR||kp.join(process.env.HOME||hW.tmpdir(),".bostrat"),Sy=()=>kp.join(l$(),"slack.json"),bp=null,by=null,ky=Promise.resolve();async function Ty(){return bp||(by??=Vc.readFile(Sy(),"utf8").then(e=>JSON.parse(e)?.threads??{}).catch(()=>({})).then(e=>bp=e).finally(()=>by=null),by)}async function i$(){let e=JSON.stringify({threads:bp},null,2),t=`${Sy()}.${process.pid}.tmp`;await Vc.mkdir(l$(),{recursive:!0}),await Vc.writeFile(t,e),await Vc.rename(t,Sy())}async function kn(){ky=ky.then(i$,i$),await ky.catch(()=>{})}async function Ey(e){return(await Ty())[e]??null}async function wW(e,t){let n=await Ty();for(let[r,o]of Object.entries(n))if(o.channel===e&&o.ts===t)return{trackId:r,rec:o};return null}var Ae=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");function Jc(e,t){let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1).trimEnd()}\u2026`}function gW(e,t=500){let n=String(e??"").trim().split(/\n\s*\n/)[0]??"";return Jc(n.replace(/\n+/g," "),t)}function u$(e){let t=`*${Ae(e.name)}*${e.archivedAt?" \xB7 _archived_":""}`,n=`${Ae(e.repoLabel)} \xB7 \`${Ae(e.branch||"?")}\` \xB7 lead *${Ae(e.lead)}*`,r=e.kickoff?`> ${Ae(Jc(e.kickoff,300))}`:"_no kickoff yet \u2014 reply in this thread to steer the lead_";return[{type:"section",text:{type:"mrkdwn",text:`${t}
734
+ ${n}`}},{type:"section",text:{type:"mrkdwn",text:r}},{type:"context",elements:[{type:"mrkdwn",text:`<${wp(e.trackId)}|open the Track> \xB7 reachable on the operator's private network only`}]}]}async function Ay(e,t){await ys(e.botToken,{channel:t.channel,ts:t.ts,text:`Track: ${t.name}`,blocks:u$(t)})}async function go(e,t,n,r=void 0){return yy(e.botToken,{channel:t.channel,thread_ts:t.ts,text:n,...r?{blocks:r}:{},unfurl_links:!1})}var c$=new Set;function wo(e){c$.add(e),e.catch(()=>{}).finally(()=>c$.delete(e))}var Ue=e=>({response_type:"ephemeral",text:e}),yW="*/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._",bW=["claude","cursor","codex"];function xy(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 vy=(e,t)=>Ue(`No live Track matches \u201C${Ae(t)}\u201D. Live: ${e.map(n=>`\`${Ae(n.name)}\``).join(" \xB7 ")||"none"}`);async function d$(e,t,{name:n,repo:r,responseUrl:o}){let s=e.deps;try{let a=(await s.listTracks()).filter(d=>!d.archivedAt);if(a.length>=t.maxConcurrent){await St(o,{...Ue(`At capacity \u2014 ${a.length} live Tracks (limit ${t.maxConcurrent}). Archive or stop something first.`),replace_original:!0});return}if(!t.channel){await St(o,{...Ue("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?kp.basename(c.base):"fresh workspace"),lead:"claude"},u=await yy(t.botToken,{channel:t.channel,text:`Track started: ${l.name}`,blocks:u$(l),unfurl_links:!1});l.ts=u.ts,(await Ty())[i.id]=l,await kn(),await St(o,{...Ue(`\u2713 *${Ae(l.name)}* started \u2014 root message posted.`),replace_original:!0})}catch(a){await St(o,{...Ue(`Start failed: ${a?.message||a}`),replace_original:!0})}}async function kW(e,t,{track:n,responseUrl:r}){let o=e.deps;try{await o.archiveTrack(n.id);let s=await Ey(n.id);s&&(s.archivedAt=Date.now(),await kn(),await Ay(t,s).catch(()=>{})),await St(r,{...Ue(`\u2713 *${Ae(n.name)}* archived.`),replace_original:!0})}catch(s){await St(r,{...Ue(`Archive failed: ${s?.message||s}`),replace_original:!0})}}async function xW(e,t,{track:n,agent:r,responseUrl:o}){try{await e.deps.startLeadHandoff(n.id,r),await St(o,{...Ue(`\u2713 Handing *${Ae(n.name)}* to ${Ae(r)} \u2014 the root message updates when the baton lands.`),replace_original:!0})}catch(s){await St(o,{...Ue(`Handoff failed: ${s?.message||s}`),replace_original:!0})}}async function vW(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 St(r,{...Ue(`\u2713 Stopped *${Ae(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 St(r,{...Ue(`Stop failed: ${s?.message||s}`),replace_original:!0})}}function SW(e,t){let n=[...t.slice(0,99).map(r=>({text:{type:"plain_text",text:Jc(`${r.name} (${r.branch})`,75)},value:r.path})),{text:{type:"plain_text",text:"fresh workspace"},value:"__fresh__"}];return[{type:"section",block_id:JSON.stringify({name:e}),text:{type:"mrkdwn",text:`Repo for *${Ae(e)}*:`},accessory:{type:"static_select",action_id:"bostrat-start-repo",placeholder:{type:"plain_text",text:"Choose a repo"},options:n}}]}async function AW(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?kp.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 *${Ae(s.name)}* \u2014 ${Ae(i)}${a.branch?` \`${Ae(a.branch)}\``:""} \xB7 lead ${Ae(c)} \xB7 ${l}`}),o=t.length-n.length;return r.join(`
731
735
  `)+(o?`
732
- _${o} archived_`:"")}async function sq(e,t){let n=await rs();if(!n)return Ue("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 Ue("Usage: `/bostrat start <name> [repo]`");let i=await r.listRepos(),c=a[a.length-1]?.toLowerCase(),l=a.length>1?i.find(d=>d.name.toLowerCase()===c):null,u=(l?a.slice(0,-1):a).join(" ");return l?(uo(YI(e,n,{name:u,repo:l.path,responseUrl:t.response_url})),Ue(`Starting *${ve(u)}* on ${ve(l.name)}\u2026`)):{response_type:"ephemeral",text:`Pick a repo for \u201C${u}\u201D`,blocks:rq(u,i)}}case"archive":{if(!a.length)return Ue("Usage: `/bostrat archive <track>`");let{match:i,live:c}=sy(await r.listTracks(),a.join(" "));return i?(uo(eq(e,n,{track:i,responseUrl:t.response_url})),Ue(`Archiving *${ve(i.name)}*\u2026`)):ay(c,a.join(" "))}case"handoff":{let i=r.knownAgents??QH,c=a.at(-1)?.toLowerCase();if(a.length<2||!i.includes(c))return Ue(`Usage: \`/bostrat handoff <track> <${i.join("|")}>\``);let l=a.slice(0,-1).join(" "),{match:u,live:d}=sy(await r.listTracks(),l);return u?(uo(tq(e,n,{track:u,agent:c,responseUrl:t.response_url})),Ue(`Handing *${ve(u.name)}* to ${ve(c)}\u2026`)):ay(d,l)}case"stop":{if(!a.length)return Ue("Usage: `/bostrat stop <track>`");let{match:i,live:c}=sy(await r.listTracks(),a.join(" "));return i?(uo(nq(e,n,{track:i,responseUrl:t.response_url})),Ue(`Stopping *${ve(i.name)}*\u2026`)):ay(c,a.join(" "))}case"list":return Ue(await oq(r));default:return Ue(ZH)}}async function aq(e,t,n,r){let{trackId:o,promptId:s,label:a}=r,i=await uy(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 yn(),await as(t.botToken,{channel:i.channel,ts:c,text:`\u2713 ${a}`,blocks:[{type:"section",text:{type:"mrkdwn",text:`~${ve(l||"question")}~
733
- \u2713 *${ve(a)}*`}}]}).catch(()=>{})}}catch(c){await xt(n.response_url,Ue(`Couldn't answer: ${c?.message||c}`))}}async function iq(e,t,n,r){let{trackId:o,offerId:s,action:a}=r,i=e.deps;try{let c=await i.resolveTrack(o);if(!c)throw new Error("track not found");let l=await i.readEvents(c),u=l.find(p=>p.type==="pr.offered"&&p.payload?.offerId===s);if(!u)throw new Error("unknown offer");if(l.some(p=>p.type==="pr.offer.answered"&&p.payload?.offerId===s))throw new Error("offer already answered");let d=Array.isArray(r.actions)?Gr.filter(p=>r.actions.includes(p)):a==="pr"?["commit","push","pr"]:a==="push"?["commit","push"]:null;if(d?.includes("pr")&&i.divertShip&&await i.divertShip(c,u,{actions:d}))return;d&&await i.sayToLead(c.id,Js(d,{branch:u.payload.branch,base:u.payload.base}),{kind:d.includes("pr")?"pr-go":"push-go"}),await i.appendEvent({id:c.id,cwd:c.cwd},{type:"pr.offer.answered",actor:"user",source:"orchestrator",boxId:u.boxId,payload:{ts:Date.now(),offerId:s,action:d?a:"dismiss",actions:d}})}catch(c){await xt(n.response_url,Ue(`Couldn't act on the offer: ${c?.message||c}`))}}async function cq(e,t,n,r){let{trackId:o,offerId:s,choice:a}=r;try{let i=await e.deps.resolveTrack(o);if(!i)throw new Error("track not found");await e.deps.answerPrExists(i,{offerId:s,choice:a})}catch(i){await xt(n.response_url,Ue(`Couldn't act on the offer: ${i?.message||i}`))}}async function lq(e,t){let n=t.actions?.[0];if(!n?.action_id)return;let r=await rs();if(!r)return;if(n.action_id==="bostrat-start-repo"){let s;try{({name:s}=JSON.parse(n.block_id))}catch{return}let a=n.selected_option?.value;await xt(t.response_url,{...Ue(`Starting *${ve(s)}*\u2026`),replace_original:!0}),uo(YI(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"?uo(aq(e,r,t,o)):n.action_id==="bostrat-ship"?uo(iq(e,r,t,o)):n.action_id==="bostrat-pr-exists"&&uo(cq(e,r,t,o))}async function uq(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 YH(t.channel,t.thread_ts);if(!n)return;let r=await rs();if(r)try{await e.deps.sayToLead(n.trackId,t.text.trim())}catch(o){await po(r,n.rec,`Couldn't deliver that to the lead: ${o?.message||o}`).catch(()=>{})}}function dq(e){return async t=>{if(t.type==="slash_commands")return sq(e,t.payload);if(t.type==="interactive"){await lq(e,t.payload);return}if(t.type==="events_api"){await uq(e,t.payload?.event);return}}}var pq=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 fq(e,t){let n=[{type:"section",text:{type:"mrkdwn",text:`\u2753 ${ve(t.question||"The lead needs an answer")}`}}],r=(t.options||[]).slice(0,12);return r.length?n.push({type:"actions",elements:r.map(o=>({type:"button",action_id:"bostrat-prompt",text:{type:"plain_text",text:Kc(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 mq(e,t,n){let r=n.payload||{};if(!r.promptId||t.prompt?.promptId===r.promptId)return;t.prompt&&await as(e.botToken,{channel:t.channel,ts:t.prompt.ts,text:"superseded",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${ve(t.prompt.question||"question")}~ _superseded_`}}]}).catch(()=>{});let o=await po(e,t,r.question||"The lead needs an answer",fq(n.trackId,r));t.prompt={promptId:r.promptId,ts:o.ts,question:r.question||null},await yn()}async function hq(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 yn(),await as(e.botToken,{channel:t.channel,ts:o,text:"answered",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${ve(s||"question")}~
734
- \u2713 _answered_`}}]})}async function wq(e,t,n){let r=n.payload||{};if(!r.offerId||t.offers?.[r.offerId])return;let o=(i,c,l,u)=>({type:"button",action_id:"bostrat-ship",text:{type:"plain_text",text:c},value:JSON.stringify({trackId:n.trackId,offerId:r.offerId,action:i,...u?{actions:u}:{}}),...l?{style:l}:{}}),s;if(!Array.isArray(r.available))s=r.toPr?[o("push",`Commit & push${r.toPr.number?` to #${r.toPr.number}`:""}`,"primary"),o("dismiss","Not now")]:[o("pr","Open PR","primary"),o("push","Just push"),o("dismiss","Not now")];else{let i=r.available,c=Array.isArray(r.defaults)&&r.defaults.length?r.defaults:i,l={commit:"Commit",rebase:"rebase",push:"push",pr:r.prState==="open"?"open new PR":"open PR"},u=c.map(d=>l[d]).filter(Boolean).join(" & ");s=[o(c.includes("pr")?"pr":"push",u||"Ship","primary",c)],i.includes("pr")&&!c.includes("pr")&&s.push(o("pr","Open new PR",void 0,["pr"])),s.push(o("dismiss","Not now"))}let a=await po(e,t,r.excerpt||"Ship it?",[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${ve(Kc(r.excerpt||"The lead offered to ship.",300))}`}},{type:"actions",elements:s}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await yn()}async function gq(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await yn();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 as(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function yq(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 po(e,t,`PR ${o} already open \u2014 push or new PR?`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${o}${r.branch?` (${ve(r.branch)})`:""} is already open. Push the update to it, or open a new PR?`}},{type:"actions",elements:[s("push",`Push to ${o}`,"primary"),s("new","Open a new PR"),s("dismiss","Not now")]}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await yn()}async function bq(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await yn();let s=r.choice==="dismiss"?"dismissed":r.choice==="new"?"\u2713 opening a new PR":"\u2713 pushing to the open PR";await as(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function kq(e,t,n,r){let o=n.payload||{};if(o.change==="ready"&&o.mockId){let s=await(r.readMockPng??xq)(o.mockId,o.version??null);if(!s)return;let a=(o.version??1)>1?` (v${o.version})`:"";await WI(e.botToken,{filename:s.filename,buffer:s.buffer,title:`${o.name}${a}`,channelId:t.channel,threadTs:t.ts,initialComment:`\u{1F3A8} mock *${ve(o.name)}*${a}${o.group?` (group \`${ve(o.group)}\`)`:""}`})}else if(o.change==="picked"){let s=(o.siblings??[]).map(a=>`*${ve(a.name)}*`).join(", ");await po(e,t,`Design decision: ${o.name} picked`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F3A8} design decision: *${ve(o.name)}* picked${s?` over ${s}`:""}`}}])}}async function xq(e,t){let n=await pr(e);if(!n)return null;let r=pn(n,t);if(!r)return null;let o=await Wc.readFile(Yt(n,r.v).png).catch(()=>null);return o?{filename:`${n.name.replace(/[^\w.-]+/g,"-")}.v${r.v}.png`,buffer:o}:null}async function vq(e,t){if(!pq.has(t.type))return;let n=await uy(t.trackId);if(!n)return;let r=await rs();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 yn(),await cy(r,n);return;case"turn.agent":{if(!o.text)return;let s=XH(o.text);if(!s)return;await po(r,n,s,[{type:"section",text:{type:"mrkdwn",text:ve(s)}},{type:"context",elements:[{type:"mrkdwn",text:`<${ep(t.trackId)}|full turn \u2192>`}]}]);return}case"prompt.raised":return mq(r,n,t);case"prompt.answered":return hq(r,n,t);case"pr.offered":return wq(r,n,t);case"pr.offer.answered":return gq(r,n,t);case"pr.exists.offered":return yq(r,n,t);case"pr.exists.answered":return bq(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 po(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 yn(),await cy(r,n);return;case"view.state.changed":{if(o.change!=="created"||o.restarted||!o.slug)return;await po(r,n,`Live preview ${o.name}: ${tp(o.slug)}`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F50D} live preview *${ve(o.name)}*: ${tp(o.slug)}
735
- _runs on the Track's branch; reachable on the operator's private network only_`}}]);return}case"mock.state.changed":return kq(r,n,t,e.deps)}}function XI(e){let t={deps:e};Je.on("event",s=>{vq(t,s).catch(()=>{})});let n=null,r=null,o=async()=>{n||!await rs()||(r&&clearInterval(r),r=null,n=KI({getToken:async()=>(await rs())?.appToken,onEnvelope:dq(t),log:s=>console.log(`[slack] ${s}`)}))};return r=setInterval(()=>o().catch(()=>{}),3e4),r.unref?.(),o().catch(()=>{}),()=>{r&&clearInterval(r),n?.()}}an();de();Tn();yh();Qn();import Sq from"node:fs/promises";function Tq(e){let t=new Map;for(let n of String(e||"").split(`
736
- `)){let r=n.trim();if(!r||r[0]!=="{")continue;let o;try{o=JSON.parse(r)}catch{continue}let s=o?.message?.usage;if(!s)continue;let a={input:s.input_tokens||0,output:s.output_tokens||0,cacheWrite:s.cache_creation_input_tokens||0,cacheRead:s.cache_read_input_tokens||0};if(a.input+a.output+a.cacheWrite+a.cacheRead===0)continue;let i=o.message?.id||o.uuid||null;if(!i)continue;let c=s.cache_creation,l=c&&typeof c=="object"?{m5:c.ephemeral_5m_input_tokens||0,h1:c.ephemeral_1h_input_tokens||0}:null,u=typeof s.speed=="string"&&s.speed!=="standard"?s.speed:null;t.set(i,{messageId:i,tokens:a,cacheWriteTtl:l,speed:u,model:o.message?.model||o.model||null})}return[...t.values()]}function Aq(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 Eq=new Set(["Write","Edit","NotebookEdit"]),_q=220,Iq=160;function $q(e,t){let n=e?.tool_name??null,r={tool:n},o=e?.tool_input;if(!o||typeof o!="object")return r;if(Eq.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,_q)}else n==="Bash"&&typeof o.command=="string"&&o.command.trim()&&(r.head=vo(o.command.trim().replace(/\s+/g," ")).slice(0,Iq));return r}function Rq(e,t){return e?.transcript_path?e.transcript_path:t?.cwd&&t?.sessionId?sn(t.cwd,t.sessionId):t?.cwd?yf(t.cwd):null}async function ZI(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 M(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=td(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:$q(e,o)});break;case"Stop":await Oq(r,o,e,i);break;default:break}return a}async function Oq(e,t,n,r){let o=[],s=Rq(n,t);if(s)try{o=Tq(await Sq.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=Aq(await K(e)),c=o.filter(u=>!i.has(u.messageId));if(c.length){let u=new Map;for(let d of c){let p=`${d.model||"unknown"}\0${d.speed||""}`,f=u.get(p)||{tokens:{input:0,output:0,cacheWrite:0,cacheRead:0},cacheWriteTtl:null,messageIds:[]};for(let w of Object.keys(f.tokens))f.tokens[w]+=d.tokens[w];d.cacheWriteTtl&&(f.cacheWriteTtl??={m5:0,h1:0},f.cacheWriteTtl.m5+=d.cacheWriteTtl.m5,f.cacheWriteTtl.h1+=d.cacheWriteTtl.h1),f.messageIds.push(d.messageId),f.speed=d.speed||null,u.set(p,f)}for(let[d,p]of u){let f=d.split("\0")[0];await r({type:"cost.recorded",actor:"system",source:"transcript",payload:{model:f,usd:In(f,p.tokens,void 0,p.speed?{speed:p.speed}:void 0),tokens:p.tokens,...p.speed?{speed:p.speed}:{},cacheWriteTtl:p.cacheWriteTtl,messageId:p.messageIds[p.messageIds.length-1],messageIds:p.messageIds,apiCalls:p.messageIds.length}})}}let l=a.tokens.input+a.tokens.cacheWrite+a.tokens.cacheRead;await r({type:"context.usage",actor:"system",source:"transcript",payload:{model:a.model,occupancy:l,tokens:a.tokens}})}fs();lf();Qu();de();de();Lr();de();Lr();Qn();function Gc(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 QI=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),e$=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},sp=e=>Math.round(e*1e4)/1e4;async function dy(e){let t=[],n={},r={},o=0,s=0,a=0,i=0,c=0,l=new Set,u=QI(),d=0,p=[];for(let f of e||[]){let w=await K(f),m=jr(w,{boxLabels:Gc(f)});if(m.turns===0){f.archivedAt?d++:p.push(f.name||f.id);continue}o+=m.totalUsd,s+=m.turns,a+=m.repricedTurns||0,i+=m.asRecordedUsd||0,c+=m.unpricedTurns||0;for(let g of m.unpricedModels||[])l.add(g);e$(u,m.totalTokens);for(let[g,y]of Object.entries(m.byModel))n[g]||={usd:0,events:0,tokens:QI()},n[g].usd=sp(n[g].usd+y.usd),n[g].events+=y.events,e$(n[g].tokens,y.tokens);for(let[g,y]of Object.entries(m.byProvider))r[g]||={usd:0,events:0},r[g].usd=sp(r[g].usd+y.usd),r[g].events+=y.events;t.push({id:f.id,name:f.name,usd:m.totalUsd,rollup:m})}return t.sort((f,w)=>w.usd-f.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",pricing:Bs(),fleet:{totalUsd:sp(o),asRecordedUsd:sp(i),turns:s,repricedTurns:a,unpricedTurns:c,unpricedModels:[...l],totalTokens:u,byModel:n,byProvider:r,tracksWithCost:t.length,tracksSilent:d+p.length,tracksSilentArchived:d,tracksSilentLive:p},tracks:t}}var fo=e=>`$${e.toFixed(4)}`,$a=(e,t)=>String(e).padEnd(t);function t$(e){let{fleet:t,tracks:n}=e,r=[];r.push(`BOSTRAT COST READ-OUT \xB7 ${e.generatedAt}`),e.pricingBasis&&r.push(`basis: ${e.pricingBasis}`);let o=t.tracksSilentLive||[];if(r.push(`fleet total ${fo(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 ${fo(t.asRecordedUsd)} \xB7 current-rates total ${fo(t.totalUsd)} (${t.totalUsd>=t.asRecordedUsd?"+":""}${fo(t.totalUsd-t.asRecordedUsd)})`),t.unpricedTurns&&r.push(`\u26A0 ${t.unpricedTurns} turn(s) UNPRICED \u2014 total under-reports. Add PER_MTOK rate(s) for: ${(t.unpricedModels||[]).join(", ")}`),e.pricing){let a=e.pricing;r.push(`rates verified against vendor pages: ${a.tableVerifiedAt??"never"}`+(a.upcomingChanges?.length?` \xB7 scheduled: ${a.upcomingChanges.map(i=>`${i.model} ${i.from}`).join(", ")}`:""));for(let i of a.problems||[])r.push(`\u26A0 RATE TABLE: ${i}`)}r.push(""),r.push("BY MODEL");let s=Object.entries(t.byModel).sort((a,i)=>i[1].usd-a[1].usd);s.length||r.push(" (no cost events yet \u2014 hooks emit on each turn of a newly started box)");for(let[a,i]of s){let c=i.tokens;r.push(` ${$a(a,26)} ${$a(fo(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(` ${$a(a.name||a.id,30)} ${fo(a.usd)}`);let i=Object.values(a.rollup.byBox).sort((c,l)=>l.usd-c.usd);for(let c of i)if(r.push(` ${$a(c.label,40)} ${$a(fo(c.usd),10)} ${c.models.join(",")||"?"}`),c.epochs)for(let[l,u]of Object.entries(c.epochs).sort((d,p)=>Number(d[0])-Number(p[0])))r.push(` \u21B3 tenure ${l} (${u.provider||"?"})${" ".repeat(Math.max(1,24-String(u.provider||"?").length))}${$a(fo(u.usd),10)} ${u.models.join(",")||"?"}`)}return r.join(`
737
- `)}de();Hm();import jq from"node:fs/promises";import Lq from"node:path";Zl();ru();Lr();var ap=e=>e.payload?.ts??e.ts,Mq=12e4,Zt=e=>Math.round(e*1e4)/1e4,Cq=()=>({usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{},byTrack:new Map});function Nq(e,{since:t}){let{track:n,events:r,brief:o}=e,s=b=>ap(b)>=t,a=Zn([Ai(n?.name),Ai(n?.workspace?.branch),o].filter(Boolean).join(" ")),i=new Map;for(let b of r)if(b.type==="subtask.delegated"&&b.boxId&&b.payload?.task){let O=Zn(b.payload.task);O&&i.set(b.boxId,O)}let c=new Map,l=b=>{let O=b||"unattributed";return c.has(O)||c.set(O,{segments:[u(null)],lastTs:null,provider:null}),c.get(O)},u=(b,{shape:O="initial",continuation:$=!1,text:C=null,ts:L=null}={})=>({textCat:b,shape:O,continuation:$,text:C,ts:L,tools:{},usd:0,tokens:{input:0,output:0,cacheRead:0,cacheWrite:0},models:{},provider:null,activeMs:0,turns:0,toolCalls:0}),d=[...r].sort((b,O)=>ap(b)-ap(O)),p=0,f=0,w=0,m={turns:0};for(let b of d){let O=l(b.boxId),$=O.segments[O.segments.length-1],C=ap(b);switch(O.lastTs!=null&&C>O.lastTs&&s(b)&&($.activeMs+=Math.min(C-O.lastTs,Mq)),O.lastTs=C,b.provider&&(O.provider=b.provider),b.type){case"turn.user":{let L=b.payload?.text;if(b.source==="hook"||!String(L||"").trim()||b.payload?.note||Ii(L))break;let q=Zn(L),I=!!b.payload?.kind,_=I||x0(L),F=u(q,{shape:I?"injected":_?"follow-up":"novel-ask",continuation:!q&&_,text:r$(L),ts:C});O.segments.push(F),s(b)&&(F.turns+=1);break}case"peer.message":{let L=b.payload?.text;if(!String(L||"").trim())break;let q=Zn(L),I=u(q,{shape:"peer",continuation:!q,text:r$(L),ts:C});O.segments.push(I),s(b)&&(I.turns+=1);break}case"tool.called":{if(b.source==="transcript")break;let L=b.payload?.tool;L&&($.tools[L]=($.tools[L]||0)+1),s(b)&&($.toolCalls+=1);break}case"cost.recorded":{if(!s(b))break;let{usd:L,tokens:q,model:I,unpriced:_}=Kt(b);_&&(m.turns+=1),$.usd+=L,q&&($.tokens.input+=q.input,$.tokens.output+=q.output,$.tokens.cacheRead+=q.cacheRead,$.tokens.cacheWrite+=q.cacheWrite),$.models[I]=($.models[I]||0)+L,b.provider&&($.provider=b.provider);break}case"handoff.done":s(b)&&(p+=1);break;case"subtask.merged":s(b)&&(f+=1);break;case"error":s(b)&&b.payload?.kind==="subtask-failed"&&(w+=1);break;default:break}}let g=new Map,y={usd:0,turns:0,byShape:{},samples:[]},x=!1;for(let[b,O]of c){let $=null;for(let C of O.segments){let L=null,q=null;if(C.textCat)L=C.textCat.category,q="text";else if(i.get(b))L=i.get(b).category,q="boxTask";else if(C.continuation&&$)L=$,q="inherited";else{let A=k0(C.tools);A?(L=A.category,q="toolMix"):a&&(L=a.category,q="hint")}if(L&&($=L),!(C.usd>0||C.activeMs>0||C.turns>0||C.toolCalls>0))continue;let _=L??"uncategorized";g.has(_)||g.set(_,{usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{}});let F=g.get(_);F.usd+=C.usd,F.activeMs+=C.activeMs,F.turns+=C.turns,F.toolCalls+=C.toolCalls,q&&(F.provenance[q]=(F.provenance[q]||0)+C.usd);for(let[A,E]of Object.entries(C.models))F.models[A]=(F.models[A]||0)+E;let V=C.provider||O.provider;V&&(F.providers[V]=(F.providers[V]||0)+C.usd),V==="cursor"&&C.usd===0&&(x=!0),L||(y.usd+=C.usd,y.turns+=C.turns,y.byShape[C.shape]=(y.byShape[C.shape]||0)+C.usd,C.usd>0&&C.text&&y.samples.push({trackId:n?.id,track:n?.name||n?.id,shape:C.shape,usd:Zt(C.usd),ts:C.ts,text:C.text}))}}return{perCategory:g,uncategorized:y,handoffs:p,merged:f,failed:w,sawCursorActivity:x,unpricedTurns:m.turns}}function py(e,{windowMs:t=null,now:n=Date.now()}={}){let r=t==null?0:n-t,o=new Map,s=[],a=0,i=!1,c=0,l={usd:0,turns:0,byShape:{},samples:[]};for(let y of e||[]){let{track:x,events:b}=y;if(!b?.length){a+=1;continue}let{perCategory:O,uncategorized:$,handoffs:C,merged:L,failed:q,sawCursorActivity:I,unpricedTurns:_}=Nq(y,{since:r});I&&(i=!0),c+=_,l.usd+=$.usd,l.turns+=$.turns;for(let[V,A]of Object.entries($.byShape))l.byShape[V]=(l.byShape[V]||0)+A;l.samples.push(...$.samples);let F={trackId:x?.id,name:x?.name||x?.id,archived:!!x?.archivedAt,usd:0,activeMs:0,turns:0,categories:{},models:{},providers:{},handoffs:C,subtasksMerged:L,subtasksFailed:q};for(let[V,A]of O){F.usd+=A.usd,F.activeMs+=A.activeMs,F.turns+=A.turns,F.categories[V]={usd:Zt(A.usd),activeMs:A.activeMs};for(let[H,z]of Object.entries(A.models))F.models[H]=Zt((F.models[H]||0)+z);for(let[H,z]of Object.entries(A.providers))F.providers[H]=Zt((F.providers[H]||0)+z);o.has(V)||o.set(V,Cq());let E=o.get(V);E.usd+=A.usd,E.activeMs+=A.activeMs,E.turns+=A.turns,E.toolCalls+=A.toolCalls;for(let[H,z]of Object.entries(A.models))E.models[H]=(E.models[H]||0)+z;for(let[H,z]of Object.entries(A.providers))E.providers[H]=(E.providers[H]||0)+z;for(let[H,z]of Object.entries(A.provenance))E.provenance[H]=(E.provenance[H]||0)+z;let N=E.byTrack.get(x?.id)||{usd:0,activeMs:0};N.usd+=A.usd,N.activeMs+=A.activeMs,E.byTrack.set(x?.id,N)}(F.usd>0||F.activeMs>0||F.turns>0)&&(F.usd=Zt(F.usd),F.dominantCategory=Bq(F.categories),s.push(F))}let u=[...o.values()].reduce((y,x)=>y+x.usd,0),d=[...o.values()].reduce((y,x)=>y+x.activeMs,0),p=u>0?"usd":"time",f=p==="usd"?u:d,w=new Map((e||[]).map(y=>[y.track?.id,y.track?.name||y.track?.id])),m=[...o.entries()].map(([y,x])=>({category:y,sharePct:f>0?Math.round((p==="usd"?x.usd:x.activeMs)/f*100):0,shareBasis:p,usd:Zt(x.usd),activeMs:x.activeMs,turns:x.turns,toolCalls:x.toolCalls,models:zc(x.models),providers:zc(x.providers),provenance:zc(x.provenance),topWorkstreams:[...x.byTrack.entries()].sort((b,O)=>O[1].usd-b[1].usd||O[1].activeMs-b[1].activeMs).slice(0,2).map(([b,O])=>({trackId:b,name:w.get(b),usd:Zt(O.usd),activeMs:O.activeMs}))})).sort((y,x)=>x.usd-y.usd||x.activeMs-y.activeMs);s.sort((y,x)=>x.usd-y.usd||x.activeMs-y.activeMs);let g={};for(let y of o.values())for(let[x,b]of Object.entries(y.provenance))g[x]=(g[x]||0)+b;return{since:r,capturedAt:n,totalUsd:Zt(u),activeMs:d,turns:[...o.values()].reduce((y,x)=>y+x.turns,0),bullets:m,workstreams:s,provenance:zc(g),gaps:{tracksWithoutEvents:a,cursorCostUnknown:i,unpricedTurns:c,uncategorized:{usd:Zt(l.usd),turns:l.turns,sharePct:u>0?Math.round(l.usd/u*100):0,byShape:zc(l.byShape),top:l.samples.sort((y,x)=>x.usd-y.usd).slice(0,Pq)}}}}var Pq=25,n$=160,r$=e=>{let t=String(e||"").replace(/\s+/g," ").trim();return t.length>n$?`${t.slice(0,n$).trimEnd()}\u2026`:t},Dq=10;function o$(e,{thresholdPct:t=Dq}={}){let n=e?.gaps?.uncategorized||{usd:0,turns:0},r=e?.totalUsd||0,o=n.usd||0,s=r>0?o/r*100:0,a=s<=t,i=a?[]:[`${s.toFixed(1)}% of the last 7d ($${o.toFixed(2)} of $${r.toFixed(2)}) is uncategorized (threshold ${t}%) \u2014 run \`npm run cost -- --uncategorized\` and add classifier table lines for the top asks`];return{ok:a,sharePct:Math.round(s*10)/10,thresholdPct:t,usd:Zt(o),totalUsd:Zt(r),turns:n.turns||0,inheritedPct:r>0?Math.round((e?.provenance?.inherited||0)/r*100):0,problems:i}}var Bq=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},zc=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Zt(n)]));var cs={"24h":24*36e5,"7d":168*36e5,"30d":720*36e5,all:null};function Fq(e){let t=String(e||"7d");return t in cs?{key:t,ms:cs[t]}:{key:"7d",ms:cs["7d"]}}function Uq(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=Eu(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 Hq(e){if(!e?.cwd)return null;try{let n=(await jq.readFile(Lq.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 fy(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}:Fq(t),d=[];for(let w of e||[]){let m=await K(w),g=Uq(w,m);i&&c<o&&(g=g.filter(y=>(y.ts??0)<=c)),d.push({track:w,events:g,brief:await Hq(w)})}let p=py(d,{windowMs:u,now:c}),f=l==="7d"&&c===o?p:py(d,{windowMs:cs["7d"],now:o});return{window:l,...p,categorization:o$(f)}}var Vc=e=>`$${Number(e||0).toFixed(2)}`,s$=e=>{let t=Math.round((e||0)/6e4);return t>=60?`${Math.floor(t/60)}h${String(t%60).padStart(2,"0")}`:`${t}m`},is=(e,t)=>String(e).padEnd(t);function a$(e){let t=[];t.push(`USAGE ROUNDUP \xB7 ${e.window} \xB7 ${Vc(e.totalUsd)} \xB7 ${s$(e.activeMs)} active \xB7 ${e.turns} turn(s) \xB7 as of ${new Date(e.capturedAt).toISOString()}`);let n=e.provenance||{};e.totalUsd>0&&Object.keys(n).length&&t.push("labeled by: "+Object.entries(n).sort((a,i)=>i[1]-a[1]).map(([a,i])=>`${a} ${Math.round(i/e.totalUsd*100)}%`).join(" \xB7 ")),t.push(""),t.push("WHERE IT WENT");for(let a of e.bullets||[])t.push(` ${is(`${a.shareBasis==="time"?"~":""}${a.sharePct}%`,5)} ${is(a.category,15)} ${is(Vc(a.usd),10)} ${is(s$(a.activeMs),6)} ${a.turns} turn(s)`+(a.topWorkstreams?.length?` \xB7 ${a.topWorkstreams.map(i=>i.name).join(", ")}`:""));let r=e.gaps||{};r.tracksWithoutEvents&&t.push(`${r.tracksWithoutEvents} track(s) have no attributed events yet`),r.cursorCostUnknown&&t.push("cursor time counted, cost unavailable"),r.unpricedTurns&&t.push(`WARNING: ${r.unpricedTurns} turn(s) unpriced \u2014 total under-reports`);let o=e.categorization;if(o){t.push(""),t.push((o.ok?"categorization ok: ":"CATEGORIZATION ALARM: ")+`${o.sharePct}% of the last 7d uncategorized (threshold ${o.thresholdPct}%) \xB7 ${o.inheritedPct}% inferred from the previous ask`);for(let a of o.problems||[])t.push(`WARNING: ${a}`)}let s=r.uncategorized;if(s){t.push(""),t.push(`UNCATEGORIZED RESIDUE \xB7 ${Vc(s.usd)} (${s.sharePct}%) \xB7 ${s.turns} turn(s) \xB7 by shape: `+(Object.entries(s.byShape||{}).filter(([,a])=>a>0).sort((a,i)=>i[1]-a[1]).map(([a,i])=>`${a} ${Vc(i)}`).join(" \xB7 ")||"none")),s.top?.length||t.push(" (nothing unmatched carried cost in this window)");for(let a of s.top||[])t.push(` ${is(Vc(a.usd),8)} ${is(a.shape,10)} ${is(String(a.track||"").slice(0,26),26)} | ${a.text}`);s.top?.length&&(t.push(""),t.push("novel-ask rows are vocabulary the classifier lacks: add a rule in agent/src/task-classifier.js (and a line in test/uncategorized-corpus.test.mjs). follow-up rows had no prior ask on their box."))}return t.join(`
738
- `)}Qn();var mo=36e5,u$=24*mo,qq=400,Wq=12,ls=e=>Math.round(e*1e4)/1e4;function my({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 Kq=(e,t)=>e!=null&&t-e<=48*mo?mo:u$;function i$(e,t){if(t===mo)return Math.floor(e/mo)*mo;let n=new Date(e);return n.setHours(0,0,0,0),n.getTime()}function Gq(e,t){if(t===mo)return e+mo;let n=new Date(e);return n.setDate(n.getDate()+1),n.setHours(0,0,0,0),n.getTime()}var c$=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),l$=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},zq=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,ls(n)]));async function d$(e,t={}){let n=t.now??Date.now(),r=my({...t,now:n}),o=r.since==null?u$:Kq(r.since,r.until),s=I=>(r.since==null||I>=r.since)&&I<r.until,a=r.since!=null?r.until-r.since:null,i=I=>a!=null&&I>=r.since-a&&I<r.since,c={},l={},u=c$(),d=0,p=0,f=0,w=0,m=0,g=0,y=new Set,x=new Map,b=[],O=[],$=[],C=null;for(let I of e||[]){let F=(await K(I)).filter(E=>E.type==="cost.recorded");if(!F.length){I.archivedAt||$.push(I.name||I.id);continue}let V=[];for(let E of F){let N=E.ts??0;s(N)?V.push(E):i(N)&&(g+=Kt(E).usd)}if(!V.length)continue;let A=jr(V,{boxLabels:Gc(I)});d+=A.totalUsd,p+=A.turns,f+=A.repricedTurns||0,w+=A.asRecordedUsd||0,m+=A.unpricedTurns||0;for(let E of A.unpricedModels||[])y.add(E);l$(u,A.totalTokens);for(let[E,N]of Object.entries(A.byModel))c[E]||={usd:0,events:0,tokens:c$()},c[E].usd=ls(c[E].usd+N.usd),c[E].events+=N.events,l$(c[E].tokens,N.tokens);for(let[E,N]of Object.entries(A.byProvider))l[E]||={usd:0,events:0},l[E].usd=ls(l[E].usd+N.usd),l[E].events+=N.events;for(let E of V){let{usd:N}=Kt(E);if(!N)continue;let H=i$(E.ts??0,o),z=x.get(H)??{t:H,total:0,byProvider:{}};z.total+=N;let fe=E.provider||"unknown";z.byProvider[fe]=(z.byProvider[fe]||0)+N,x.set(H,z),(C==null||H<C)&&(C=H)}b.push({id:I.id,name:I.name||I.id,archived:!!I.archivedAt,usd:A.totalUsd,turns:A.turns,providers:Object.keys(A.byProvider)});for(let[E,N]of Object.entries(A.byBox))O.push({trackId:I.id,trackName:I.name||I.id,boxId:E,...N})}let L=r.since!=null?i$(r.since,o):C,q=[];for(let I=L,_=0;I!=null&&I<r.until&&_<qq;I=Gq(I,o),_++){let F=x.get(I);q.push(F?{t:I,total:ls(F.total),byProvider:zq(F.byProvider)}:{t:I,total:0,byProvider:{}})}return b.sort((I,_)=>_.usd-I.usd),O.sort((I,_)=>_.usd-I.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",pricing:Bs(),window:r.key,since:r.since,until:r.until,bucketMs:o,series:q,fleet:{totalUsd:ls(d),asRecordedUsd:ls(w),turns:p,repricedTurns:f,unpricedTurns:m,unpricedModels:[...y],totalTokens:u,byModel:c,byProvider:l,tracksWithCost:b.length,tracksSilentLive:$},prior:a!=null?{totalUsd:ls(g),since:r.since-a,until:r.since}:null,tracks:b.slice(0,50),boxes:O.slice(0,Wq)}}Xu();var Vq=new Set(["cost.recorded","code.committed","code.rework","rework.cause.offered","rework.cause.answered"]),Jq=20,Yq=40;async function p$(e,t={}){let n=t.now??Date.now(),r=my({...t,now:n}),o=l=>(r.since==null||l>=r.since)&&l<r.until,s=[],a={},i=0;for(let l of e||[]){let u=await K(l),d=0,p=Gc(l);for(let f of u){if(!Vq.has(f.type))continue;let w=f.type==="code.rework"?f.payload?.ts??f.ts:f.ts;f.type!=="rework.cause.answered"&&!o(w??0)||(f.type==="code.committed"&&d++,s.push(f.trackId?f:{...f,trackId:l.id}))}d&&i++;for(let f of l.boxes||[])a[`${l.id}/${f.name}`]={trackName:l.name||l.id,label:p[f.name]||f.name}}let c=fT(s,{boxMeta:a});return{generatedAt:new Date().toISOString(),window:r.key,since:r.since,until:r.until,reworkWindowDays:Qr,decayEndDays:lh,basis:c.basis,commits:c.commits,tracksWithCommits:i,fixesAnalyzed:c.fixes.length,fixUsdTotal:c.fixUsdTotal,buckets:c.buckets,verdicts:c.verdicts,intents:c.intents,noCodeDelta:c.noCodeDelta,pendingTaps:c.pendingTaps.length,byProvider:c.byProvider,byModel:c.byModel,epochs:c.epochs.slice(0,Jq),fixes:c.fixes.slice(0,Yq)}}import Xq from"node:fs";import f$ from"node:fs/promises";import Jc from"node:os";import Zq from"node:path";tw();ct();var Qq=1024*1024,ip=e=>Math.round(e/Qq);async function eW(e){try{let t=await f$.statfs(e),n=t.blocks*t.bsize,r=n-t.bavail*t.bsize;return{diskUsedMb:ip(r),diskTotalMb:ip(n)}}catch{return{diskUsedMb:null,diskTotalMb:null}}}async function tW(){try{return(await nn()).filter(t=>t.isBostrat).length}catch{return null}}async function nW(){let e=0,t=!1;for(let n of["workspaces","worktrees"])try{let r=await f$.readdir(Zq.join(Nc,n),{withFileTypes:!0});e+=r.filter(o=>o.isDirectory()).length,t=!0}catch{}return t?e:null}async function m$({stateDir:e=Nc,now:t=Date.now}={}){let n=Jc.totalmem(),[r,o,s,a]=await Promise.all([fd().catch(()=>null),eW(Xq.existsSync(e)?e:Jc.tmpdir()),tW(),nW()]),i=Jc.cpus()?.length||null,c=Jc.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?ip(n-r):null,memTotalMb:ip(n),...o,boxes:s,worktrees:a,procUptimeS:Math.round(process.uptime()),osUptimeS:Math.round(Jc.uptime())}}Bh();de();qf();Xa();Qn();de();Qn();var rW=864e5;function oW(e,{tolerance:t=.005}={}){if(e.type!=="cost.recorded"||e.source==="vendor")return null;let n=e.payload?.tokens,r=Number(e.payload?.usd)||0;if(!(n?(n.input||0)+(n.output||0)+(n.cacheRead||0)+(n.cacheWrite??n.cacheCreation??0):0)||!r)return null;let s=e.payload?.model||"unknown",a=e.payload?.speed||void 0,i={input:n.input||0,output:n.output||0,cacheRead:n.cacheRead||0,cacheWrite:n.cacheWrite??n.cacheCreation??0},c=In(s,i,e.ts,a?{speed:a}:void 0);if(!c)return null;let l=r-c,u=Math.abs(l)>Math.max(c*t,.001);return{model:s,speed:a??null,ts:e.ts,asRecorded:r,expected:c,delta:l,divergent:u}}async function h$(e,{days:t=14,tolerance:n=.005,now:r=Date.now()}={}){let o=r-t*rW,s={},a=0,i=0,c=[];for(let u of e||[]){let d=await K(u);for(let p of d){if(!p.ts||p.ts<o)continue;let f=oW(p,{tolerance:n});if(!f)continue;a++;let w=f.speed?`${f.model} (${f.speed})`:f.model,m=s[w]||={rows:0,divergent:0,asRecordedUsd:0,expectedUsd:0};m.rows++,m.asRecordedUsd+=f.asRecorded,m.expectedUsd+=f.expected,f.divergent&&(i++,m.divergent++,c.length<10&&c.push({track:u.name||u.id,...f}))}}let l=u=>Math.round(u*1e4)/1e4;for(let u of Object.values(s))u.asRecordedUsd=l(u.asRecordedUsd),u.expectedUsd=l(u.expectedUsd);return{sinceMs:o,days:t,tolerance:n,rows:a,divergent:i,byModel:s,examples:c,ok:i===0}}Nh();Aw();vu();pt();Gt();import Ra from"node:fs/promises";import sW from"node:fs";import ht from"node:path";import aW from"node:os";import{execFile as iW}from"node:child_process";import{promisify as cW}from"node:util";var lW=cW(iW),w$=process.env.BOSTRAT_STATE_DIR||ht.join(process.env.HOME||aW.tmpdir(),".bostrat"),cp=!1,hy=null;async function wy(e,t){let n=await Ra.stat(e).catch(()=>null);if(!n?.isFile())return!1;let r=await Ra.stat(t).catch(()=>null);return r&&r.size===n.size&&r.mtimeMs>=n.mtimeMs?!1:(await Ra.mkdir(ht.dirname(t),{recursive:!0}),await Ra.copyFile(e,t),!0)}var uW=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 lp(e,t,{skip:n=null}={}){let r=0,o=await Ra.readdir(e,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(uW.has(s.name)||n?.has(s.name))continue;let a=ht.join(e,s.name);s.isDirectory()?r+=await lp(a,ht.join(t,s.name)):s.isFile()&&(r+=await wy(a,ht.join(t,s.name))?1:0)}return r}async function g$({stateDir:e=w$,dest:t=process.env.BOSTRAT_SYNC_DIR||`${w$}-sync`,remote:n=process.env.BOSTRAT_STATE_REMOTE||null,tracks:r=null}={}){try{await Ra.mkdir(t,{recursive:!0});let o=0;o+=await wy(ht.join(e,"tracks.json"),ht.join(t,"tracks.json"))?1:0,o+=await wy(ht.join(e,"events.jsonl"),ht.join(t,"events.jsonl"))?1:0,o+=await lp(ht.join(e,"events"),ht.join(t,"events")),o+=await lp(ht.join(e,"memory"),ht.join(t,"memory"));let s=new Set(["mocks"]);for(let u of r||[])!u?.cwd||!u?.id||(o+=await lp(ht.join(u.cwd,".bostrat"),ht.join(t,"workspaces",u.id,".bostrat"),{skip:s}));let a=(...u)=>lW("git",["-C",t,...u]);sW.existsSync(ht.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 Wp(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||cp))try{await a("push","-q",n,"HEAD:refs/heads/main"),l=!0,cp&&console.log("[state-sync] push recovered \u2014 off-box copy is current again"),cp=!1,hy=null}catch(u){cp=!0;let d=(u?.stderr||u?.message||String(u)).trim().split(`
739
- `).slice(-3).join(" | ").slice(0,300);d!==hy&&(hy=d,console.warn(`[state-sync] PUSH FAILING (retrying each cycle; off-box copy is STALE): ${d}`))}return{staged:o,committed:i,pushed:l}}catch(o){return{staged:0,committed:!1,pushed:!1,error:o?.message||String(o)}}}kw();an();Io();ct();Wa();import{execFile as dW}from"node:child_process";import{promisify as pW}from"node:util";import{randomUUID as fW}from"node:crypto";import mW from"node:fs";import hW from"node:os";import wW from"node:path";var wo=pW(dW),up=e=>new Promise(t=>setTimeout(t,e)),go=pf,gy=process.env.BOSTRAT_USAGE_PROBE_CWD||wW.join(hW.homedir(),".bostrat","usage-probe"),gW=Number(process.env.BOSTRAT_USAGE_IDLE_REAP_MS)||5*6e4,yW=Number(process.env.BOSTRAT_USAGE_PANEL_TIMEOUT_MS)||15e3,bW=Number(process.env.BOSTRAT_USAGE_READY_TIMEOUT_MS)||45e3,y$=Number(process.env.BOSTRAT_USAGE_CACHE_MS)||2e4,ho=null,Yc=null,Xc=null;async function kW(){try{return await wo(Y,Z("has-session","-t",go)),!0}catch{return!1}}function xW(){ho&&clearTimeout(ho),ho=setTimeout(()=>vW().catch(()=>{}),gW),ho.unref&&ho.unref()}async function vW(){ho&&(clearTimeout(ho),ho=null);try{await wo(Y,Z("kill-session","-t",go))}catch{}}async function SW(){let e=Date.now()+bW;for(;;){let t=await yy().catch(()=>"");if(/for agents|for shortcuts|bypass permissions on/i.test(t)){await up(500);return}if(Date.now()>e)throw new Error("usage probe didn't reach the prompt (trust/onboarding may be blocking)");await up(500)}}async function TW(){if(await kW())return;if(!await Rr())throw new Error("host tmux server not running \u2014 start globo-tmux.service");mW.mkdirSync(gy,{recursive:!0}),await vr(gy);let e=fW();await wo(Y,Z("new-session","-d","-s",go,"-c",gy,"-x","200","-y","60",...ai()));let t=`${df} --session-id ${e}`;await wo(Y,Z("send-keys","-t",go,t,"Enter")),await SW()}async function yy(){let{stdout:e}=await wo(Y,Z("capture-pane","-t",go,"-p"));return e}async function AW(){await TW(),await wo(Y,Z("send-keys","-t",go,"-l","/usage")),await wo(Y,Z("send-keys","-t",go,"Enter"));let e=Date.now()+yW,t="";for(;await up(400),t=await yy(),!(/Current\s+(session|week)/i.test(t)||/\d+%\s*used/i.test(t)||Date.now()>e););return await up(900),t=await yy(),await wo(Y,Z("send-keys","-t",go,"Escape")).catch(()=>{}),xW(),t}function EW(e){let t=String(e||"").split(`
740
- `).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 _W(e){let t=String(e||"").split(`
741
- `).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 b$({fresh:e=!1}={}){return!e&&Yc&&Date.now()-Yc.at<y$?Yc.data:Xc||(Xc=(async()=>{try{let t=await AW(),n=EW(t),r={...n,contributors:_W(t),subscription:!!(n.session||n.week||n.weekModels),capturedAt:Date.now()};return Yc={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 Yc={at:Date.now()-(y$-3e3),data:n},n}finally{Xc=null}})(),Xc)}var IW=262144;function $W(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 RW=new Set([300]),OW=new Set([10080]);function MW(e){let t=Number(e);return!Number.isFinite(t)||t<=0?null:RW.has(t)?"session":OW.has(t)?"week":"other"}function CW(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 NW(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?$W((o-n)/1e3):null,resetsAt:o}}var Zc=e=>({session:null,week:null,other:null,planType:null,credits:null,limitReached:null,sawTokenCount:e});function PW(e,t=Date.now()){let n=String(e||"").split(`
742
- `),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 Zc(r);if(c.primary||c.secondary){let l=Date.parse(a.timestamp)||null,u=Zc(r);[c.primary,c.secondary].forEach((f,w)=>{let m=NW(f,l,t);if(!m)return;let g=MW(f.window_minutes);g===null&&(g=w===0?"session":"week"),g==="session"&&!u.session?u.session=m:g==="week"&&!u.week?u.week=m:(u.other??=[]).push({label:CW(f.window_minutes),...m})}),u.planType=typeof c.plan_type=="string"?c.plan_type:null;let p=c.credits;return p&&(p.has_credits||p.unlimited)&&(u.credits={balance:String(p.balance??""),unlimited:!!p.unlimited}),u.limitReached=typeof c.rate_limit_reached_type=="string"&&c.rate_limit_reached_type||(c.spend_control_reached?"spend_control":null),u}if(c.primary_used_percent!=null||c.secondary_used_percent!=null){let l=u=>Number.isFinite(Number(u))?{pct:Math.round(Number(u)),resets:null,resetsAt:null}:null;return{...Zc(r),session:l(c.primary_used_percent),week:l(c.secondary_used_percent)}}return Zc(r)}return Zc(r)}async function by(e){let t={provider:"codex",supported:!0,contributors:null};try{let n=await Eo(e?.cwd,e?.sessionId);if(!n)return{...t,session:null,week:null,subscription:!1,error:"no codex rollout found for this box yet",capturedAt:Date.now()};let r=await _t(n.file,IW),o=PW(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 k$(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 dp({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 by(i);if(c.subscription){a=c;break}(!a||a.error&&!c.error)&&(a=c)}r.push(a||await by(null))}return n.has("cursor")&&r.push(await dp({agent:"cursor"})),{providers:r,capturedAt:Date.now()}}async function dp(e,{fresh:t=!1}={}){let n=e?.agent||"claude";return n==="codex"?by(e):n==="cursor"?{provider:"cursor",supported:!1,subscription:!1,session:null,week:null,contributors:null,capturedAt:Date.now()}:{provider:"claude",supported:!0,...await b$({fresh:t})}}Tr();pt();pt();function DW(e=process.env){return!!(Re(e)&&e.BOSTRAT_PLANE_TOKEN)}var BW=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),pp=(e,t)=>Object.assign(new Error(e),{status:t});async function x$(e,t){if(!DW(t))throw pp("node is not plane-linked \u2014 Gmail unavailable",503);let n;try{n=await fetch(`${Re(t)}${e}`,{headers:BW(t)})}catch(o){throw pp(`plane unreachable \u2014 Gmail unavailable (${o?.message||o})`,503)}let r=await n.json().catch(()=>({}));if(!n.ok)throw pp(r?.error||`plane replied ${n.status}`,n.status);return r}async function v$(e,{max:t=10,env:n=process.env}={}){let r=new URLSearchParams({q:e||""});return t&&r.set("max",String(t)),(await x$(`/v1/gmail/messages?${r.toString()}`,n)).messages||[]}async function S$(e,{env:t=process.env}={}){if(!e)throw pp("message id required",400);return(await x$(`/v1/gmail/messages/${encodeURIComponent(e)}`,t)).message}Bi();ju();function ky(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 jW(e){let[t,n]=e.split("/"),r=ky(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 T$(e){return(e||"").split(",").map(t=>t.trim()).filter(Boolean).map(jW).filter(Boolean)}function LW(e){let t=e.headers["fly-client-ip"];return typeof t=="string"&&t.trim()?t.trim():(e.socket&&e.socket.remoteAddress||"").replace(/^::ffff:/,"")}function A$(e){let t=T$(e),n=String(e||"").trim().toLowerCase()==="open";return{open:n,clientIp:LW,allowed(r){if(n)return!0;let o=ky((r||"").replace(/^::ffff:/,""));return o==null?!1:t.some(s=>s(o))}}}function E$(e,t){let n=T$(e);return{active:n.length>0,allows(r){if(!n.length)return!1;let o=(r.socket&&r.socket.remoteAddress||"").replace(/^::ffff:/,""),s=ky(o);if(s==null||!n.some(i=>i(s)))return!1;let a=t(r);return!!(a&&a.view)}}}import _$ from"node:crypto";import fp from"node:fs";import FW from"node:path";function I$(e=process.env,{stateDir:t=Nc,log:n=console}={}){let r=String(e.BOSTRAT_NODE_API_TOKEN||"").trim();if(r)return r;let o=FW.join(t,"api-token");try{let a=fp.readFileSync(o,"utf8").trim();if(a)return a}catch{}let s=_$.randomBytes(32).toString("base64url");try{fp.mkdirSync(t,{recursive:!0}),fp.writeFileSync(o,s+`
743
- `,{mode:384}),fp.chmodSync(o,384)}catch(a){n.error?.(`[bostrat-agent] could not persist the node API token: ${a?.message||a}`)}return s}function Qc(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 $$(e,t){if(!e||!t)return!1;let n=Buffer.from(String(e)),r=Buffer.from(String(t));return n.length!==r.length?!1:_$.timingSafeEqual(n,r)}function R$(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 UW=[/^\/api\/github\/token\b/,/^\/api\/gmail\b/,/^\/api\/tracks\/adopt\b/,/^\/api\/tracks\/[^/]+\/transfer-out\b/,/^\/api\/node\/self-update\b/,/^\/api\/changelog\/(publish|retract)\b/,/^\/api\/tracks\/[^/]+\/loop-(update|delete)-offer\b/],HW=e=>UW.some(t=>t.test(e));function O$({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=R$(o);return $$(c,e)?a():HW(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||Qc(o)?a():(n.log?.(`[perimeter] refused ${o.method} ${i} from ${o.socket?.remoteAddress||"?"} \u2014 no node API token`),s.status(401).json({error:"unauthorized"}))}}function M$(e,t,{enforce:n=!0}={}){return!n||$$(R$(e),t)?!0:Qc(e)}Tn();dd();dd();import qW from"node:http";import WW from"node:net";function mp(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 hp(e){let t=mp(e.headers.host);return t?{slug:t,view:Yh(t)}:null}var KW=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;"),GW=e=>{let t=KW(e.name);return`<!doctype html><meta charset="utf-8">
736
+ _${o} archived_`:"")}async function TW(e,t){let n=await hs();if(!n)return Ue("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 Ue("Usage: `/bostrat start <name> [repo]`");let i=await r.listRepos(),c=a[a.length-1]?.toLowerCase(),l=a.length>1?i.find(d=>d.name.toLowerCase()===c):null,u=(l?a.slice(0,-1):a).join(" ");return l?(wo(d$(e,n,{name:u,repo:l.path,responseUrl:t.response_url})),Ue(`Starting *${Ae(u)}* on ${Ae(l.name)}\u2026`)):{response_type:"ephemeral",text:`Pick a repo for \u201C${u}\u201D`,blocks:SW(u,i)}}case"archive":{if(!a.length)return Ue("Usage: `/bostrat archive <track>`");let{match:i,live:c}=xy(await r.listTracks(),a.join(" "));return i?(wo(kW(e,n,{track:i,responseUrl:t.response_url})),Ue(`Archiving *${Ae(i.name)}*\u2026`)):vy(c,a.join(" "))}case"handoff":{let i=r.knownAgents??bW,c=a.at(-1)?.toLowerCase();if(a.length<2||!i.includes(c))return Ue(`Usage: \`/bostrat handoff <track> <${i.join("|")}>\``);let l=a.slice(0,-1).join(" "),{match:u,live:d}=xy(await r.listTracks(),l);return u?(wo(xW(e,n,{track:u,agent:c,responseUrl:t.response_url})),Ue(`Handing *${Ae(u.name)}* to ${Ae(c)}\u2026`)):vy(d,l)}case"stop":{if(!a.length)return Ue("Usage: `/bostrat stop <track>`");let{match:i,live:c}=xy(await r.listTracks(),a.join(" "));return i?(wo(vW(e,n,{track:i,responseUrl:t.response_url})),Ue(`Stopping *${Ae(i.name)}*\u2026`)):vy(c,a.join(" "))}case"list":return Ue(await AW(r));default:return Ue(yW)}}async function EW(e,t,n,r){let{trackId:o,promptId:s,label:a}=r,i=await Ey(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 kn(),await ys(t.botToken,{channel:i.channel,ts:c,text:`\u2713 ${a}`,blocks:[{type:"section",text:{type:"mrkdwn",text:`~${Ae(l||"question")}~
737
+ \u2713 *${Ae(a)}*`}}]}).catch(()=>{})}}catch(c){await St(n.response_url,Ue(`Couldn't answer: ${c?.message||c}`))}}async function _W(e,t,n,r){let{trackId:o,offerId:s,action:a}=r,i=e.deps;try{let c=await i.resolveTrack(o);if(!c)throw new Error("track not found");let l=await i.readEvents(c),u=l.find(p=>p.type==="pr.offered"&&p.payload?.offerId===s);if(!u)throw new Error("unknown offer");if(l.some(p=>p.type==="pr.offer.answered"&&p.payload?.offerId===s))throw new Error("offer already answered");let d=Array.isArray(r.actions)?Xr.filter(p=>r.actions.includes(p)):a==="pr"?["commit","push","pr"]:a==="push"?["commit","push"]:null;if(d?.includes("pr")&&i.divertShip&&await i.divertShip(c,u,{actions:d}))return;d&&await i.sayToLead(c.id,oa(d,{branch:u.payload.branch,base:u.payload.base}),{kind:d.includes("pr")?"pr-go":"push-go"}),await i.appendEvent({id:c.id,cwd:c.cwd},{type:"pr.offer.answered",actor:"user",source:"orchestrator",boxId:u.boxId,payload:{ts:Date.now(),offerId:s,action:d?a:"dismiss",actions:d}})}catch(c){await St(n.response_url,Ue(`Couldn't act on the offer: ${c?.message||c}`))}}async function IW(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 St(n.response_url,Ue(`Couldn't act on the offer: ${i?.message||i}`))}}async function $W(e,t){let n=t.actions?.[0];if(!n?.action_id)return;let r=await hs();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 St(t.response_url,{...Ue(`Starting *${Ae(s)}*\u2026`),replace_original:!0}),wo(d$(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"?wo(EW(e,r,t,o)):n.action_id==="bostrat-ship"?wo(_W(e,r,t,o)):n.action_id==="bostrat-pr-exists"&&wo(IW(e,r,t,o))}async function RW(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 wW(t.channel,t.thread_ts);if(!n)return;let r=await hs();if(r)try{await e.deps.sayToLead(n.trackId,t.text.trim())}catch(o){await go(r,n.rec,`Couldn't deliver that to the lead: ${o?.message||o}`).catch(()=>{})}}function OW(e){return async t=>{if(t.type==="slash_commands")return TW(e,t.payload);if(t.type==="interactive"){await $W(e,t.payload);return}if(t.type==="events_api"){await RW(e,t.payload?.event);return}}}var MW=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 CW(e,t){let n=[{type:"section",text:{type:"mrkdwn",text:`\u2753 ${Ae(t.question||"The lead needs an answer")}`}}],r=(t.options||[]).slice(0,12);return r.length?n.push({type:"actions",elements:r.map(o=>({type:"button",action_id:"bostrat-prompt",text:{type:"plain_text",text:Jc(String(o),75)},value:JSON.stringify({trackId:e,promptId:t.promptId,label:String(o)})}))}):n.push({type:"context",elements:[{type:"mrkdwn",text:"_reply in this thread to answer_"}]}),n}async function NW(e,t,n){let r=n.payload||{};if(!r.promptId||t.prompt?.promptId===r.promptId)return;t.prompt&&await ys(e.botToken,{channel:t.channel,ts:t.prompt.ts,text:"superseded",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${Ae(t.prompt.question||"question")}~ _superseded_`}}]}).catch(()=>{});let o=await go(e,t,r.question||"The lead needs an answer",CW(n.trackId,r));t.prompt={promptId:r.promptId,ts:o.ts,question:r.question||null},await kn()}async function PW(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 kn(),await ys(e.botToken,{channel:t.channel,ts:o,text:"answered",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${Ae(s||"question")}~
738
+ \u2713 _answered_`}}]})}async function DW(e,t,n){let r=n.payload||{};if(!r.offerId||t.offers?.[r.offerId])return;let o=(i,c,l,u)=>({type:"button",action_id:"bostrat-ship",text:{type:"plain_text",text:c},value:JSON.stringify({trackId:n.trackId,offerId:r.offerId,action:i,...u?{actions:u}:{}}),...l?{style:l}:{}}),s;if(!Array.isArray(r.available))s=r.toPr?[o("push",`Commit & push${r.toPr.number?` to #${r.toPr.number}`:""}`,"primary"),o("dismiss","Not now")]:[o("pr","Open PR","primary"),o("push","Just push"),o("dismiss","Not now")];else{let i=r.available,c=Array.isArray(r.defaults)&&r.defaults.length?r.defaults:i,l={commit:"Commit",rebase:"rebase",push:"push",pr:r.prState==="open"?"open new PR":"open PR"},u=c.map(d=>l[d]).filter(Boolean).join(" & ");s=[o(c.includes("pr")?"pr":"push",u||"Ship","primary",c)],i.includes("pr")&&!c.includes("pr")&&s.push(o("pr","Open new PR",void 0,["pr"])),s.push(o("dismiss","Not now"))}let a=await go(e,t,r.excerpt||"Ship it?",[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${Ae(Jc(r.excerpt||"The lead offered to ship.",300))}`}},{type:"actions",elements:s}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await kn()}async function BW(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await kn();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 ys(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function jW(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 go(e,t,`PR ${o} already open \u2014 push or new PR?`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${o}${r.branch?` (${Ae(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 kn()}async function LW(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await kn();let s=r.choice==="dismiss"?"dismissed":r.choice==="new"?"\u2713 opening a new PR":"\u2713 pushing to the open PR";await ys(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function FW(e,t,n,r){let o=n.payload||{};if(o.change==="ready"&&o.mockId){let s=await(r.readMockPng??UW)(o.mockId,o.version??null);if(!s)return;let a=(o.version??1)>1?` (v${o.version})`:"";await s$(e.botToken,{filename:s.filename,buffer:s.buffer,title:`${o.name}${a}`,channelId:t.channel,threadTs:t.ts,initialComment:`\u{1F3A8} mock *${Ae(o.name)}*${a}${o.group?` (group \`${Ae(o.group)}\`)`:""}`})}else if(o.change==="picked"){let s=(o.siblings??[]).map(a=>`*${Ae(a.name)}*`).join(", ");await go(e,t,`Design decision: ${o.name} picked`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F3A8} design decision: *${Ae(o.name)}* picked${s?` over ${s}`:""}`}}])}}async function UW(e,t){let n=await wr(e);if(!n)return null;let r=fn(n,t);if(!r)return null;let o=await Vc.readFile(Qt(n,r.v).png).catch(()=>null);return o?{filename:`${n.name.replace(/[^\w.-]+/g,"-")}.v${r.v}.png`,buffer:o}:null}async function HW(e,t){if(!MW.has(t.type))return;let n=await Ey(t.trackId);if(!n)return;let r=await hs();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 kn(),await Ay(r,n);return;case"turn.agent":{if(!o.text)return;let s=gW(o.text);if(!s)return;await go(r,n,s,[{type:"section",text:{type:"mrkdwn",text:Ae(s)}},{type:"context",elements:[{type:"mrkdwn",text:`<${wp(t.trackId)}|full turn \u2192>`}]}]);return}case"prompt.raised":return NW(r,n,t);case"prompt.answered":return PW(r,n,t);case"pr.offered":return DW(r,n,t);case"pr.offer.answered":return BW(r,n,t);case"pr.exists.offered":return jW(r,n,t);case"pr.exists.answered":return LW(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 go(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 kn(),await Ay(r,n);return;case"view.state.changed":{if(o.change!=="created"||o.restarted||!o.slug)return;await go(r,n,`Live preview ${o.name}: ${gp(o.slug)}`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F50D} live preview *${Ae(o.name)}*: ${gp(o.slug)}
739
+ _runs on the Track's branch; reachable on the operator's private network only_`}}]);return}case"mock.state.changed":return FW(r,n,t,e.deps)}}function p$(e){let t={deps:e};Je.on("event",s=>{HW(t,s).catch(()=>{})});let n=null,r=null,o=async()=>{n||!await hs()||(r&&clearInterval(r),r=null,n=a$({getToken:async()=>(await hs())?.appToken,onEnvelope:OW(t),log:s=>console.log(`[slack] ${s}`)}))};return r=setInterval(()=>o().catch(()=>{}),3e4),r.unref?.(),o().catch(()=>{}),()=>{r&&clearInterval(r),n?.()}}cn();fe();En();Nh();rr();import WW from"node:fs/promises";function qW(e){let t=new Map;for(let n of String(e||"").split(`
740
+ `)){let r=n.trim();if(!r||r[0]!=="{")continue;let o;try{o=JSON.parse(r)}catch{continue}let s=o?.message?.usage;if(!s)continue;let a={input:s.input_tokens||0,output:s.output_tokens||0,cacheWrite:s.cache_creation_input_tokens||0,cacheRead:s.cache_read_input_tokens||0};if(a.input+a.output+a.cacheWrite+a.cacheRead===0)continue;let i=o.message?.id||o.uuid||null;if(!i)continue;let c=s.cache_creation,l=c&&typeof c=="object"?{m5:c.ephemeral_5m_input_tokens||0,h1:c.ephemeral_1h_input_tokens||0}:null,u=typeof s.speed=="string"&&s.speed!=="standard"?s.speed:null;t.set(i,{messageId:i,tokens:a,cacheWriteTtl:l,speed:u,model:o.message?.model||o.model||null})}return[...t.values()]}function KW(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 GW=new Set(["Write","Edit","NotebookEdit"]),zW=220,VW=160;function JW(e,t){let n=e?.tool_name??null,r={tool:n},o=e?.tool_input;if(!o||typeof o!="object")return r;if(GW.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,zW)}else n==="Bash"&&typeof o.command=="string"&&o.command.trim()&&(r.head=Io(o.command.trim().replace(/\s+/g," ")).slice(0,VW));return r}function YW(e,t){return e?.transcript_path?e.transcript_path:t?.cwd&&t?.sessionId?an(t.cwd,t.sessionId):t?.cwd?Cf(t.cwd):null}async function f$(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 M(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=id(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:JW(e,o)});break;case"Stop":await XW(r,o,e,i);break;default:break}return a}async function XW(e,t,n,r){let o=[],s=YW(n,t);if(s)try{o=qW(await WW.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=KW(await K(e)),c=o.filter(u=>!i.has(u.messageId));if(c.length){let u=new Map;for(let d of c){let p=`${d.model||"unknown"}\0${d.speed||""}`,f=u.get(p)||{tokens:{input:0,output:0,cacheWrite:0,cacheRead:0},cacheWriteTtl:null,messageIds:[]};for(let w of Object.keys(f.tokens))f.tokens[w]+=d.tokens[w];d.cacheWriteTtl&&(f.cacheWriteTtl??={m5:0,h1:0},f.cacheWriteTtl.m5+=d.cacheWriteTtl.m5,f.cacheWriteTtl.h1+=d.cacheWriteTtl.h1),f.messageIds.push(d.messageId),f.speed=d.speed||null,u.set(p,f)}for(let[d,p]of u){let f=d.split("\0")[0];await r({type:"cost.recorded",actor:"system",source:"transcript",payload:{model:f,usd:On(f,p.tokens,void 0,p.speed?{speed:p.speed}:void 0),tokens:p.tokens,...p.speed?{speed:p.speed}:{},cacheWriteTtl:p.cacheWriteTtl,messageId:p.messageIds[p.messageIds.length-1],messageIds:p.messageIds,apiCalls:p.messageIds.length}})}}let l=a.tokens.input+a.tokens.cacheWrite+a.tokens.cacheRead;await r({type:"context.usage",actor:"system",source:"transcript",payload:{model:a.model,occupancy:l,tokens:a.tokens}})}Ts();Af();sd();fe();fe();Wr();fe();Wr();rr();function Yc(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 m$=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),h$=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},xp=e=>Math.round(e*1e4)/1e4;async function _y(e){let t=[],n={},r={},o=0,s=0,a=0,i=0,c=0,l=new Set,u=m$(),d=0,p=[];for(let f of e||[]){let w=await K(f),m=Hr(w,{boxLabels:Yc(f)});if(m.turns===0){f.archivedAt?d++:p.push(f.name||f.id);continue}o+=m.totalUsd,s+=m.turns,a+=m.repricedTurns||0,i+=m.asRecordedUsd||0,c+=m.unpricedTurns||0;for(let g of m.unpricedModels||[])l.add(g);h$(u,m.totalTokens);for(let[g,y]of Object.entries(m.byModel))n[g]||={usd:0,events:0,tokens:m$()},n[g].usd=xp(n[g].usd+y.usd),n[g].events+=y.events,h$(n[g].tokens,y.tokens);for(let[g,y]of Object.entries(m.byProvider))r[g]||={usd:0,events:0},r[g].usd=xp(r[g].usd+y.usd),r[g].events+=y.events;t.push({id:f.id,name:f.name,usd:m.totalUsd,rollup:m})}return t.sort((f,w)=>w.usd-f.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",pricing:Vs(),fleet:{totalUsd:xp(o),asRecordedUsd:xp(i),turns:s,repricedTurns:a,unpricedTurns:c,unpricedModels:[...l],totalTokens:u,byModel:n,byProvider:r,tracksWithCost:t.length,tracksSilent:d+p.length,tracksSilentArchived:d,tracksSilentLive:p},tracks:t}}var yo=e=>`$${e.toFixed(4)}`,ja=(e,t)=>String(e).padEnd(t);function w$(e){let{fleet:t,tracks:n}=e,r=[];r.push(`BOSTRAT COST READ-OUT \xB7 ${e.generatedAt}`),e.pricingBasis&&r.push(`basis: ${e.pricingBasis}`);let o=t.tracksSilentLive||[];if(r.push(`fleet total ${yo(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 ${yo(t.asRecordedUsd)} \xB7 current-rates total ${yo(t.totalUsd)} (${t.totalUsd>=t.asRecordedUsd?"+":""}${yo(t.totalUsd-t.asRecordedUsd)})`),t.unpricedTurns&&r.push(`\u26A0 ${t.unpricedTurns} turn(s) UNPRICED \u2014 total under-reports. Add PER_MTOK rate(s) for: ${(t.unpricedModels||[]).join(", ")}`),e.pricing){let a=e.pricing;r.push(`rates verified against vendor pages: ${a.tableVerifiedAt??"never"}`+(a.upcomingChanges?.length?` \xB7 scheduled: ${a.upcomingChanges.map(i=>`${i.model} ${i.from}`).join(", ")}`:""));for(let i of a.problems||[])r.push(`\u26A0 RATE TABLE: ${i}`)}r.push(""),r.push("BY MODEL");let s=Object.entries(t.byModel).sort((a,i)=>i[1].usd-a[1].usd);s.length||r.push(" (no cost events yet \u2014 hooks emit on each turn of a newly started box)");for(let[a,i]of s){let c=i.tokens;r.push(` ${ja(a,26)} ${ja(yo(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(` ${ja(a.name||a.id,30)} ${yo(a.usd)}`);let i=Object.values(a.rollup.byBox).sort((c,l)=>l.usd-c.usd);for(let c of i)if(r.push(` ${ja(c.label,40)} ${ja(yo(c.usd),10)} ${c.models.join(",")||"?"}`),c.epochs)for(let[l,u]of Object.entries(c.epochs).sort((d,p)=>Number(d[0])-Number(p[0])))r.push(` \u21B3 tenure ${l} (${u.provider||"?"})${" ".repeat(Math.max(1,24-String(u.provider||"?").length))}${ja(yo(u.usd),10)} ${u.models.join(",")||"?"}`)}return r.join(`
741
+ `)}fe();oh();import oq from"node:fs/promises";import sq from"node:path";ru();cu();Wr();var vp=e=>e.payload?.ts??e.ts,ZW=12e4,en=e=>Math.round(e*1e4)/1e4,QW=()=>({usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{},byTrack:new Map});function eq(e,{since:t}){let{track:n,events:r,brief:o}=e,s=b=>vp(b)>=t,a=nr([Mi(n?.name),Mi(n?.workspace?.branch),o].filter(Boolean).join(" ")),i=new Map;for(let b of r)if(b.type==="subtask.delegated"&&b.boxId&&b.payload?.task){let R=nr(b.payload.task);R&&i.set(b.boxId,R)}let c=new Map,l=b=>{let R=b||"unattributed";return c.has(R)||c.set(R,{segments:[u(null)],lastTs:null,provider:null}),c.get(R)},u=(b,{shape:R="initial",continuation:_=!1,text:C=null,ts:U=null}={})=>({textCat:b,shape:R,continuation:_,text:C,ts:U,tools:{},usd:0,tokens:{input:0,output:0,cacheRead:0,cacheWrite:0},models:{},provider:null,activeMs:0,turns:0,toolCalls:0}),d=[...r].sort((b,R)=>vp(b)-vp(R)),p=0,f=0,w=0,m={turns:0};for(let b of d){let R=l(b.boxId),_=R.segments[R.segments.length-1],C=vp(b);switch(R.lastTs!=null&&C>R.lastTs&&s(b)&&(_.activeMs+=Math.min(C-R.lastTs,ZW)),R.lastTs=C,b.provider&&(R.provider=b.provider),b.type){case"turn.user":{let U=b.payload?.text;if(b.source==="hook"||!String(U||"").trim()||b.payload?.note||Pi(U))break;let B=nr(U),T=!!b.payload?.kind,$=T||B0(U),L=u(B,{shape:T?"injected":$?"follow-up":"novel-ask",continuation:!B&&$,text:y$(U),ts:C});R.segments.push(L),s(b)&&(L.turns+=1);break}case"peer.message":{let U=b.payload?.text;if(!String(U||"").trim())break;let B=nr(U),T=u(B,{shape:"peer",continuation:!B,text:y$(U),ts:C});R.segments.push(T),s(b)&&(T.turns+=1);break}case"tool.called":{if(b.source==="transcript")break;let U=b.payload?.tool;U&&(_.tools[U]=(_.tools[U]||0)+1),s(b)&&(_.toolCalls+=1);break}case"cost.recorded":{if(!s(b))break;let{usd:U,tokens:B,model:T,unpriced:$}=Vt(b);$&&(m.turns+=1),_.usd+=U,B&&(_.tokens.input+=B.input,_.tokens.output+=B.output,_.tokens.cacheRead+=B.cacheRead,_.tokens.cacheWrite+=B.cacheWrite),_.models[T]=(_.models[T]||0)+U,b.provider&&(_.provider=b.provider);break}case"handoff.done":s(b)&&(p+=1);break;case"subtask.merged":s(b)&&(f+=1);break;case"error":s(b)&&b.payload?.kind==="subtask-failed"&&(w+=1);break;default:break}}let g=new Map,y={usd:0,turns:0,byShape:{},samples:[]},x=!1;for(let[b,R]of c){let _=null;for(let C of R.segments){let U=null,B=null;if(C.textCat)U=C.textCat.category,B="text";else if(i.get(b))U=i.get(b).category,B="boxTask";else if(C.continuation&&_)U=_,B="inherited";else{let A=D0(C.tools);A?(U=A.category,B="toolMix"):a&&(U=a.category,B="hint")}if(U&&(_=U),!(C.usd>0||C.activeMs>0||C.turns>0||C.toolCalls>0))continue;let $=U??"uncategorized";g.has($)||g.set($,{usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{}});let L=g.get($);L.usd+=C.usd,L.activeMs+=C.activeMs,L.turns+=C.turns,L.toolCalls+=C.toolCalls,B&&(L.provenance[B]=(L.provenance[B]||0)+C.usd);for(let[A,S]of Object.entries(C.models))L.models[A]=(L.models[A]||0)+S;let J=C.provider||R.provider;J&&(L.providers[J]=(L.providers[J]||0)+C.usd),J==="cursor"&&C.usd===0&&(x=!0),U||(y.usd+=C.usd,y.turns+=C.turns,y.byShape[C.shape]=(y.byShape[C.shape]||0)+C.usd,C.usd>0&&C.text&&y.samples.push({trackId:n?.id,track:n?.name||n?.id,shape:C.shape,usd:en(C.usd),ts:C.ts,text:C.text}))}}return{perCategory:g,uncategorized:y,handoffs:p,merged:f,failed:w,sawCursorActivity:x,unpricedTurns:m.turns}}function Iy(e,{windowMs:t=null,now:n=Date.now()}={}){let r=t==null?0:n-t,o=new Map,s=[],a=0,i=!1,c=0,l={usd:0,turns:0,byShape:{},samples:[]};for(let y of e||[]){let{track:x,events:b}=y;if(!b?.length){a+=1;continue}let{perCategory:R,uncategorized:_,handoffs:C,merged:U,failed:B,sawCursorActivity:T,unpricedTurns:$}=eq(y,{since:r});T&&(i=!0),c+=$,l.usd+=_.usd,l.turns+=_.turns;for(let[J,A]of Object.entries(_.byShape))l.byShape[J]=(l.byShape[J]||0)+A;l.samples.push(..._.samples);let L={trackId:x?.id,name:x?.name||x?.id,archived:!!x?.archivedAt,usd:0,activeMs:0,turns:0,categories:{},models:{},providers:{},handoffs:C,subtasksMerged:U,subtasksFailed:B};for(let[J,A]of R){L.usd+=A.usd,L.activeMs+=A.activeMs,L.turns+=A.turns,L.categories[J]={usd:en(A.usd),activeMs:A.activeMs};for(let[H,q]of Object.entries(A.models))L.models[H]=en((L.models[H]||0)+q);for(let[H,q]of Object.entries(A.providers))L.providers[H]=en((L.providers[H]||0)+q);o.has(J)||o.set(J,QW());let S=o.get(J);S.usd+=A.usd,S.activeMs+=A.activeMs,S.turns+=A.turns,S.toolCalls+=A.toolCalls;for(let[H,q]of Object.entries(A.models))S.models[H]=(S.models[H]||0)+q;for(let[H,q]of Object.entries(A.providers))S.providers[H]=(S.providers[H]||0)+q;for(let[H,q]of Object.entries(A.provenance))S.provenance[H]=(S.provenance[H]||0)+q;let N=S.byTrack.get(x?.id)||{usd:0,activeMs:0};N.usd+=A.usd,N.activeMs+=A.activeMs,S.byTrack.set(x?.id,N)}(L.usd>0||L.activeMs>0||L.turns>0)&&(L.usd=en(L.usd),L.dominantCategory=rq(L.categories),s.push(L))}let u=[...o.values()].reduce((y,x)=>y+x.usd,0),d=[...o.values()].reduce((y,x)=>y+x.activeMs,0),p=u>0?"usd":"time",f=p==="usd"?u:d,w=new Map((e||[]).map(y=>[y.track?.id,y.track?.name||y.track?.id])),m=[...o.entries()].map(([y,x])=>({category:y,sharePct:f>0?Math.round((p==="usd"?x.usd:x.activeMs)/f*100):0,shareBasis:p,usd:en(x.usd),activeMs:x.activeMs,turns:x.turns,toolCalls:x.toolCalls,models:Xc(x.models),providers:Xc(x.providers),provenance:Xc(x.provenance),topWorkstreams:[...x.byTrack.entries()].sort((b,R)=>R[1].usd-b[1].usd||R[1].activeMs-b[1].activeMs).slice(0,2).map(([b,R])=>({trackId:b,name:w.get(b),usd:en(R.usd),activeMs:R.activeMs}))})).sort((y,x)=>x.usd-y.usd||x.activeMs-y.activeMs);s.sort((y,x)=>x.usd-y.usd||x.activeMs-y.activeMs);let g={};for(let y of o.values())for(let[x,b]of Object.entries(y.provenance))g[x]=(g[x]||0)+b;return{since:r,capturedAt:n,totalUsd:en(u),activeMs:d,turns:[...o.values()].reduce((y,x)=>y+x.turns,0),bullets:m,workstreams:s,provenance:Xc(g),gaps:{tracksWithoutEvents:a,cursorCostUnknown:i,unpricedTurns:c,uncategorized:{usd:en(l.usd),turns:l.turns,sharePct:u>0?Math.round(l.usd/u*100):0,byShape:Xc(l.byShape),top:l.samples.sort((y,x)=>x.usd-y.usd).slice(0,tq)}}}}var tq=25,g$=160,y$=e=>{let t=String(e||"").replace(/\s+/g," ").trim();return t.length>g$?`${t.slice(0,g$).trimEnd()}\u2026`:t},nq=10;function b$(e,{thresholdPct:t=nq}={}){let n=e?.gaps?.uncategorized||{usd:0,turns:0},r=e?.totalUsd||0,o=n.usd||0,s=r>0?o/r*100:0,a=s<=t,i=a?[]:[`${s.toFixed(1)}% of the last 7d ($${o.toFixed(2)} of $${r.toFixed(2)}) is uncategorized (threshold ${t}%) \u2014 run \`npm run cost -- --uncategorized\` and add classifier table lines for the top asks`];return{ok:a,sharePct:Math.round(s*10)/10,thresholdPct:t,usd:en(o),totalUsd:en(r),turns:n.turns||0,inheritedPct:r>0?Math.round((e?.provenance?.inherited||0)/r*100):0,problems:i}}var rq=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},Xc=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,en(n)]));var ks={"24h":24*36e5,"7d":168*36e5,"30d":720*36e5,all:null};function aq(e){let t=String(e||"7d");return t in ks?{key:t,ms:ks[t]}:{key:"7d",ms:ks["7d"]}}function iq(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=Mu(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 cq(e){if(!e?.cwd)return null;try{let n=(await oq.readFile(sq.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 $y(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}:aq(t),d=[];for(let w of e||[]){let m=await K(w),g=iq(w,m);i&&c<o&&(g=g.filter(y=>(y.ts??0)<=c)),d.push({track:w,events:g,brief:await cq(w)})}let p=Iy(d,{windowMs:u,now:c}),f=l==="7d"&&c===o?p:Iy(d,{windowMs:ks["7d"],now:o});return{window:l,...p,categorization:b$(f)}}var Zc=e=>`$${Number(e||0).toFixed(2)}`,k$=e=>{let t=Math.round((e||0)/6e4);return t>=60?`${Math.floor(t/60)}h${String(t%60).padStart(2,"0")}`:`${t}m`},bs=(e,t)=>String(e).padEnd(t);function x$(e){let t=[];t.push(`USAGE ROUNDUP \xB7 ${e.window} \xB7 ${Zc(e.totalUsd)} \xB7 ${k$(e.activeMs)} active \xB7 ${e.turns} turn(s) \xB7 as of ${new Date(e.capturedAt).toISOString()}`);let n=e.provenance||{};e.totalUsd>0&&Object.keys(n).length&&t.push("labeled by: "+Object.entries(n).sort((a,i)=>i[1]-a[1]).map(([a,i])=>`${a} ${Math.round(i/e.totalUsd*100)}%`).join(" \xB7 ")),t.push(""),t.push("WHERE IT WENT");for(let a of e.bullets||[])t.push(` ${bs(`${a.shareBasis==="time"?"~":""}${a.sharePct}%`,5)} ${bs(a.category,15)} ${bs(Zc(a.usd),10)} ${bs(k$(a.activeMs),6)} ${a.turns} turn(s)`+(a.topWorkstreams?.length?` \xB7 ${a.topWorkstreams.map(i=>i.name).join(", ")}`:""));let r=e.gaps||{};r.tracksWithoutEvents&&t.push(`${r.tracksWithoutEvents} track(s) have no attributed events yet`),r.cursorCostUnknown&&t.push("cursor time counted, cost unavailable"),r.unpricedTurns&&t.push(`WARNING: ${r.unpricedTurns} turn(s) unpriced \u2014 total under-reports`);let o=e.categorization;if(o){t.push(""),t.push((o.ok?"categorization ok: ":"CATEGORIZATION ALARM: ")+`${o.sharePct}% of the last 7d uncategorized (threshold ${o.thresholdPct}%) \xB7 ${o.inheritedPct}% inferred from the previous ask`);for(let a of o.problems||[])t.push(`WARNING: ${a}`)}let s=r.uncategorized;if(s){t.push(""),t.push(`UNCATEGORIZED RESIDUE \xB7 ${Zc(s.usd)} (${s.sharePct}%) \xB7 ${s.turns} turn(s) \xB7 by shape: `+(Object.entries(s.byShape||{}).filter(([,a])=>a>0).sort((a,i)=>i[1]-a[1]).map(([a,i])=>`${a} ${Zc(i)}`).join(" \xB7 ")||"none")),s.top?.length||t.push(" (nothing unmatched carried cost in this window)");for(let a of s.top||[])t.push(` ${bs(Zc(a.usd),8)} ${bs(a.shape,10)} ${bs(String(a.track||"").slice(0,26),26)} | ${a.text}`);s.top?.length&&(t.push(""),t.push("novel-ask rows are vocabulary the classifier lacks: add a rule in agent/src/task-classifier.js (and a line in test/uncategorized-corpus.test.mjs). follow-up rows had no prior ask on their box."))}return t.join(`
742
+ `)}rr();var bo=36e5,T$=24*bo,lq=400,uq=12,xs=e=>Math.round(e*1e4)/1e4;function Ry({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 ks?String(e||"7d"):"7d",i=ks[a];return{key:a,since:i==null?null:r-i,until:r}}var dq=(e,t)=>e!=null&&t-e<=48*bo?bo:T$;function v$(e,t){if(t===bo)return Math.floor(e/bo)*bo;let n=new Date(e);return n.setHours(0,0,0,0),n.getTime()}function pq(e,t){if(t===bo)return e+bo;let n=new Date(e);return n.setDate(n.getDate()+1),n.setHours(0,0,0,0),n.getTime()}var S$=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),A$=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},fq=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,xs(n)]));async function E$(e,t={}){let n=t.now??Date.now(),r=Ry({...t,now:n}),o=r.since==null?T$:dq(r.since,r.until),s=T=>(r.since==null||T>=r.since)&&T<r.until,a=r.since!=null?r.until-r.since:null,i=T=>a!=null&&T>=r.since-a&&T<r.since,c={},l={},u=S$(),d=0,p=0,f=0,w=0,m=0,g=0,y=new Set,x=new Map,b=[],R=[],_=[],C=null;for(let T of e||[]){let L=(await K(T)).filter(S=>S.type==="cost.recorded");if(!L.length){T.archivedAt||_.push(T.name||T.id);continue}let J=[];for(let S of L){let N=S.ts??0;s(N)?J.push(S):i(N)&&(g+=Vt(S).usd)}if(!J.length)continue;let A=Hr(J,{boxLabels:Yc(T)});d+=A.totalUsd,p+=A.turns,f+=A.repricedTurns||0,w+=A.asRecordedUsd||0,m+=A.unpricedTurns||0;for(let S of A.unpricedModels||[])y.add(S);A$(u,A.totalTokens);for(let[S,N]of Object.entries(A.byModel))c[S]||={usd:0,events:0,tokens:S$()},c[S].usd=xs(c[S].usd+N.usd),c[S].events+=N.events,A$(c[S].tokens,N.tokens);for(let[S,N]of Object.entries(A.byProvider))l[S]||={usd:0,events:0},l[S].usd=xs(l[S].usd+N.usd),l[S].events+=N.events;for(let S of J){let{usd:N}=Vt(S);if(!N)continue;let H=v$(S.ts??0,o),q=x.get(H)??{t:H,total:0,byProvider:{}};q.total+=N;let re=S.provider||"unknown";q.byProvider[re]=(q.byProvider[re]||0)+N,x.set(H,q),(C==null||H<C)&&(C=H)}b.push({id:T.id,name:T.name||T.id,archived:!!T.archivedAt,usd:A.totalUsd,turns:A.turns,providers:Object.keys(A.byProvider)});for(let[S,N]of Object.entries(A.byBox))R.push({trackId:T.id,trackName:T.name||T.id,boxId:S,...N})}let U=r.since!=null?v$(r.since,o):C,B=[];for(let T=U,$=0;T!=null&&T<r.until&&$<lq;T=pq(T,o),$++){let L=x.get(T);B.push(L?{t:T,total:xs(L.total),byProvider:fq(L.byProvider)}:{t:T,total:0,byProvider:{}})}return b.sort((T,$)=>$.usd-T.usd),R.sort((T,$)=>$.usd-T.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",pricing:Vs(),window:r.key,since:r.since,until:r.until,bucketMs:o,series:B,fleet:{totalUsd:xs(d),asRecordedUsd:xs(w),turns:p,repricedTurns:f,unpricedTurns:m,unpricedModels:[...y],totalTokens:u,byModel:c,byProvider:l,tracksWithCost:b.length,tracksSilentLive:_},prior:a!=null?{totalUsd:xs(g),since:r.since-a,until:r.since}:null,tracks:b.slice(0,50),boxes:R.slice(0,uq)}}rd();var mq=new Set(["cost.recorded","code.committed","code.rework","rework.cause.offered","rework.cause.answered"]),hq=20,wq=40;async function _$(e,t={}){let n=t.now??Date.now(),r=Ry({...t,now:n}),o=l=>(r.since==null||l>=r.since)&&l<r.until,s=[],a={},i=0;for(let l of e||[]){let u=await K(l),d=0,p=Yc(l);for(let f of u){if(!mq.has(f.type))continue;let w=f.type==="code.rework"?f.payload?.ts??f.ts:f.ts;f.type!=="rework.cause.answered"&&!o(w??0)||(f.type==="code.committed"&&d++,s.push(f.trackId?f:{...f,trackId:l.id}))}d&&i++;for(let f of l.boxes||[])a[`${l.id}/${f.name}`]={trackName:l.name||l.id,label:p[f.name]||f.name}}let c=IA(s,{boxMeta:a});return{generatedAt:new Date().toISOString(),window:r.key,since:r.since,until:r.until,reworkWindowDays:oo,decayEndDays:Th,basis:c.basis,commits:c.commits,tracksWithCommits:i,fixesAnalyzed:c.fixes.length,fixUsdTotal:c.fixUsdTotal,buckets:c.buckets,verdicts:c.verdicts,intents:c.intents,noCodeDelta:c.noCodeDelta,pendingTaps:c.pendingTaps.length,byProvider:c.byProvider,byModel:c.byModel,epochs:c.epochs.slice(0,hq),fixes:c.fixes.slice(0,wq)}}import gq from"node:fs";import I$ from"node:fs/promises";import Qc from"node:os";import yq from"node:path";yw();ct();var bq=1024*1024,Sp=e=>Math.round(e/bq);async function kq(e){try{let t=await I$.statfs(e),n=t.blocks*t.bsize,r=n-t.bavail*t.bsize;return{diskUsedMb:Sp(r),diskTotalMb:Sp(n)}}catch{return{diskUsedMb:null,diskTotalMb:null}}}async function xq(){try{return(await on()).filter(t=>t.isBostrat).length}catch{return null}}async function vq(){let e=0,t=!1;for(let n of["workspaces","worktrees"])try{let r=await I$.readdir(yq.join(jc,n),{withFileTypes:!0});e+=r.filter(o=>o.isDirectory()).length,t=!0}catch{}return t?e:null}async function $$({stateDir:e=jc,now:t=Date.now}={}){let n=Qc.totalmem(),[r,o,s,a]=await Promise.all([bd().catch(()=>null),kq(gq.existsSync(e)?e:Qc.tmpdir()),xq(),vq()]),i=Qc.cpus()?.length||null,c=Qc.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?Sp(n-r):null,memTotalMb:Sp(n),...o,boxes:s,worktrees:a,procUptimeS:Math.round(process.uptime()),osUptimeS:Math.round(Qc.uptime())}}Qh();fe();om();si();rr();fe();rr();var Sq=864e5;function Aq(e,{tolerance:t=.005}={}){if(e.type!=="cost.recorded"||e.source==="vendor")return null;let n=e.payload?.tokens,r=Number(e.payload?.usd)||0;if(!(n?(n.input||0)+(n.output||0)+(n.cacheRead||0)+(n.cacheWrite??n.cacheCreation??0):0)||!r)return null;let s=e.payload?.model||"unknown",a=e.payload?.speed||void 0,i={input:n.input||0,output:n.output||0,cacheRead:n.cacheRead||0,cacheWrite:n.cacheWrite??n.cacheCreation??0},c=On(s,i,e.ts,a?{speed:a}:void 0);if(!c)return null;let l=r-c,u=Math.abs(l)>Math.max(c*t,.001);return{model:s,speed:a??null,ts:e.ts,asRecorded:r,expected:c,delta:l,divergent:u}}async function R$(e,{days:t=14,tolerance:n=.005,now:r=Date.now()}={}){let o=r-t*Sq,s={},a=0,i=0,c=[];for(let u of e||[]){let d=await K(u);for(let p of d){if(!p.ts||p.ts<o)continue;let f=Aq(p,{tolerance:n});if(!f)continue;a++;let w=f.speed?`${f.model} (${f.speed})`:f.model,m=s[w]||={rows:0,divergent:0,asRecordedUsd:0,expectedUsd:0};m.rows++,m.asRecordedUsd+=f.asRecorded,m.expectedUsd+=f.expected,f.divergent&&(i++,m.divergent++,c.length<10&&c.push({track:u.name||u.id,...f}))}}let l=u=>Math.round(u*1e4)/1e4;for(let u of Object.values(s))u.asRecordedUsd=l(u.asRecordedUsd),u.expectedUsd=l(u.expectedUsd);return{sinceMs:o,days:t,tolerance:n,rows:a,divergent:i,byModel:s,examples:c,ok:i===0}}Yh();Hw();Iu();ft();Jt();import La from"node:fs/promises";import Tq from"node:fs";import wt from"node:path";import Eq from"node:os";import{execFile as _q}from"node:child_process";import{promisify as Iq}from"node:util";var $q=Iq(_q),O$=process.env.BOSTRAT_STATE_DIR||wt.join(process.env.HOME||Eq.tmpdir(),".bostrat"),Ap=!1,Oy=null;async function My(e,t){let n=await La.stat(e).catch(()=>null);if(!n?.isFile())return!1;let r=await La.stat(t).catch(()=>null);return r&&r.size===n.size&&r.mtimeMs>=n.mtimeMs?!1:(await La.mkdir(wt.dirname(t),{recursive:!0}),await La.copyFile(e,t),!0)}var Rq=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 Tp(e,t,{skip:n=null}={}){let r=0,o=await La.readdir(e,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(Rq.has(s.name)||n?.has(s.name))continue;let a=wt.join(e,s.name);s.isDirectory()?r+=await Tp(a,wt.join(t,s.name)):s.isFile()&&(r+=await My(a,wt.join(t,s.name))?1:0)}return r}async function M$({stateDir:e=O$,dest:t=process.env.BOSTRAT_SYNC_DIR||`${O$}-sync`,remote:n=process.env.BOSTRAT_STATE_REMOTE||null,tracks:r=null}={}){try{await La.mkdir(t,{recursive:!0});let o=0;o+=await My(wt.join(e,"tracks.json"),wt.join(t,"tracks.json"))?1:0,o+=await My(wt.join(e,"events.jsonl"),wt.join(t,"events.jsonl"))?1:0,o+=await Tp(wt.join(e,"events"),wt.join(t,"events")),o+=await Tp(wt.join(e,"memory"),wt.join(t,"memory"));let s=new Set(["mocks"]);for(let u of r||[])!u?.cwd||!u?.id||(o+=await Tp(wt.join(u.cwd,".bostrat"),wt.join(t,"workspaces",u.id,".bostrat"),{skip:s}));let a=(...u)=>$q("git",["-C",t,...u]);Tq.existsSync(wt.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 af(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||Ap))try{await a("push","-q",n,"HEAD:refs/heads/main"),l=!0,Ap&&console.log("[state-sync] push recovered \u2014 off-box copy is current again"),Ap=!1,Oy=null}catch(u){Ap=!0;let d=(u?.stderr||u?.message||String(u)).trim().split(`
743
+ `).slice(-3).join(" | ").slice(0,300);d!==Oy&&(Oy=d,console.warn(`[state-sync] PUSH FAILING (retrying each cycle; off-box copy is STALE): ${d}`))}return{staged:o,committed:i,pushed:l}}catch(o){return{staged:0,committed:!1,pushed:!1,error:o?.message||String(o)}}}Bw();cn();No();ct();Za();import{execFile as Oq}from"node:child_process";import{promisify as Mq}from"node:util";import{randomUUID as Cq}from"node:crypto";import Nq from"node:fs";import Pq from"node:os";import Dq from"node:path";var xo=Mq(Oq),Ep=e=>new Promise(t=>setTimeout(t,e)),vo=_f,Cy=process.env.BOSTRAT_USAGE_PROBE_CWD||Dq.join(Pq.homedir(),".bostrat","usage-probe"),Bq=Number(process.env.BOSTRAT_USAGE_IDLE_REAP_MS)||5*6e4,jq=Number(process.env.BOSTRAT_USAGE_PANEL_TIMEOUT_MS)||15e3,Lq=Number(process.env.BOSTRAT_USAGE_READY_TIMEOUT_MS)||45e3,C$=Number(process.env.BOSTRAT_USAGE_CACHE_MS)||2e4,ko=null,el=null,tl=null;async function Fq(){try{return await xo(ee,ne("has-session","-t",vo)),!0}catch{return!1}}function Uq(){ko&&clearTimeout(ko),ko=setTimeout(()=>Hq().catch(()=>{}),Bq),ko.unref&&ko.unref()}async function Hq(){ko&&(clearTimeout(ko),ko=null);try{await xo(ee,ne("kill-session","-t",vo))}catch{}}async function Wq(){let e=Date.now()+Lq;for(;;){let t=await Ny().catch(()=>"");if(/for agents|for shortcuts|bypass permissions on/i.test(t)){await Ep(500);return}if(Date.now()>e)throw new Error("usage probe didn't reach the prompt (trust/onboarding may be blocking)");await Ep(500)}}async function qq(){if(await Fq())return;if(!await Pr())throw new Error("host tmux server not running \u2014 start globo-tmux.service");Nq.mkdirSync(Cy,{recursive:!0}),await _r(Cy);let e=Cq();await xo(ee,ne("new-session","-d","-s",vo,"-c",Cy,"-x","200","-y","60",...mi()));let t=`${Ef} --session-id ${e}`;await xo(ee,ne("send-keys","-t",vo,t,"Enter")),await Wq()}async function Ny(){let{stdout:e}=await xo(ee,ne("capture-pane","-t",vo,"-p"));return e}async function Kq(){await qq(),await xo(ee,ne("send-keys","-t",vo,"-l","/usage")),await xo(ee,ne("send-keys","-t",vo,"Enter"));let e=Date.now()+jq,t="";for(;await Ep(400),t=await Ny(),!(/Current\s+(session|week)/i.test(t)||/\d+%\s*used/i.test(t)||Date.now()>e););return await Ep(900),t=await Ny(),await xo(ee,ne("send-keys","-t",vo,"Escape")).catch(()=>{}),Uq(),t}function Gq(e){let t=String(e||"").split(`
744
+ `).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 zq(e){let t=String(e||"").split(`
745
+ `).map(s=>s.replace(/\s+$/,"")),n=t.findIndex(s=>/What's contributing/i.test(s));if(n<0)return null;let r=/(Usage credits|Esc to cancel|d to day · w to week|^\s*d to day)/i,o=[];for(let s=n+1;s<t.length&&!r.test(t[s]);s++)t[s].trim()&&o.push(t[s].trim());return o.length?o:null}async function N$({fresh:e=!1}={}){return!e&&el&&Date.now()-el.at<C$?el.data:tl||(tl=(async()=>{try{let t=await Kq(),n=Gq(t),r={...n,contributors:zq(t),subscription:!!(n.session||n.week||n.weekModels),capturedAt:Date.now()};return el={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 el={at:Date.now()-(C$-3e3),data:n},n}finally{tl=null}})(),tl)}var Vq=262144;function Jq(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 Yq=new Set([300]),Xq=new Set([10080]);function Zq(e){let t=Number(e);return!Number.isFinite(t)||t<=0?null:Yq.has(t)?"session":Xq.has(t)?"week":"other"}function Qq(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 e5(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?Jq((o-n)/1e3):null,resetsAt:o}}var nl=e=>({session:null,week:null,other:null,planType:null,credits:null,limitReached:null,sawTokenCount:e});function t5(e,t=Date.now()){let n=String(e||"").split(`
746
+ `),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 nl(r);if(c.primary||c.secondary){let l=Date.parse(a.timestamp)||null,u=nl(r);[c.primary,c.secondary].forEach((f,w)=>{let m=e5(f,l,t);if(!m)return;let g=Zq(f.window_minutes);g===null&&(g=w===0?"session":"week"),g==="session"&&!u.session?u.session=m:g==="week"&&!u.week?u.week=m:(u.other??=[]).push({label:Qq(f.window_minutes),...m})}),u.planType=typeof c.plan_type=="string"?c.plan_type:null;let p=c.credits;return p&&(p.has_credits||p.unlimited)&&(u.credits={balance:String(p.balance??""),unlimited:!!p.unlimited}),u.limitReached=typeof c.rate_limit_reached_type=="string"&&c.rate_limit_reached_type||(c.spend_control_reached?"spend_control":null),u}if(c.primary_used_percent!=null||c.secondary_used_percent!=null){let l=u=>Number.isFinite(Number(u))?{pct:Math.round(Number(u)),resets:null,resetsAt:null}:null;return{...nl(r),session:l(c.primary_used_percent),week:l(c.secondary_used_percent)}}return nl(r)}return nl(r)}async function Py(e){let t={provider:"codex",supported:!0,contributors:null};try{let n=await Mo(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 Rt(n.file,Vq),o=t5(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 P$(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 _p({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 Py(i);if(c.subscription){a=c;break}(!a||a.error&&!c.error)&&(a=c)}r.push(a||await Py(null))}return n.has("cursor")&&r.push(await _p({agent:"cursor"})),{providers:r,capturedAt:Date.now()}}async function _p(e,{fresh:t=!1}={}){let n=e?.agent||"claude";return n==="codex"?Py(e):n==="cursor"?{provider:"cursor",supported:!1,subscription:!1,session:null,week:null,contributors:null,capturedAt:Date.now()}:{provider:"claude",supported:!0,...await N$({fresh:t})}}$r();ft();ft();function n5(e=process.env){return!!(Oe(e)&&e.BOSTRAT_PLANE_TOKEN)}var r5=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),Ip=(e,t)=>Object.assign(new Error(e),{status:t});async function D$(e,t){if(!n5(t))throw Ip("node is not plane-linked \u2014 Gmail unavailable",503);let n;try{n=await fetch(`${Oe(t)}${e}`,{headers:r5(t)})}catch(o){throw Ip(`plane unreachable \u2014 Gmail unavailable (${o?.message||o})`,503)}let r=await n.json().catch(()=>({}));if(!n.ok)throw Ip(r?.error||`plane replied ${n.status}`,n.status);return r}async function B$(e,{max:t=10,env:n=process.env}={}){let r=new URLSearchParams({q:e||""});return t&&r.set("max",String(t)),(await D$(`/v1/gmail/messages?${r.toString()}`,n)).messages||[]}async function j$(e,{env:t=process.env}={}){if(!e)throw Ip("message id required",400);return(await D$(`/v1/gmail/messages/${encodeURIComponent(e)}`,t)).message}Wi();qu();function Dy(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 o5(e){let[t,n]=e.split("/"),r=Dy(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 L$(e){return(e||"").split(",").map(t=>t.trim()).filter(Boolean).map(o5).filter(Boolean)}function s5(e){let t=e.headers["fly-client-ip"];return typeof t=="string"&&t.trim()?t.trim():(e.socket&&e.socket.remoteAddress||"").replace(/^::ffff:/,"")}function F$(e){let t=L$(e),n=String(e||"").trim().toLowerCase()==="open";return{open:n,clientIp:s5,allowed(r){if(n)return!0;let o=Dy((r||"").replace(/^::ffff:/,""));return o==null?!1:t.some(s=>s(o))}}}function U$(e,t){let n=L$(e);return{active:n.length>0,allows(r){if(!n.length)return!1;let o=(r.socket&&r.socket.remoteAddress||"").replace(/^::ffff:/,""),s=Dy(o);if(s==null||!n.some(i=>i(s)))return!1;let a=t(r);return!!(a&&a.view)}}}import H$ from"node:crypto";import $p from"node:fs";import a5 from"node:path";function W$(e=process.env,{stateDir:t=jc,log:n=console}={}){let r=String(e.BOSTRAT_NODE_API_TOKEN||"").trim();if(r)return r;let o=a5.join(t,"api-token");try{let a=$p.readFileSync(o,"utf8").trim();if(a)return a}catch{}let s=H$.randomBytes(32).toString("base64url");try{$p.mkdirSync(t,{recursive:!0}),$p.writeFileSync(o,s+`
747
+ `,{mode:384}),$p.chmodSync(o,384)}catch(a){n.error?.(`[bostrat-agent] could not persist the node API token: ${a?.message||a}`)}return s}function rl(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 q$(e,t){if(!e||!t)return!1;let n=Buffer.from(String(e)),r=Buffer.from(String(t));return n.length!==r.length?!1:H$.timingSafeEqual(n,r)}function K$(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 i5=[/^\/api\/github\/token\b/,/^\/api\/gmail\b/,/^\/api\/tracks\/adopt\b/,/^\/api\/tracks\/[^/]+\/transfer-out\b/,/^\/api\/node\/self-update\b/,/^\/api\/changelog\/(publish|retract)\b/,/^\/api\/tracks\/[^/]+\/loop-(update|delete)-offer\b/],c5=e=>i5.some(t=>t.test(e));function G$({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=K$(o);return q$(c,e)?a():c5(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||rl(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 z$(e,t,{enforce:n=!0}={}){return!n||q$(K$(e),t)?!0:rl(e)}En();gd();gd();import l5 from"node:http";import u5 from"node:net";function Rp(e){if(!e)return null;let t=String(e).replace(/:\d+$/,"").toLowerCase();if(/^[\d.]+$/.test(t)||t.includes(":"))return null;let n=t.split(".");if(n.length<3)return null;let r=n[0];return/^[a-z0-9-]+$/.test(r)?r:null}function Op(e){let t=Rp(e.headers.host);return t?{slug:t,view:pw(t)}:null}var d5=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;"),p5=e=>{let t=d5(e.name);return`<!doctype html><meta charset="utf-8">
744
748
  <meta http-equiv="refresh" content="3">
745
749
  <title>${t} \u2014 starting</title>
746
750
  <body style="font-family:system-ui;background:#0b0e14;color:#dce3f0;display:grid;place-items:center;height:100vh;margin:0">
747
751
  <div style="text-align:center"><p style="font-size:2rem;margin:0">\u23F3</p>
748
- <p><b>${t}</b> is waking up\u2026</p><p style="opacity:.6">auto-refreshing</p></div>`};function C$(e){if(!/[?&]token=/.test(e))return e;try{let t=new URL(e,"http://view");return t.searchParams.delete("token"),t.pathname+t.search}catch{return e}}function N$(e,t,n){let r=hp(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(GW(o));if(o.state!=="live"&&o.state!=="unhealthy")return t.statusCode=404,t.setHeader("content-type","text/plain"),t.end(`bostrat: view "${s}" is ${o.state} \u2014 restart it from the Views tab`);let a={...e.headers,host:`127.0.0.1:${o.port}`,"x-forwarded-host":e.headers.host,"x-forwarded-proto":e.headers["x-forwarded-proto"]||"http"};delete a.authorization,delete a.cookie,delete a["x-bostrat-token"];let i=qW.request({host:"127.0.0.1",port:o.port,method:e.method,path:C$(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 P$(e,t,n){let r=hp(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
752
+ <p><b>${t}</b> is waking up\u2026</p><p style="opacity:.6">auto-refreshing</p></div>`};function V$(e){if(!/[?&]token=/.test(e))return e;try{let t=new URL(e,"http://view");return t.searchParams.delete("token"),t.pathname+t.search}catch{return e}}function J$(e,t,n){let r=Op(e);if(!r)return n();let{view:o,slug:s}=r;if(!o)return t.statusCode=404,t.setHeader("content-type","text/plain"),t.end(`bostrat: no view named "${s}"`);if(o.state==="starting")return t.statusCode=503,t.setHeader("content-type","text/html"),t.end(p5(o));if(o.state!=="live"&&o.state!=="unhealthy")return t.statusCode=404,t.setHeader("content-type","text/plain"),t.end(`bostrat: view "${s}" is ${o.state} \u2014 restart it from the Views tab`);let a={...e.headers,host:`127.0.0.1:${o.port}`,"x-forwarded-host":e.headers.host,"x-forwarded-proto":e.headers["x-forwarded-proto"]||"http"};delete a.authorization,delete a.cookie,delete a["x-bostrat-token"];let i=l5.request({host:"127.0.0.1",port:o.port,method:e.method,path:V$(e.url),headers:a},c=>{t.writeHead(c.statusCode||502,c.headers),c.pipe(t)});i.on("error",()=>{t.headersSent?t.destroy():(t.statusCode=502,t.setHeader("content-type","text/plain"),t.end(`bostrat: view "${s}" did not answer on :${o.port}`))}),e.pipe(i),e.on("aborted",()=>i.destroy())}function Y$(e,t,n){let r=Op(e);if(!r)return!1;let{view:o,slug:s}=r;if(!o||o.state!=="live"&&o.state!=="unhealthy")return t.write(`HTTP/1.1 404 Not Found\r
749
753
  \r
750
754
  bostrat: no live view "${s}"\r
751
- `),t.destroy(),!0;let a=WW.connect(o.port,"127.0.0.1",()=>{let c=[`${e.method} ${C$(e.url)} HTTP/1.1`];for(let[l,u]of Object.entries(e.headers))l!=="host"&&(l==="authorization"||l==="cookie"||l==="x-bostrat-token"||c.push(`${l}: ${Array.isArray(u)?u.join(", "):u}`));c.push(`host: 127.0.0.1:${o.port}`),a.write(c.join(`\r
755
+ `),t.destroy(),!0;let a=u5.connect(o.port,"127.0.0.1",()=>{let c=[`${e.method} ${V$(e.url)} HTTP/1.1`];for(let[l,u]of Object.entries(e.headers))l!=="host"&&(l==="authorization"||l==="cookie"||l==="x-bostrat-token"||c.push(`${l}: ${Array.isArray(u)?u.join(", "):u}`));c.push(`host: 127.0.0.1:${o.port}`),a.write(c.join(`\r
752
756
  `)+`\r
753
757
  \r
754
- `),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 D$(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}.${zW(n.host)}/`}function zW(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 mp(t)&&Yh(n[0])?n.slice(1).join("."):t}da();lw();yd();xh();de();import B$ from"node:os";import{randomUUID as vy}from"node:crypto";var VW=(e=process.env)=>({nodeId:e.BOSTRAT_NODE_ID||B$.hostname(),nodeName:e.BOSTRAT_NODE_NAME||B$.hostname()});var j$=32768,L$=120,F$=1e3,U$=new Set(["claude","codex","cursor"]),JW=new Set(["off","transition","nag"]),YW=[[0,59],[0,23],[1,31],[1,12],[0,6]];function XW(e){let t=String(e??"").trim().split(/\s+/);return t.length!==5?!1:t.every((n,r)=>{let[o,s]=YW[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(),us={name(e){let t=bn(e);if(!t)throw new Error("a loop needs a name");if(t.length>L$)throw new Error(`name is too long (${t.length}); cap is ${L$}`);return t},schedule(e){let t=bn(e);if(!t)throw new Error('a loop needs a schedule (5-field UTC crontab, e.g. "0 7 * * *")');if(!XW(t))throw new Error(`invalid cron schedule: "${t}" \u2014 5 UTC fields, e.g. "0 7 * * *"`);return t},prompt(e){let t=bn(e);if(!t)throw new Error("a loop needs a prompt \u2014 it is what the run does");if(t.length>j$)throw new Error(`prompt is too long (${t.length} chars); cap is ${j$}`);return t},expectation(e){let t=bn(e)||null;if(t&&t.length>F$)throw new Error(`expectation is too long (${t.length}); cap is ${F$}`);return t},notify(e){let t=bn(e)||"off";if(!JW.has(t))throw new Error(`notify must be one of off | transition | nag, got "${e}"`);return t},assignment(e){let t=e??null,n=bn(typeof t=="string"?t:t?.provider)||"claude";if(!U$.has(n))throw new Error(`unknown provider "${n}" \u2014 one of ${[...U$].join(", ")}`);let r=typeof t=="object"&&t&&bn(t.model)||null;return r?{provider:n,model:r}:{provider:n}},enabled(e){if(typeof e=="boolean")return e;if(e==="true"||e==="false")return e==="true";throw new Error(`enabled must be true or false, got "${e}"`)}};function ZW(e,t){let n=e&&typeof e=="object"?e:{},r=us.name(n.name),o=us.schedule(n.schedule),s=us.prompt(n.prompt),a=us.expectation(n.expectation),i=us.notify(n.notify),c=us.assignment(n.assignment),l=bn(t?.workspace?.repo)||bn(t?.workspace?.base)||null;if(!l)throw new Error("this Track isn't based on a repo, so there's nothing for a loop to run in \u2014 propose from a repo-backed Track");let{nodeId:u,nodeName:d}=VW();return{name:r,schedule:o,prompt:s,expectation:a,notify:i,assignment:c,repo:l,nodeId:u||null,nodeName:d||null}}async function q$(e,t){let n=ZW(t,e),r=vy();return await M({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 W$(e,t,n,{loopId:r=null,nextFireAt:o=null}={}){if(!t)throw new Error("proposalId required");let s=await K({id:e.id,cwd:e.cwd}),a=s.find(c=>c.type==="loop.create.offered"&&c.payload?.proposalId===t);if(!a)throw new Error("unknown proposal");if(s.some(c=>c.type==="loop.create.answered"&&c.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await M({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 M({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 M({id:e.id,cwd:e.cwd},{type:"loop.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",loopId:String(r)}}),{proposalId:t,action:"created",loopId:String(r)}}var xy=["name","schedule","prompt","expectation","notify","assignment","enabled"],QW=(e,t)=>(e?.provider??"claude")===(t?.provider??"claude")&&(e?.model??null)===(t?.model??null);function K$(e){let t=Array.isArray(e.runs)?e.runs:[],n=t[t.length-1]??null;return{definitionUpdatedAt:Number(e.definitionUpdatedAt??e.updatedAt)||null,name:e.name??"",schedule:e.schedule??"",prompt:e.prompt??"",expectation:e.expectation??null,notify:e.notify??"off",assignment:e.assignment&&typeof e.assignment=="object"?e.assignment:{provider:String(e.assignment||"claude")},enabled:e.enabled!==!1,repo:e.repo??null,nodeId:e.nodeId??null,nodeName:e.nodeName??null,trackId:e.trackId??null,nextFireAt:Number.isFinite(Number(e.nextFireAt))?Number(e.nextFireAt):null,createdAt:Number(e.createdAt)||null,runCount:t.length,lastRun:n?{firedAt:Number(n.firedAt)||null,outcome:n.outcome??(n.error?"errored":null)}:null}}function G$(e,t){let n=bn(t);if(!n)throw new Error("which loop? give an id or a name \u2014 see `bostrat-loop ls`");let r=e.find(a=>a.id===n)||e.find(a=>a.name===n);if(r)return r;let o=n.toLowerCase(),s=e.filter(a=>String(a.id).toLowerCase().startsWith(o)||String(a.name).toLowerCase().startsWith(o));if(s.length===1)return s[0];throw s.length>1?new Error(`"${n}" matches ${s.length} loops: ${s.map(a=>`${a.name} (${a.id})`).join(", ")} \u2014 use the id`):new Error(`no loop matching "${n}" \u2014 use \`bostrat-loop ls\``)}function e5(e,t){let n=e&&typeof e=="object"&&!Array.isArray(e)?e:null;if(!n)throw new Error("a patch must be a JSON object of the fields to change");let r=Object.keys(n).filter(a=>!xy.includes(a));if(r.length){let a=r.filter(i=>["repo","nodeId","cwd","userId","owner","id","trackId"].includes(i));throw a.length?new Error(`a proposal can't change ${a.join(", ")} \u2014 retargeting a loop is a Loops-tab edit (scope D5)`):new Error(`unknown field(s) ${r.join(", ")} \u2014 patchable: ${xy.join(", ")}`)}let o={};for(let a of xy){if(!(a in n))continue;let i=us[a](n[a]);(a==="assignment"?QW(i,t.assignment):i===(t[a]??(a==="notify"?"off":a==="enabled"?!0:null)))||(o[a]=i)}let s=Object.keys(o);if(!s.length)throw new Error("nothing would change \u2014 the patch equals the loop's current definition");return{patch:o,changed:s}}async function z$(e,t,n){let r=K$(t),{patch:o,changed:s}=e5(n,r),a=vy(),i={ts:Date.now(),proposalId:a,loopId:String(t.id),name:r.name,base:r,patch:o,changed:s,selfEdit:!!(r.trackId&&r.trackId===e.id)};return await M({id:e.id,cwd:e.cwd},{type:"loop.update.offered",actor:"system",source:"orchestrator",payload:i}),i}var H$=600;async function V$(e,t,n){let r=bn(n);if(!r)throw new Error('a delete proposal needs a reason \u2014 bostrat-loop propose-delete <loop> --reason "<why this loop should go>"');if(r.length>H$)throw new Error(`reason is too long (${r.length}); cap is ${H$}`);let o=K$(t),s=vy(),a={ts:Date.now(),proposalId:s,loopId:String(t.id),name:o.name,base:o,reason:r,selfEdit:!!(o.trackId&&o.trackId===e.id)};return await M({id:e.id,cwd:e.cwd},{type:"loop.delete.offered",actor:"system",source:"orchestrator",payload:a}),a}var J$=async(e,t,n)=>{if(!n)throw new Error("proposalId required");let r=await K({id:e.id,cwd:e.cwd}),o=r.find(a=>a.type===t&&a.payload?.proposalId===n);if(!o)throw new Error("unknown proposal");let s=t.replace(".offered",".answered");if(r.some(a=>a.type===s&&a.payload?.proposalId===n))throw new Error("proposal already answered");return o};async function Y$(e,t,n,{nextFireAt:r=null}={}){if(!["applied","dismiss","moved"].includes(n))throw new Error("action must be one of applied | dismiss | moved");let s=(await J$(e,"loop.update.offered",t)).payload,a={id:e.id,cwd:e.cwd};return n==="applied"&&await M(a,{type:"loop.updated",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,loopId:s.loopId,name:s.patch?.name??s.name,changed:s.changed??Object.keys(s.patch||{}),nextFireAt:Number.isFinite(Number(r))?Number(r):null}}),await M(a,{type:"loop.update.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:n,loopId:s.loopId}}),{proposalId:t,action:n,loopId:s.loopId}}async function X$(e,t,n){if(!["delete","pause","keep","moved"].includes(n))throw new Error("action must be one of delete | pause | keep | moved");let o=(await J$(e,"loop.delete.offered",t)).payload,s={id:e.id,cwd:e.cwd};return(n==="delete"||n==="pause")&&await M(s,{type:n==="delete"?"loop.deleted":"loop.paused",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,loopId:o.loopId,name:o.name,trackId:o.base?.trackId??null}}),await M(s,{type:"loop.delete.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:n,loopId:o.loopId}}),{proposalId:t,action:n,loopId:o.loopId}}de();import{randomUUID as t5}from"node:crypto";var Ay=20,n5=300,Sy=120,Z$=120,Q$=2e3,wp=new Set(["build","ops","debt","spike"]),eR=new Set(["active","done","abandoned"]),Ey=new Set(["circuit.create","circuit.update","circuit.delete"]),r5=new Set(["person.create","slot.create","slot.update","slot.delete","reservation.create","reservation.update","reservation.delete"]),el=new Set([...Ey,...r5]),o5=["name","description","status","type"],s5=["person","startDate","endDate","estUsd"],a5=["person","label","startDate","endDate"],i5=/^\d{4}-\d{2}-\d{2}$/,Lt=e=>String(e??"").trim(),_y=e=>typeof e=="string"&&e.startsWith("@"),rR=864e5;function oR(e){let t=Date.parse(`${e}T00:00:00Z`),n=new Date(t).getUTCDay();return new Date(t-(n+6)%7*rR).toISOString().slice(0,10)}function c5(e){return new Date(Date.parse(`${oR(e)}T00:00:00Z`)+6*rR).toISOString().slice(0,10)}var tR=(e,t)=>{let n=Lt(e);if(!i5.test(n))throw new Error(`${t} must be YYYY-MM-DD, got "${e??""}"`);if(!Number.isFinite(Date.parse(`${n}T00:00:00Z`)))throw new Error(`${t} "${n}" is not a real date`);return n};function l5(e,t){let n=tR(e,"startDate"),r=tR(t,"endDate");if(r<n)throw new Error(`endDate ${r} is before startDate ${n}`);let o=oR(n),s=c5(r);return{startDate:o,endDate:s,snapped:o!==n||s!==r}}var nR=e=>{if(e==null||e==="")return null;let t=Number(e);if(!Number.isFinite(t)||t<0)throw new Error(`estUsd must be a non-negative number, got "${e}"`);return t},yo=(e,t,n)=>{let r=Lt(e);if(r.length>t)throw new Error(`${n} is too long (${r.length}); cap is ${t}`);return r};function Ty(e,t){let n=Lt(t);if(!n)throw new Error("a circuit name or id is required");if(_y(n))return{ref:n,id:null,name:n.slice(1)};let r=e.find(i=>i.id===n);if(r)return r;let o=n.toLowerCase(),s=e.filter(i=>String(i.name).toLowerCase()===o);if(s.length===1)return s[0];if(s.length>1)throw new Error(`"${n}" names ${s.length} circuits \u2014 use an id (bostrat-circuit ls)`);let a=e.filter(i=>String(i.name).toLowerCase().includes(o)).slice(0,5);throw new Error(a.length?`no circuit named "${n}" \u2014 near matches: ${a.map(i=>`${i.name} (${i.id})`).join(", ")}`:`no circuit named "${n}" \u2014 propose a circuit.create op if it should exist (bostrat-circuit ls lists yours)`)}function u5(e,t){let n=Lt(t);if(!n)throw new Error('a person is required \u2014 "me", a person id, or a row label');if(n==="me"||_y(n))return{ref:n,id:null,label:n==="me"?"you":n.slice(1)};let r=e.find(a=>a.personId===n);if(r)return{...r,id:r.personId};let o=n.toLowerCase(),s=e.filter(a=>String(a.label).toLowerCase()===o);if(s.length===1)return{...s[0],id:s[0].personId};throw s.length>1?new Error(`"${n}" names ${s.length} roadmap rows \u2014 use a person id`):new Error(e.length?`no roadmap row for "${n}" \u2014 rows: ${e.map(a=>`${a.label} (${a.personId})`).join(", ")}, or propose a person.create op`:`no roadmap rows yet \u2014 use "me", or propose a person.create op for "${n}"`)}function d5(e,t,{allow:n=el}={}){let r=e&&typeof e=="object"&&!Array.isArray(e)?e:null;if(!r)throw new Error("a plan must be a JSON object with an `ops` array");let o=Array.isArray(r.ops)?r.ops:null;if(!o?.length)throw new Error("a plan needs at least one op in `ops`");if(o.length>Ay)throw new Error(`too many ops (${o.length}); cap is ${Ay} \u2014 propose one intent at a time`);let s=Array.isArray(t?.circuits)?t.circuits:[],a=Array.isArray(t?.people)?t.people:[],i=Array.isArray(t?.slots)?t.slots:[],c=Array.isArray(t?.reservations)?t.reservations:[],l={circuits:{},slots:{},reservations:{}},u={},d=new Set,p=!1,f=!1,w=b=>{b.id&&(l.circuits[b.id]={name:b.name,status:b.status,type:b.type??"build",updatedAt:b.updatedAt??null},u[b.id]=b.name)},m=b=>{b.id&&(u[b.id]=b.label)},g=(b,O)=>{let $=Lt(b);if(!$)return null;if(d.has($))throw new Error(`ref "${$}" is used by two ops \u2014 each ref names one thing`);return d.add($),u[`@${$}`]=O,$},y=o.map((b,O)=>{let $=b&&typeof b=="object"?b:{},C=Lt($.op),L=`op ${O+1}`;if(!el.has(C))throw new Error(`${L}: unknown op "${C}" \u2014 one of ${[...el].join(", ")}`);if(!n.has(C))throw new Error(`${L}: "${C}" isn't a circuit op \u2014 roadmap changes go through \`bostrat-roadmap propose\` (one card, either CLI)`);let q=A=>{throw new Error(`${L} (${C}): ${A}`)},I=A=>{let E=$.set&&typeof $.set=="object"&&!Array.isArray($.set)?$.set:null;E||q("needs a `set` object naming the fields to change");let N=Object.keys(E).filter(H=>!A.includes(H));return N.length&&q(`unknown field(s) ${N.join(", ")} \u2014 settable: ${A.join(", ")}`),Object.keys(E).length||q("`set` names no fields"),E},_=A=>{let{startDate:E,endDate:N,snapped:H}=l5(A.startDate,A.endDate);return H&&(p=!0),{startDate:E,endDate:N,snapped:H}},F=A=>{let E=u5(a,A);return Lt(A)==="me"&&(f=!0),m(E),{key:E.id??Lt(A),label:E.label}},V=(A,E,N,H,z)=>{let fe=Lt(A);fe||q(`needs a ${H} id`);let me=E.find(Se=>Se[N]===fe);return me||q(`no ${H} "${fe}" \u2014 see \`bostrat-roadmap ls\``),z[fe]={...me},me};switch(C){case"circuit.create":{let A=yo($.name,Z$,"name");A||q("a circuit needs a name");let E=Lt($.type)||"build";wp.has(E)||q(`bad type "${E}" (${[...wp].join(" | ")})`);let N=s.find(z=>String(z.name).toLowerCase()===A.toLowerCase());N&&q(`a circuit named "${N.name}" already exists (${N.id}) \u2014 update it instead of making a twin`);let H=g($.ref,A);return{op:C,...H?{ref:H}:{},name:A,description:yo($.description,Q$,"description"),type:E}}case"circuit.update":{let A=Ty(s,$.circuit);A.id||q("can't update a circuit created in the same plan \u2014 set its fields on the create op"),w(A);let E=I(o5),N={};if(E.name!==void 0){let H=yo(E.name,Z$,"name");H||q("name can't be blank"),H!==A.name&&(N.name=H)}return E.description!==void 0&&(N.description=yo(E.description,Q$,"description")),E.status!==void 0&&(eR.has(E.status)||q(`bad status "${E.status}" (${[...eR].join(" | ")})`),E.status!==A.status&&(N.status=E.status)),E.type!==void 0&&(wp.has(E.type)||q(`bad type "${E.type}" (${[...wp].join(" | ")})`),E.type!==(A.type??"build")&&(N.type=E.type)),Object.keys(N).length||q("nothing would change \u2014 the set equals the circuit's current values"),{op:C,circuit:A.id,name:A.name,set:N}}case"circuit.delete":{let A=Ty(s,$.circuit);A.id||q("can't delete a circuit created in the same plan"),w(A);let E=o.some((N,H)=>H<O&&Lt(N?.op)==="circuit.update"&&N?.set?.status&&N.set.status!=="active"&&Lt(N?.circuit)===Lt($.circuit));return A.status==="active"&&!E&&q(`\u201C${A.name}\u201D is active \u2014 an active circuit can't be deleted; propose a circuit.update to done/abandoned first (both can ride one card)`),{op:C,circuit:A.id,name:A.name,status:A.status}}case"person.create":{let A=yo($.label,Sy,"label");A||q("a person row needs a label");let E=a.find(H=>String(H.label).toLowerCase()===A.toLowerCase());E&&q(`a roadmap row labelled "${E.label}" already exists (${E.personId})`);let N=g($.ref,A);return{op:C,...N?{ref:N}:{},label:A}}case"slot.create":{let A=Ty(s,$.circuit);w(A);let E=F($.person),N=_($);return{op:C,circuit:A.id??A.ref,circuitName:A.name,person:E.key,personLabel:E.label,...N,estUsd:nR($.estUsd)}}case"slot.update":{let A=V($.slot,i,"slotId","slot",l.slots),E=I(s5),N={};if(E.person!==void 0){let z=F(E.person);N.person=z.key,N.personLabel=z.label}if(E.startDate!==void 0||E.endDate!==void 0){let z=_({startDate:E.startDate??A.startDate,endDate:E.endDate??A.endDate});z.startDate!==A.startDate&&(N.startDate=z.startDate),z.endDate!==A.endDate&&(N.endDate=z.endDate)}E.estUsd!==void 0&&(N.estUsd=nR(E.estUsd)),Object.keys(N).length||q("nothing would change");let H=s.find(z=>z.id===A.circuitId);return{op:C,slot:A.slotId,circuitName:H?.name??null,set:N}}case"slot.delete":{let A=V($.slot,i,"slotId","slot",l.slots),E=s.find(N=>N.id===A.circuitId);return{op:C,slot:A.slotId,circuitName:E?.name??null,startDate:A.startDate,endDate:A.endDate}}case"reservation.create":{let A=F($.person),E=yo($.label,Sy,"label");return E||q("a reservation needs a label (Leave, Support rotation, \u2026)"),{op:C,person:A.key,personLabel:A.label,label:E,..._($)}}case"reservation.update":{let A=V($.reservation,c,"reservationId","reservation",l.reservations),E=I(a5),N={};if(E.person!==void 0){let H=F(E.person);N.person=H.key,N.personLabel=H.label}if(E.label!==void 0){let H=yo(E.label,Sy,"label");H||q("label can't be blank"),H!==A.label&&(N.label=H)}if(E.startDate!==void 0||E.endDate!==void 0){let H=_({startDate:E.startDate??A.startDate,endDate:E.endDate??A.endDate});H.startDate!==A.startDate&&(N.startDate=H.startDate),H.endDate!==A.endDate&&(N.endDate=H.endDate)}return Object.keys(N).length||q("nothing would change"),{op:C,reservation:A.reservationId,label:A.label,set:N}}case"reservation.delete":{let A=V($.reservation,c,"reservationId","reservation",l.reservations);return{op:C,reservation:A.reservationId,label:A.label,startDate:A.startDate,endDate:A.endDate}}default:return q("unhandled op")}});y.forEach((b,O)=>{for(let $ of[b.circuit,b.person,b.set?.person])if(_y($)&&!d.has(String($).slice(1)))throw new Error(`op ${O+1} (${b.op}): unknown ref "${$}" \u2014 no earlier op in this plan creates it`)});let x=a.some(b=>b.kind==="user"&&b.userId);return{why:yo(r.why,n5,"why"),ops:y,base:l,resolved:u,snapped:p,createsMeRow:f&&!x}}async function sR(e,t,n,r={}){let o=d5(t,n,r),s=t5(),a={ts:Date.now(),proposalId:s,...o};return await M({id:e.id,cwd:e.cwd},{type:"planning.change.offered",actor:"system",source:"orchestrator",payload:a}),a}var p5=async(e,t)=>{if(!t)throw new Error("proposalId required");let n=await K({id:e.id,cwd:e.cwd}),r=n.find(o=>o.type==="planning.change.offered"&&o.payload?.proposalId===t);if(!r)throw new Error("unknown proposal");if(n.some(o=>o.type==="planning.change.answered"&&o.payload?.proposalId===t))throw new Error("proposal already answered");return r};async function aR(e,t,n,{results:r=[]}={}){if(!["applied","dismiss","moved"].includes(n))throw new Error("action must be one of applied | dismiss | moved");let o=await p5(e,t),s={id:e.id,cwd:e.cwd},a=o.payload;return n==="applied"&&await M(s,{type:"planning.changed",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,why:a.why??"",results:Array.isArray(r)?r.slice(0,Ay+1):[]}}),await M(s,{type:"planning.change.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:n,ops:a.ops?.length??0}}),{proposalId:t,action:n}}od();de();Ir();de();Rn();yd();var iR=10,cR=200,f5=120,m5=24,uR=/^\d{4}-\d{2}-\d{2}$/;function Iy(e=process.env){return(e.CHANGELOG_REPOS||"globocodes/bostrat").split(",").map(t=>t.trim()).filter(Boolean)}var h5=(e=Date.now())=>new Date(e).toISOString().slice(0,10),wt=(e,t="i")=>new RegExp(e,t),w5=[{re:wt("^(business|docs|chore|ci|refactor|test|security|sec)(\\([^)]*\\))?!?:"),reason:"non-product PR prefix"},{re:wt("\\bSPC\\b",""),reason:"business (SPC)"},{re:wt("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),reason:"business"},{re:wt("competitor|cloudcli|\\bkiro\\b"),reason:"competitor research"},{re:wt("\\bReplicas\\b",""),reason:"competitor research"},{re:wt("tenanc|tenant|perimeter|ip[- ]gate|access[- ]code|vulnerab|\\bCVE\\b|audit|hardening|security|\\bsweep\\b"),reason:"security / tenancy"},{re:wt("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),reason:"internal codename"},{re:wt("^track/(business|security|spc|sec)-"),reason:"non-product branch"}],g5=[wt("\\bSPC\\b",""),wt("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),wt("competitor|cloudcli|\\bkiro\\b"),wt("\\bReplicas\\b",""),wt("tenanc|\\btenants?\\b|cross-tenant|perimeter|ip[- ]gate|vulnerab|\\bCVE\\b|hardening|security register|audit finding"),wt("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),wt("(^|[^\\w&])#\\d+\\b"),wt("\\btrack/[\\w.-]+")];function y5({title:e="",headRef:t=""}={}){let n=String(e||""),r=String(t||"");for(let{re:o,reason:s}of w5)if(o.test(n)||o.test(r))return s;return null}function lR(e){let t=String(e||"");for(let n of g5){let r=n.exec(t);if(r)return r[0].trim()}return null}function dR(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 b5=/^\*\*([^*]+?)\*\*\s*[:.]?\s*[—–-]?\s*(.*)$/;function k5(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=dc(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(`
755
- `)){let s=o.trim();if(!s)continue;if(s.startsWith("#")){n==null&&(n=s.replace(/^#+\s*/,"").trim().slice(0,f5)||null);continue}let a=/^[-*]\s+(.*)$/.exec(s);if(!a)continue;let i=a[1].trim(),c=null,l=new RegExp(`^\\[([^\\]]{1,${m5}})\\]\\s+(.*)$`).exec(i);if(l&&(c=l[1].trim(),i=l[2].trim()),!i)continue;let u=b5.exec(i);if(!u||!u[1].trim()||!u[2].trim())throw new Error(`bullet ${r.length+1} must be \`**Short summary** \u2014 the item, one sentence.\` (bold summary title, em dash, then the change) \u2014 got "${i.slice(0,80)}". Rewrite it and re-publish.`);i=`**${u[1].trim().replace(/[:.]\s*$/,"")}** \u2014 ${u[2].trim()}`;let d=lR(i);if(d)throw new Error(`bullet ${r.length+1} mentions "${d}" \u2014 the product changelog never carries business, security/tenancy or internal-ops items, PR numbers, branch names or codenames; drop the bullet or rewrite it as the user-visible change and re-publish.`);if(i.length>cR)throw new Error(`bullet ${r.length+1} is ${i.length} chars \u2014 over the ${cR}-char cap; a changelog bullet is one line`);r.push({text:i,...c?{area:c}:{}})}if(n){let o=lR(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>iR)throw new Error(`${r.length} bullets \u2014 over the ${iR}-bullet cap; group related changes into one line`);return{title:n||null,bullets:r}}async function x5(e,{repos:t=Iy()}={}){let n=new Set(t);return(await un()).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:y5({title:r.title,headRef:r.headRef})}))}async function pR(e,t){let n=await x5(e,t);return{prs:n.filter(r=>!r.excluded),excluded:n.filter(r=>r.excluded)}}async function fR(e,{md:t,day:n=null}){let r=k5(t),o=n==null||n===""?h5():String(n);if(!uR.test(o)||Number.isNaN(Date.parse(o)))throw new Error(`invalid day "${n}" \u2014 expected YYYY-MM-DD`);let s=await M({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 mR(e,{day:t}){let n=String(t||"");if(!uR.test(n)||Number.isNaN(Date.parse(n)))throw new Error(`invalid day "${t}" \u2014 expected YYYY-MM-DD`);let r=await M({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}}Uo();Rn();qo();de();Uo();pt();cr();Rn();Bi();Qu();ju();qi();Gt();import{execFile as C5}from"node:child_process";import{promisify as N5}from"node:util";var v5=new Set(["pull_request","check_suite","workflow_run","push"]),S5=/^[^/\s]+\/[^/\s]+$/,T5=500,$y=new Set,Ry=[],gp=new Map,Qt={hourStart:0,byEvent:{},duplicates:0,rejected:0};function Oy(e,t,n){let r=Math.floor(e/36e5)*36e5;r!==Qt.hourStart&&(Qt.hourStart=r,Qt.byEvent={},Qt.duplicates=0,Qt.rejected=0),t==="accepted"?Qt.byEvent[n]=(Qt.byEvent[n]||0)+1:Qt[t]+=1}function A5(e){if(!e||typeof e!="object"||e.forge!=="github"||typeof e.event!="string"||!v5.has(e.event)||typeof e.repo!="string"||!S5.test(e.repo))return null;let t=(Array.isArray(e.numbers)?e.numbers:[]).map(Number).filter(r=>Number.isInteger(r)&&r>0),n=Number.isInteger(e.number)&&e.number>0?e.number:t[0]??null;return{forge:"github",deliveryId:typeof e.deliveryId=="string"&&e.deliveryId?e.deliveryId.slice(0,128):null,event:e.event,action:typeof e.action=="string"?e.action.slice(0,64):null,repo:e.repo,number:n,numbers:n&&!t.includes(n)?[n,...t]:t,headSha:typeof e.headSha=="string"?e.headSha.slice(0,64):null,headRef:typeof e.headRef=="string"?e.headRef.slice(0,256):null,baseRef:typeof e.baseRef=="string"?e.baseRef.slice(0,256):null,merged:typeof e.merged=="boolean"?e.merged:null,draft:typeof e.draft=="boolean"?e.draft:null,conclusion:typeof e.conclusion=="string"?e.conclusion.slice(0,64):null,deleted:e.deleted===!0,senderLogin:typeof e.senderLogin=="string"?e.senderLogin.slice(0,128):null,ts:Number.isFinite(e.ts)?e.ts:null}}function hR(e,{now:t=Date.now(),onAccept:n=null,log:r=console}={}){let o=A5(e);if(!o)return Oy(t,"rejected"),{ok:!1,error:"malformed github event envelope"};if(o.deliveryId){if($y.has(o.deliveryId))return Oy(t,"duplicates"),{ok:!0,duplicate:!0,envelope:o};for($y.add(o.deliveryId),Ry.push(o.deliveryId);Ry.length>T5;)$y.delete(Ry.shift())}let s=o.repo.toLowerCase(),a=gp.get(s)||{lastDeliveryAt:0,count:0};a.lastDeliveryAt=t,a.count+=1,gp.set(s,a),Oy(t,"accepted",o.event),r.log?.(`[github-event] ${o.event}${o.action?` ${o.action}`:""} ${o.repo}${o.number?` #${o.number}`:o.headRef?` ${o.headRef}`:""}${o.conclusion?` (${o.conclusion})`:""}${o.deliveryId?` delivery ${o.deliveryId.slice(0,8)}`:""}`);try{n?.(o)}catch(i){r.error?.("[github-event] onAccept failed:",i?.message||i)}return{ok:!0,duplicate:!1,envelope:o}}function E5(e,t=Date.now()){let n=gp.get(String(e||"").toLowerCase());return n?{covered:!0,lastDeliveryAt:n.lastDeliveryAt,ageMs:t-n.lastDeliveryAt,count:n.count}:{covered:!1,lastDeliveryAt:null,ageMs:null,count:0}}var wR=1440*6e4;function My(e,t=Date.now()){let n=E5(e,t);return n.covered&&n.ageMs<wR}function gR(e=Date.now()){let t={};for(let[n,r]of gp)t[n]={lastDeliveryAt:r.lastDeliveryAt,count:r.count,covered:e-r.lastDeliveryAt<wR};return{hourStart:Qt.hourStart,byEvent:{...Qt.byEvent},duplicates:Qt.duplicates,rejected:Qt.rejected,repos:t}}de();Rn();Tr();cr();Gt();function yR(e){return(e?.checks?.failed??0)>0?"red":e?.mergeable==="CONFLICTING"?"conflict":e?.mergeStateStatus==="BEHIND"?"behind":null}function _5(e){return!(!e?.checks||e.checks.pending>0||e.mergeabilityPending||e.mergeable==="UNKNOWN"||e.mergeStateStatus==="UNKNOWN")}var I5=new Set(["merged","closed","lost"]);function $5(e,t){if(!e?.blocked)return null;let n=yR(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 R5(e,t){return e.autoMerge?!0:t==="ci-fixed"?!!(e.ciFix||e.ciFixAwait):t==="reconciled"?!!(e.reconcile||e.reconcileAwait):!1}async function O5(e,t,n,r,o){return(await K(e).catch(()=>[])).some(a=>{if(a.type!=="pr.state.changed"||a.payload?.number!==Number(n))return!1;let i=a.payload?.change;return i===t?a.payload?.sha&&r?a.payload.sha===r:(a.payload?.ts||0)>=o:i==="pushed"&&!!r&&a.payload?.sha===r})}async function M5(e,t,n){await M({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 yp(e,t={}){let{now:n=Date.now(),slugOf:r=_e,lookup:o=at,note:s=xS,tracks:a=async()=>(await we()).filter(d=>!De(d)),asked:i=O5,emitChange:c=M5}=t,l=[],u=null;for(let d of e??[]){if(!d?.prs?.length)continue;let p=await r(d.path).catch(()=>null);if(p)for(let f of d.prs)try{if(!_5(f))continue;let w=await o(p,f.number).catch(()=>null);if(!w?.trackId||I5.has(w.state))continue;let{prev:m}=await s(p,f.number,{blocked:yR(f),sha:f.headSha??null,at:n});if(!m)continue;let g=$5(m,f);if(!g||R5(w,g.change))continue;u??=new Map((await a()).map(O=>[O.id,O]));let y=u.get(w.trackId);if(!y)continue;let x=f.headSha??null;if(await i(y,g.change,f.number,x,m.at||0))continue;let b={number:Number(f.number),url:f.url||w.url,title:f.title||w.title,branch:f.headRefName||w.headRef,repo:p,sha:x,delegated:!1,reason:g.reason};g.change==="ci-fixed"?b.passed=f.checks.passed:b.base=f.baseRefName||null,await c(y,g.change,b),l.push({change:g.change,number:f.number,reason:g.reason})}catch{}}return l}var Py=N5(C5),AR=3e4,P5=30*6e4,D5=AR,B5=10*6e4,j5=10080*6e4,L5=60*6e4,F5=8,ER=1440*6e4,U5=3,_R="number,url,title,headRefName,headRefOid,state,mergedAt,closedAt",Ny=60*6e4,H5=15*6e4,q5=9e4,W5=1440*6e4,bp=new Map,kp=new Map,K5=/could not resolve|not found|no pull requests?/i,G5=e=>K5.test(String(e?.message||e||""));function z5(e,t){return[e.ciFix?.delegatedAt,e.reconcile?.delegatedAt,e.ciFixAwait?.since,e.reconcileAwait?.since].some(n=>n&&t-n<Ny)}var bR={fast:D5,slow:B5,decay:L5};function kR(e,t,n=My){return IR(e,t,{grace:0})||!n(e.repo,t)&&(e.armedAt&&t-e.armedAt<P5||z5(e,t))?"fast":t-(e.firstSeen||0)>j5?"decay":"slow"}function nl(e,t,n,r){let o=e.lanes?.get(ae(t.repo,t.number))||{};return Bu({change:n,repo:t.repo,number:Number(t.number),githubAt:r||null,lane:o.lane||null,intervalMs:o.intervalMs||null,source:"watch"})}async function V5(e,t){rr("watch");try{let{stdout:n}=await Py("gh",["pr","view",String(t),"--repo",e,"--json",_R],{timeout:3e4,maxBuffer:4194304,env:{...process.env,...await vn({slug:e})}});return JSON.parse(n||"null")}catch(n){throw Yr(n)&&Xr(n),n}}async function J5(e){rr("watch");try{let{stdout:t}=await Py("gh",["pr","list","--repo",e,"--state","all","--limit","100","--json",_R],{timeout:3e4,maxBuffer:8388608,env:{...process.env,...await vn({slug:e})}}),n=new Map;for(let r of JSON.parse(t||"[]"))n.set(Number(r.number),r);return n}catch(t){throw Yr(t)&&Xr(t),t}}async function Y5(){let e=new Map;for(let t of await we().catch(()=>[]))e.set(t.id,t);return e}async function X5(e,t){await M({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"merged",...t}}),await Zu(e,t).catch(()=>{})}async function Z5(e,t){let n=await Fo(e);return n?Qs(n,t):null}async function Q5(e,t,n){let r=await Fo(e);if(!r)throw new Error(`no local checkout for ${e}`);return ea(r,t,{method:n})}async function eK(e,t){let n=await Fo(e);if(!n)throw new Error(`no local checkout for ${e}`);return Fi(n,t)}async function tK(e,t){await M({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 Oa(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 nK=10*6e4;async function rK(e,t,n){let r=e.autoMerge?.armedAt||0;if(r&&(n.now??Date.now())-r>ER){await Oa(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 Oa(e,o,t,n,`check${o.checks.failed===1?"":"s"} failed: ${a}`);return}if(o.mergeable==="CONFLICTING"){await Oa(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<nK)return;await Oa(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 Oa(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 Oa(e,o,t,n,String(a?.message||a).trim()||"merge failed");return}await $R(e,{...o,state:"MERGED"},t,n,{change:"auto-merged",githubAt:o.checks.settledAt||null})}}async function Ma(e,t,n){await M({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 oK(e,t){try{return await Py("git",["-C",e.cwd,"cat-file","-e",`${t}^{commit}`],{timeout:1e4}),!0}catch{return!1}}async function tl(e,t,n,r=()=>!0){return(await K(e).catch(()=>[])).some(s=>s.type==="pr.state.changed"&&s.payload?.change===t&&s.payload?.number===Number(n)&&r(s))}var Ca=(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 IR(e,t,{grace:n=q5}={}){if(e.announced!==!1)return!1;let r=t-(e.firstSeen||0);return r>=n&&r<=W5}async function sK(e,t,n,r){let o=r.now??Date.now();if(!IR(e,o))return!1;let s=n.get(e.trackId)||null;if(!s||De(s))return!1;let a=(s.boxes||[]).find(d=>d.name===s.leadBox);return await(r.midTurn??Ho)(s.leadBox,a?.agent).catch(()=>!1)?!1:(await K(s).catch(()=>[])).some(d=>d.type==="pr.state.changed"&&d.payload?.number===Number(e.number))?(await(r.claim??tr)(e.repo,e.number).catch(()=>null),!1):await(r.claim??tr)(e.repo,e.number).catch(()=>null)?(await Ma(s,"opened",{...Ca(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 aK(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 $u(e.repo,e.number,{headSha:s}).catch(()=>{}),e.reconcile?.headSha&&s!==e.reconcile.headSha&&await Ou(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<H5;await kS(e.repo,e.number,s).catch(()=>{}),e.baseFoldAt&&await bS(e.repo,e.number).catch(()=>{}),!i&&!c&&!l&&a&&!await r.localHasCommit(a,s).catch(()=>!1)&&!await tl(a,"pushed",e.number,d=>d.payload?.sha===s)&&await Ma(a,"pushed",{...Ca(e,t),sha:s}).catch(()=>{})}if(e.ciFixAwait)if(o-(e.ciFixAwait.since||0)>Ny)await Ru(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 Ru(e.repo,e.number).catch(()=>{});else if(i.checks.total>0&&i.checks.pending===0){let c=nl(r,e,"ci-fixed",i.checks.settledAt||null),l=e.ciFixAwait.since||0;a&&!await tl(a,"ci-fixed",e.number,u=>(u.payload?.ts||0)>=l)&&await Ma(a,"ci-fixed",{...Ca(e,t),sha:s,delegated:!0,passed:i.checks.passed,githubAt:c.githubAt,latencyMs:c.latencyMs,lane:c.lane}).catch(()=>{}),await Ru(e.repo,e.number).catch(()=>{})}}}if(e.reconcileAwait)if(o-(e.reconcileAwait.since||0)>Ny)await Mu(e.repo,e.number).catch(()=>{});else{let i=await r.detail(e.repo,e.number).catch(()=>null);if(i){if(i.mergeable==="CONFLICTING")await Mu(e.repo,e.number).catch(()=>{});else if(i.mergeable==="MERGEABLE"){nl(r,e,"reconciled",null);let c=e.reconcileAwait.since||0;a&&!await tl(a,"reconciled",e.number,l=>(l.payload?.ts||0)>=c)&&await Ma(a,"reconciled",{...Ca(e,t),sha:s,delegated:!0,base:i.baseRefName||null}).catch(()=>{}),await Mu(e.repo,e.number).catch(()=>{})}}}}async function iK(e,t,n,r){let o=nl(r,e,"closed",Date.parse(t?.closedAt||"")||null),s=n.get(e.trackId);s&&!await tl(s,"closed",e.number)&&await Ma(s,"closed",{...Ca(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 cK(e,t,n){nl(n,e,"lost",null);let r=t.get(e.trackId);r&&!await tl(r,"lost",e.number)&&await Ma(r,"lost",Ca(e,null)).catch(()=>{}),await n.notifyIfResolved(e.repo,e.number,"lost").catch(()=>{}),await n.mark(e.repo,e.number,"lost").catch(()=>{})}async function $R(e,t,n,r,o={}){let s=nl(r,e,o.change||"merged",o.githubAt??(Date.parse(t.mergedAt||"")||null)),a=n.get(e.trackId);a&&((await K(a).catch(()=>[])).some(l=>l.type==="pr.state.changed"&&l.payload?.change==="merged"&&l.payload?.number===Number(e.number))||await r.emitMerged(a,{number:Number(e.number),url:t.url||e.url,title:t.title||e.title,branch:t.headRefName||e.headRef,repo:e.repo,githubAt:s.githubAt,latencyMs:s.latencyMs,lane:s.lane}).catch(()=>{})),await r.notifyIfArmed(e.repo,e.number).catch(()=>{}),await r.followupsIfMerged(e.repo,e.number).catch(()=>{}),await r.archiveIfArmed(e.repo,e.number).catch(()=>{}),await r.mark(e.repo,e.number,"merged").catch(()=>{})}async function xR(e={}){let{now:t=Date.now(),auth:n=Xm,view:r=V5,list:o=J5,links:s=TS,trackMap:a=Y5,emitMerged:i=X5,mark:c=Vr,archiveIfArmed:l=ar,notifyIfArmed:u=ir,notifyIfResolved:d=Cd,followupsIfMerged:p=Qo,batchThreshold:f=U5,detail:w=Z5,merge:m=Q5,updateBranch:g=eK,lookup:y=at,disarm:x=Di,emitDisarmed:b=tK,localHasCommit:O=oK,claim:$=tr,midTurn:C=Ho,only:L=null,wantDetail:q=null,covered:I=My,verdicts:_=null}=e;if(!(await n().catch(()=>null))?.authenticated||Pu()>0)return 0;let V=await s().catch(()=>[]),A=VS(V),E=J=>{try{return!!q?.(J)}catch{return!1}},N=L?V.filter(J=>{try{return L(J)}catch{return!1}}):V.filter(J=>t-(bp.get(ae(J.repo,J.number))||0)>=bR[kR(J,t,I)]);if(!N.length)return 0;let H=Date.now(),z=new Map,fe=new Map;for(let J of[...N].sort(Ui)){let ye=L?"event":kR(J,t,I);z.set(ae(J.repo,J.number),{lane:ye,intervalMs:bR[ye]??null}),bp.set(ae(J.repo,J.number),t),fe.has(J.repo)||fe.set(J.repo,[]),fe.get(J.repo).push(J)}let me=await a().catch(()=>new Map),Se=new Map,Ae=(J,ye)=>{let Ce=ae(J,ye);if(!Se.has(Ce)){let Ne=Promise.resolve().then(()=>w(J,ye));Ne.catch(()=>{}),Se.set(Ce,Ne)}return Se.get(Ce)},W=_??((J,ye)=>yp([{path:J,prs:[ye]}],{now:t,slugOf:async()=>J,tracks:async()=>[...me.values()].filter(Ce=>!De(Ce))}).catch(()=>{})),te={now:t,lanes:z,emitMerged:i,mark:c,archiveIfArmed:l,notifyIfArmed:u,notifyIfResolved:d,followupsIfMerged:p,detail:Ae,merge:m,updateBranch:g,lookup:y,disarm:x,emitDisarmed:b,localHasCommit:O,claim:$,midTurn:C};for(let[J,ye]of fe){let Ce,Ne=new Set,R=D=>D.ciFixAwait||D.reconcileAwait||E(D)?!0:!D.autoMerge||D.trackId&&A.get(D.trackId)!==ae(D.repo,D.number)?!1:t-(D.autoMerge.armedAt||0)<=ER;if(ye.length>f)Ce=await o(J).catch(()=>null);else{Ce=new Map;for(let D of ye){if(R(D)){let ue=await Ae(J,D.number).catch(()=>null);if(ue?.state){Ce.set(Number(D.number),{number:Number(D.number),url:ue.url,title:ue.title,headRefName:ue.headRefName,headRefOid:ue.headSha??null,state:ue.state,mergedAt:ue.mergedAt??null,closedAt:ue.closedAt??null});continue}}try{let ue=await r(J,D.number);ue?.number!=null&&Ce.set(Number(ue.number),ue)}catch(ue){G5(ue)&&Ne.add(ae(D.repo,D.number))}}}if(Ce)for(let D of ye){let ue=ae(D.repo,D.number),Le=Ce.get(Number(D.number));if(!Le){if(Ne.has(ue)){let Me=(kp.get(ue)||0)+1;kp.set(ue,Me),Me>=F5&&(await cK(D,me,te),kp.delete(ue),bp.delete(ue))}continue}if(kp.delete(ue),Le.state==="MERGED"||Le.state==="CLOSED")Le.state==="MERGED"?await $R(D,Le,me,te):await iK(D,Le,me,te),bp.delete(ue);else{await sK(D,Le,me,te).catch(()=>{}),await aK(D,Le,me,te).catch(()=>{});let Me=!D.trackId||A.get(D.trackId)===ue;D.autoMerge&&Me&&await rK(D,me,te).catch(()=>{});try{if(E(D)&&!Se.has(ue)&&Ae(D.repo,D.number),Se.has(ue)){let Ht=await Se.get(ue).catch(()=>null);Ht?.checks&&await W(D.repo,Ht)}}catch{}}}}let le={};for(let{lane:J}of z.values())le[J]=(le[J]||0)+1;return console.log(`[pr-watch] probed ${N.length} link(s) (${Object.entries(le).map(([J,ye])=>`${J} ${ye}`).join(", ")}) in ${Date.now()-H}ms`),N.length}function vR(e,t){return!e||!t?!1:e.all?!0:String(t.repo||"").toLowerCase()!==e.repo?!1:e.numbers?.length?e.numbers.includes(Number(t.number)):e.event==="push"?!!e.branch&&t.headRef===e.branch||!!t.autoMerge:e.branch?t.headRef===e.branch:!0}var Cy=!1,xp=!1,vp=[],SR=Promise.resolve();async function lK(){for(;xp||vp.length;){if(xp){xp=!1;try{await xR()}catch{}continue}let e=vp;vp=[];let t=e.map(r=>r.spec),n=Object.assign({},...e.map(r=>r.deps||{}));try{await xR({...n,only:r=>t.some(o=>vR(o,r)),wantDetail:r=>t.some(o=>o.detail&&vR(o,r))})}catch{}}}function Sp(e,t){return e===null?xp=!0:vp.push({spec:e,deps:t}),Cy||(Cy=!0,SR=lK().finally(()=>{Cy=!1})),SR}function RR(e,t=void 0){let n=String(e?.repo||"").toLowerCase();if(!/^[^/\s]+\/[^/\s]+$/.test(n))return Promise.resolve();let r=(Array.isArray(e.numbers)?e.numbers:[]).map(Number).filter(o=>Number.isInteger(o)&&o>0);return Sp({repo:n,numbers:r,branch:e.branch||null,event:e.event||null,detail:e.detail===!0},t)}var uK=6e4,TR=0;function OR(e=void 0){let t=e?.now??Date.now();return t-TR<uK?Promise.resolve():(TR=t,Sp({all:!0},e))}function MR(){Sp(null),setInterval(()=>Sp(null),AR)}Uo();ed();ic();cr();Gt();var dK=new Set(["opened","reopened","closed","synchronize","ready_for_review","converted_to_draft","edited"]);async function pK({tracks:e=we,reconcile:t=pd}={}){for(let n of(await e().catch(()=>[])).filter(r=>!De(r)))await t(n,{bypassThrottle:!0}).catch(()=>{})}function CR(e,t={}){let{invalidate:n=Vt,probe:r=RR,poke:o=OT,reconcileOpened:s=pK}=t;try{n()}catch{}let a={probe:null,poked:!1,reconciled:!1};if(!e?.repo)return a;if(e.event==="pull_request"&&dK.has(e.action)){if(e.action==="opened"||e.action==="reopened"){a.poked=!0,a.reconciled=!0;try{o()}catch{}s()}a.probe={repo:e.repo,numbers:e.numbers,branch:e.headRef||null,event:e.event}}else(e.event==="check_suite"||e.event==="workflow_run")&&e.action==="completed"?a.probe={repo:e.repo,numbers:e.numbers,branch:e.headRef||null,event:e.event,detail:!0}:e.event==="push"&&!e.deleted&&(a.probe={repo:e.repo,branch:e.headRef||null,event:"push"});return a.probe&&r(a.probe),a}ct();de();cr();Gt();import{randomUUID as fK}from"node:crypto";var mK=2e4,NR=3,Na=new Map,Dy=new Set;async function PR(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 hK(e={}){let{sessions:t=null,tracks:n=null,append:r=M,read:o=K,now:s=Date.now()}=e;if(process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1")return;let a,i;try{a=t??await nn(),i=n??await we()}catch{return}let c=new Map(a.map(u=>[u.name,u])),l=new Set;for(let u of i){if(De(u)||!u.leadBox)continue;let d=(u.boxes||[]).find(f=>f.name===u.leadBox);if(!d||d.agent!=="claude"||d.state!=="live")continue;let p=c.get(d.name);if(p)if(l.add(d.name),p.alternateOn){let f=(Na.get(d.name)||0)+1;Na.set(d.name,f),f===NR&&(Dy.add(d.name),await PR(u,d.name,o)||await r(u,{type:"box.fullscreen.detected",actor:"system",source:"orchestrator",boxId:d.name,provider:d.agent,payload:{ts:s,offerId:fK(),box:d.name,agent:d.agent}}).catch(()=>{}))}else{let f=(Na.get(d.name)||0)>=NR;if(Na.delete(d.name),f||!Dy.has(d.name)){Dy.add(d.name);let w=await PR(u,d.name,o);w&&await r(u,{type:"box.fullscreen.answered",actor:"system",source:"orchestrator",boxId:d.name,provider:d.agent,payload:{ts:s,offerId:w,action:"cleared"}}).catch(()=>{})}}}for(let u of[...Na.keys()])l.has(u)||Na.delete(u)}var rl=null,By=!1;function DR(){return rl?()=>{}:(rl=setInterval(()=>{By||(By=!0,hK().catch(()=>{}).finally(()=>{By=!1}))},mK),rl.unref?.(),()=>{clearInterval(rl),rl=null})}Do();ic();de();Uo();qo();Do();Vi();import{randomUUID as wK}from"node:crypto";async function gK(){let e=await Promise.resolve().then(()=>(cr(),C_));return{sayToLead:e.sayToLead,queueShipCompleteNotify:e.queueShipCompleteNotify}}var jy={listRepoPrs:On,readEvents:K,appendEvent:M,sayDeps:gK,currentBranch:Zr};async function yK(e,t=jy,{branch:n=null}={}){if(!e?.cwd)return null;let r=n||await(t.currentBranch??Zr)(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 Ly(e,t,{actions:n,notify:r=!1}={},o=jy){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 yK(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=wK();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 Fy(e,{offerId:t,choice:n}={},r=jy){if(!t)throw new Error("offerId required");if(!["push","new","dismiss"].includes(n))throw new Error('choice "push" | "new" | "dismiss" required');return eo(`prx:${e.id}:${t}`,()=>bK(e,{offerId:t,choice:n},r))}async function bK(e,{offerId:t,choice:n},r){let o=await r.readEvents(e),s=o.find(u=>u.type==="pr.exists.offered"&&u.payload?.offerId===t);if(!s)throw new Error("unknown offer");if(o.some(u=>u.type==="pr.exists.answered"&&u.payload?.offerId===t))throw new Error("offer already answered");let a=s.payload||{},i=Array.isArray(a.actions)&&a.actions.length?a.actions:["commit","push","pr"],c=null,l=null;if(n==="push"){let{sayToLead:u}=await r.sayDeps();l=Gr.filter(d=>d!=="pr"&&(i.includes(d)||d==="push")),c=await u(e.id,Js(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,cS(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}}Vi();import xr from"node:fs/promises";import Pa from"node:path";import qR from"node:os";import BR from"node:fs/promises";import Tp from"node:path";import{execFile as kK}from"node:child_process";import{promisify as xK}from"node:util";import{fileURLToPath as vK}from"node:url";var SK=xK(kK),LR=Tp.dirname(vK(import.meta.url)),TK=Tp.resolve(LR,"..","..","client","dist"),AK="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",EK=new Map([...AK].map((e,t)=>[e,t]));function _K(e){let t=[],n=0,r=0;for(let o of e){let s=EK.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 IK(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=_K(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 $K(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 jR=new Map;async function RK(e){let t;try{t=await BR.stat(e)}catch{return null}let n=jR.get(e);if(n&&n.mtimeMs===t.mtimeMs)return n;try{let r=JSON.parse(await BR.readFile(e,"utf8")),o={mtimeMs:t.mtimeMs,sources:r.sources||[],lines:IK(r.mappings||"")};return jR.set(e,o),o}catch{return null}}var Uy=null;function OK(){return Uy||(Uy=process.env.BOSTRAT_RELEASE?Promise.resolve(process.env.BOSTRAT_RELEASE):SK("git",["rev-parse","--short","HEAD"],{cwd:Tp.resolve(LR,"..","..")}).then(e=>e.stdout.trim()).catch(()=>null)),Uy}var MK=/(?:https?:\/\/[^\s()]*)?\/assets\/([^\s()/]+\.js):(\d+):(\d+)/g;async function CK(e,{distDir:t=TK}={}){let n=[],r=0,o=!1;for(let s of e.matchAll(MK)){let[a,i,c,l]=s,u=await RK(Tp.join(t,"assets",`${i}.map`)),d=u?$K(u.lines[Number(c)-1],Number(l)-1):null;if(n.push(e.slice(r,s.index)),d&&u.sources[d[1]]){let p=u.sources[d[1]].replace(/^(\.\.\/)+/,"");n.push(`${p}:${d[2]+1}:${d[3]+1}`),o=!0}else n.push(a);r=s.index+a.length}return n.push(e.slice(r)),{stack:n.join(""),symbolicated:o}}async function FR(e,t={}){try{if(!e?.error?.stack||!e.release||e.release==="unknown")return e;let n=t.release??await OK();if(!n||e.release!==n)return e;let{stack:r,symbolicated:o}=await CK(e.error.stack,t);o&&(e.error.stack=r,e.error.symbolicated=!0)}catch{}return e}var NK=()=>process.env.BOSTRAT_STATE_DIR||Pa.join(process.env.HOME||qR.tmpdir(),".bostrat"),bo=()=>Pa.join(NK(),"telemetry"),WR=()=>Pa.join(bo(),".relay-offsets.json"),PK=50,DK=14,BK=3e4,UR=500,Ft=(e,t)=>typeof e=="string"?e.slice(0,t):"";function jK(e,t){if(!e||typeof e!="object")return null;let n=Ft(e.name,64);if(!n)return null;let r=Number.isFinite(e.ts)?e.ts:t,o={name:n,ts:Math.abs(r-t)<168*3600*1e3?r:t,receivedAt:t,anonId:Ft(e.anonId,64),sessionId:Ft(e.sessionId,64),userId:Ft(e.userId,64),release:Ft(e.release,64),appVersion:Ft(e.appVersion,32),route:Ft(e.route,128),deviceClass:e.deviceClass==="phone"||e.deviceClass==="desktop"?e.deviceClass:""};return e.props&&typeof e.props=="object"&&!Array.isArray(e.props)&&(JSON.stringify(e.props).length<=8192?o.props=e.props:o.props={clamped:!0}),e.error&&typeof e.error=="object"&&(o.error={kind:Ft(e.error.kind,256),message:Ft(e.error.message,8192),stack:Ft(e.error.stack,32768),fingerprint:Ft(e.error.fingerprint,64)}),Array.isArray(e.breadcrumbs)&&(o.breadcrumbs=e.breadcrumbs.slice(-50).map(s=>({t:Number.isFinite(s?.t)?s.t:0,n:Ft(s?.n,64),r:Ft(s?.r,128)}))),o}var KR=e=>new Date(e).toISOString().slice(0,10),HR=0;async function GR(e,t=Date.now()){let r=(Array.isArray(e?.events)?e.events.slice(0,PK):[]).map(s=>jK(s,t)).filter(Boolean);if(!r.length)return 0;for(let s of r)s.error?.stack&&await FR(s);await xr.mkdir(bo(),{recursive:!0});let o=Pa.join(bo(),`${KR(t)}.ndjson`);return await xr.appendFile(o,r.map(s=>JSON.stringify(s)+`
756
- `).join(""),"utf8"),t-HR>6*3600*1e3&&(HR=t,LK(t).catch(()=>{})),r.length}async function LK(e=Date.now()){let t=KR(e-DK*24*3600*1e3),n=[];try{n=await xr.readdir(bo())}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 xr.rm(Pa.join(bo(),s),{force:!0});let o=await VR();for(let s of r)delete o[s];await JR(o)}var Ap=new Map;function zR(e,t=Date.now()){let n=e||"unknown",r=Ap.get(n);return r||(Ap.size>512&&Ap.clear(),r={tokens:40,at:t},Ap.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 VR(){try{return JSON.parse(await xr.readFile(WR(),"utf8"))||{}}catch{return{}}}async function JR(e){await xr.mkdir(bo(),{recursive:!0}),await xr.writeFile(WR(),JSON.stringify(e),"utf8")}function FK(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||qR.hostname(),level:r?"error":"info",message:r?`${e.error.kind||"Error"}: ${e.error.message||"(no message)"}`.slice(0,8192):e.name,tags:o,attributes:{...e.props?{props:e.props}:{},receivedAt:e.receivedAt}};return r&&(s.error={kind:e.error.kind,message:e.error.message,stack:e.error.stack},e.error.fingerprint&&(s.fingerprint=e.error.fingerprint),e.error.symbolicated&&(s.attributes.symbolicated=!0),e.breadcrumbs&&(s.attributes.breadcrumbs=e.breadcrumbs)),s}async function UK({fetchImpl:e=fetch}={}){let t=await wI();if(!t)return{sent:0,disabled:!0};let n;try{n=(await xr.readdir(bo())).filter(s=>s.endsWith(".ndjson")).sort()}catch{return{sent:0,disabled:!1}}let r=await VR(),o=0;for(let s of n){let a=Pa.join(bo(),s),i=r[s]||0,c;try{let p=await xr.open(a,"r");try{let f=(await p.stat()).size;if(f<=i)continue;c=Buffer.alloc(f-i),await p.read(c,0,c.length,i)}finally{await p.close()}}catch{continue}let l=c.lastIndexOf(10);if(l<0)continue;let u=c.toString("utf8",0,l+1).split(`
757
- `).filter(Boolean),d=[];for(let p of u)try{d.push(JSON.parse(p))}catch{}for(let p=0;p<d.length;p+=UR){let f=d.slice(p,p+UR).map(m=>FK(m)),w=await e(`${t.url.replace(/\/$/,"")}/v1/logs`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${t.ingestKey}`},body:JSON.stringify({events:f})}).catch(()=>null);if(!w||!w.ok)return{sent:o,disabled:!1};o+=f.length}r[s]=i+l+1,await JR(r)}return{sent:o,disabled:!1}}var Hy=null,qy=!1;function YR(){Hy||(Hy=setInterval(async()=>{if(!qy){qy=!0;try{await UK()}catch(e){console.error("[telemetry] relay failed:",e?.message||e)}finally{qy=!1}}},BK),Hy.unref?.())}import _p from"node:fs/promises";import tO from"node:path";import HK from"node:os";var nO=()=>process.env.BOSTRAT_STATE_DIR||tO.join(process.env.HOME||HK.tmpdir(),".bostrat"),rO=()=>tO.join(nO(),"dictation-glossary.json"),qK=100,WK=500,KK=["bostrat","globopi","codex","tmux","worktree","Deepgram","Linear","Firecracker","Tigris","WireGuard","misous","postyx","cedar","gerbil","Anthropic","Opus","Haiku","Sonnet","keyterm","monorepo","dogfood"],Ip=null,Wy=null,Ky=Promise.resolve();function XR(){let e={},t=Date.now();for(let n of KK)e[n.toLowerCase()]={term:n,count:1,lastUsed:t,source:"seed"};return e}async function oO(){return Ip||(Wy??=_p.readFile(rO(),"utf8").then(e=>JSON.parse(e)?.terms??XR()).catch(()=>XR()).then(e=>Ip=e).finally(()=>Wy=null),Wy)}async function ZR(){let e=JSON.stringify({terms:Ip},null,2),t=rO(),n=`${t}.${process.pid}.tmp`;await _p.mkdir(nO(),{recursive:!0}),await _p.writeFile(n,e),await _p.rename(n,t)}function GK(){return Ky=Ky.then(ZR,ZR),Ky.catch(()=>{})}async function Gy(){return Object.values(await oO()).sort((t,n)=>n.count-t.count||n.lastUsed-t.lastUsed)}var zK=e=>Math.max(1,Math.ceil(e.length/4));async function VK(){let e=[],t=0;for(let{term:n}of await Gy()){let r=zK(n);if(!(t+r>WK)&&(e.push(n),t+=r,e.length>=qK))break}return e}async function JK(e,t){let n=await oO(),r=e.toLowerCase(),o=n[r];n[r]={term:e,count:(o?.count??0)+1,lastUsed:Date.now(),source:o?.source??t}}var QR=e=>(e||"").split(/\s+/).map(t=>t.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"")).filter(Boolean),Ep=e=>e.toLowerCase();function eO(e){return!new RegExp("\\p{L}","u").test(e)||e.length<3?!1:/^[a-z]+$/.test(e)?e.length>=4:!0}async function sO(e,t){let n=QR(e),r=QR(t);if(!n.length||!r.length)return[];let o=n.length,s=r.length,a=Array.from({length:o+1},()=>new Array(s+1).fill(0));for(let u=o-1;u>=0;u--)for(let d=s-1;d>=0;d--)a[u][d]=Ep(n[u])===Ep(r[d])?a[u+1][d+1]+1:Math.max(a[u+1][d],a[u][d+1]);let i=new Set,c=0,l=0;for(;c<o&&l<s;)Ep(n[c])===Ep(r[l])?(c++,l++):a[c+1][l]>=a[c][l+1]?c++:(eO(r[l])&&i.add(r[l]),l++);for(;l<s;l++)eO(r[l])&&i.add(r[l]);if(!i.size)return[];for(let u of i)await JK(u,"learned");return await GK(),[...i]}var ol=null;function YK(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 aO(){if(!ol)return null;let e=await Lc();if(!e||e.apiKey.slice(-6)!==ol.keyTail)return null;let{keyTail:t,...n}=ol;return n}async function iO(e,t){let n=await Lc();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 VK())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=YK(o.status,i);c.persistent&&(ol={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 ol=null,{transcript:(await o.json())?.results?.channels?.[0]?.alternatives?.[0]?.transcript??""}}de();var zy={"gpt-realtime-2.1":{textIn:4,textInCached:.4,textOut:24,audioIn:32,audioInCached:.4,audioOut:64},"gpt-realtime-2":{textIn:4,textInCached:.4,textOut:24,audioIn:32,audioInCached:.4,audioOut:64},"gpt-realtime":{textIn:4,textInCached:.4,textOut:16,audioIn:32,audioInCached:.4,audioOut:64},"gpt-realtime-2.1-mini":{textIn:.6,textInCached:.06,textOut:2.4,audioIn:10,audioInCached:.3,audioOut:20},"gpt-realtime-mini":{textIn:.6,textInCached:.06,textOut:2.4,audioIn:10,audioInCached:.3,audioOut:20}};function XK(e){if(!e)return null;let t=String(e).trim();if(zy[t])return t;let n=null;for(let r of Object.keys(zy))t.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function ZK(e,t={}){let n=zy[XK(e)];if(!n)return 0;let r=0;for(let o of Object.keys(n))r+=(Number(t[o])||0)*n[o];return r/1e6}function QK(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 sl=null;async function e6(){if(!sl)return null;let e=await Qd();if(!e||e.apiKey.slice(-6)!==sl.keyTail)return null;let{keyTail:t,...n}=sl;return n}async function t6(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=QK(t.status,o);s.persistent&&(sl={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}sl=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 n6={openai:t6};async function cO(){let e=await Qd();return e?{configured:!0,provider:e.provider,model:e.model,voice:e.voice,problem:await e6()}:{configured:!1}}async function lO(){let e=await Qd();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 n6[e.provider](e);return{provider:e.provider,model:e.model,voice:e.voice,...t}}async function uO(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=ZK(t,s),i=await M(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}}Gt();var yO=Te.dirname(o6(import.meta.url)),dO=Number(process.env.PORT)||3362,Rp=Rg(process.env),bO=Number(process.env.BOSTRAT_AUTO_TRIGGER_PCT)||80,Da=A$(process.env.BOSTRAT_ALLOW_IPS),Zy=E$(process.env.BOSTRAT_VIEW_FRONT_CIDRS,hp),Qy=I$(),kO=process.env.BOSTRAT_ALLOW_LAN_TOKENLESS!=="1",S=Ut();S.disable("x-powered-by");S.use((e,t,n)=>{t.setHeader("x-content-type-options","nosniff"),mp(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(Qc(e)||Da.allowed(Da.clientIp(e))||Zy.allows(e))return n();t.status(403).type("text/plain").send("bostrat: access restricted to the allowlist")});S.use(N$);S.use(O$({token:Qy,enforce:kO}));S.use("/api/mocks",Ut.json({limit:"1mb"}));S.use("/api/mocks",Ut.raw({type:"image/png",limit:"24mb"}));S.use("/api/mocks",Ut.raw({type:["video/mp4","video/webm"],limit:"105mb"}));S.use("/api/runbooks",Ut.json({limit:"1mb"}));S.use("/api/tracks/adopt",Ut.json({limit:"1mb"}));S.use("/api/telemetry",Ut.json({limit:"256kb"}));S.use("/api/hook",Ut.json({limit:"2mb"}));S.use("/api/dictation",Ut.raw({type:["audio/*","video/mp4","application/octet-stream"],limit:"32mb"}));S.use("/api/tracks/:id/upload",Ut.raw({type:()=>!0,limit:"25mb"}));S.use(Ut.json({limit:"64kb"}));S.get("/api/health",async(e,t)=>{t.json({ok:!0,tmuxSocket:Rt,hostTmuxAlive:await Rr(),autoTriggerPct:bO,plane:Ba?Ba.status():null})});S.get("/api/sessions",async(e,t)=>{t.json({sessions:await nn()})});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 Or(n,r||void 0);t.json({ok:!0,...o})}catch(o){let s=o?.message||String(o),a=/already exists/i.test(s)?409:/must be|invalid/i.test(s)?400:500;t.status(a).json({error:s})}});S.delete("/api/sessions/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!je(n))return t.status(400).json({error:"invalid session name"});if(!await ke(n))return t.status(404).json({error:"session not found"});try{await rn(n),t.json({ok:!0})}catch(r){t.status(500).json({error:`failed to kill: ${r?.message||r}`})}});S.get("/api/context/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!je(n))return t.status(400).json({error:"invalid session name"});let r=await ke(n);if(!r)return t.status(404).json({error:"session not found"});let o=await di(r.cwd,r.sessionId);if(!o)return t.json({available:!1,cwd:r.cwd,sessionId:r.sessionId||null});t.json({available:!0,...o})});S.post("/api/handoff/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!je(n))return t.status(400).json({error:"invalid session name"});try{let r=await xx(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=cu(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 pO=10;async function xO(){let e=await we(),[t,n]=await Promise.all([F_(e),H_(e)]);return{tracks:e,views:await Jh(),queuedOf:r=>Xo(r),jobsOf:r=>t.get(r)??[],prPendingOf:r=>n.get(r)??[]}}S.get("/api/idle-guard",async(e,t)=>{try{t.json(Eg(await xO()))}catch{t.status(500).json({busy:!0,reasons:["error"]})}});var en=ts(),u6=nI({kind:en}),al=null,vt=()=>al&&["auto","prompt","off"].includes(al)?al:u6,Xy=null,d6=Bc.has(en),vO=async({to:e,from:t})=>!d6||Gd(await jc())?!1:(cl.arm({to:e,from:t,kind:en}),!0);async function p6(e){let t=vt();al=e??null;let n=vt();if(t!==n){if(console.log(`[self-update] policy ${t} \u2192 ${n} (${e?"plane row":"node default"})`),n!=="auto"){cl.cancel();return}Xy&&await vO(Xy)}}var SO=(()=>{try{return l6(import.meta.url)("../package.json").version||null}catch{return null}})(),cl=oI({isBusy:async()=>Eg(await xO()).busy,onStuck:({to:e,from:t})=>qn({current:t,latest:e,installKind:en,policy:vt(),status:"stuck"}).catch(()=>{}),onStarted:({to:e,from:t,result:n})=>(n?.ok?qn({current:t,latest:e,installKind:en,policy:vt(),status:"updating",reason:"auto"}):qn({current:t,latest:e,installKind:en,policy:vt(),status:"failed",error:n?.reason})).catch(()=>{})});S.get("/api/node/self-update",async(e,t)=>{t.json({installKind:en,policy:vt(),policySource:al?"plane":"node",current:SO,status:await jc(),armed:cl.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 zd({to:n,kind:en,reason:"manual"});if(r.ok)return cl.cancel(),qn({current:r.from,latest:n,installKind:en,policy:vt(),status:"updating",reason:"manual"}).catch(()=>{}),t.json({ok:!0,...r});t.status(409).json({ok:!1,error:r.reason,status:r.status??null})});async function TO(){try{let e=await rI();e&&await qn({current:e.from,latest:e.to,installKind:e.kind||en,policy:vt(),status:e.status,error:e.error,reason:e.reason}),await qw({current:SO,installKind:en,policy:vt()})}catch{}}TO();setInterval(TO,3e4).unref();S.get("/api/tracks",async(e,t)=>{let n=(await we()).filter(s=>!s.transferredTo),r=n.filter(s=>s.archivedAt&&!s.archiving),o=n;if(e.query.archived!=="all"&&r.length>pO){let s=new Set([...r].sort((a,i)=>(i.archivedAt||0)-(a.archivedAt||0)).slice(0,pO).map(a=>a.id));o=n.filter(a=>!a.archivedAt||a.archiving||s.has(a.id))}t.json({tracks:o,archivedTotal:r.length,agents:Ac,agentAvailability:await _d(),tickets:await RI()})});S.get("/api/cost",async(e,t)=>{try{let n=await we();e.query.track&&(n=n.filter(o=>o.id===e.query.track));let r=await dy(n);if(r.cursorUsage=Ch(),e.query.format==="text")return t.type("text/plain").send(t$(r));t.json(r)}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/usage/roundup",async(e,t)=>{try{let n=await fy(await we(),{window:e.query.window,from:e.query.from,to:e.query.to});if(e.query.format==="text")return t.type("text/plain").send(a$(n));t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/usage/spend",async(e,t)=>{try{let n=await d$(await we(),{window:e.query.window,from:e.query.from,to:e.query.to});n.cursorUsage=Ch(),n.subscriptionMonthlyUsd=Number(process.env.BOSTRAT_SUBSCRIPTION_MONTHLY_USD)||null,n.caps=Ci(),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/usage/caps",(e,t)=>{t.json(Ci())});S.post("/api/usage/caps",async(e,t)=>{try{t.json(await xu(e.body?.caps??{},{source:"local"}))}catch(n){t.status(400).json({error:n?.message||String(n)})}});S.get("/api/usage/limits",async(e,t)=>{try{let n=e.query.fresh==="1"||e.query.fresh==="true";t.json(await k$(await we(),{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 pb(e.get(Vn),{byToken:_c,legacy:()=>Xi(e.body?.session_id,e.body?.cwd)});if(n==="refused")return qa("refused",{reason:"unknown-token",hook:e.body?.hook_event_name}),t.json({ok:!1,error:"unknown hook token"});if(n==="legacy-denied")return qa("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&&qa("mismatch",{track:r.track.id,box:r.box.name}),qa(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 ZI(e.body||{},()=>r);e.body?.hook_event_name==="Stop"&&r?.box?.cwd&&_l(r.box.cwd),t.json({ok:!0,events:o.length})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});S.get("/api/git/trailers",async(e,t)=>{t.type("text/plain");try{let n=await _c(e.get(Vn));if(!n?.track||!n?.box)return t.status(204).end();t.send((await hT(n.track,n.box)).join(`
758
+ `),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 X$(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}.${f5(n.host)}/`}function f5(e){if(process.env.BOSTRAT_PUBLIC_HOST)return String(process.env.BOSTRAT_PUBLIC_HOST).replace(/:\d+$/,"");let t=String(e||"").replace(/:\d+$/,"").toLowerCase();if(!t||!t.includes(".")||/^[\d.]+$/.test(t))return"bostrat.globopi";let n=t.split(".");return Rp(t)&&pw(n[0])?n.slice(1).join("."):t}ka();Ew();Ad();Bh();fe();import Z$ from"node:os";import{randomUUID as jy}from"node:crypto";var m5=(e=process.env)=>({nodeId:e.BOSTRAT_NODE_ID||Z$.hostname(),nodeName:e.BOSTRAT_NODE_NAME||Z$.hostname()});var Q$=32768,eR=120,tR=1e3,nR=new Set(["claude","codex","cursor"]),h5=new Set(["off","transition","nag"]),w5=[[0,59],[0,23],[1,31],[1,12],[0,6]];function g5(e){let t=String(e??"").trim().split(/\s+/);return t.length!==5?!1:t.every((n,r)=>{let[o,s]=w5[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 xn=e=>String(e??"").trim(),vs={name(e){let t=xn(e);if(!t)throw new Error("a loop needs a name");if(t.length>eR)throw new Error(`name is too long (${t.length}); cap is ${eR}`);return t},schedule(e){let t=xn(e);if(!t)throw new Error('a loop needs a schedule (5-field UTC crontab, e.g. "0 7 * * *")');if(!g5(t))throw new Error(`invalid cron schedule: "${t}" \u2014 5 UTC fields, e.g. "0 7 * * *"`);return t},prompt(e){let t=xn(e);if(!t)throw new Error("a loop needs a prompt \u2014 it is what the run does");if(t.length>Q$)throw new Error(`prompt is too long (${t.length} chars); cap is ${Q$}`);return t},expectation(e){let t=xn(e)||null;if(t&&t.length>tR)throw new Error(`expectation is too long (${t.length}); cap is ${tR}`);return t},notify(e){let t=xn(e)||"off";if(!h5.has(t))throw new Error(`notify must be one of off | transition | nag, got "${e}"`);return t},assignment(e){let t=e??null,n=xn(typeof t=="string"?t:t?.provider)||"claude";if(!nR.has(n))throw new Error(`unknown provider "${n}" \u2014 one of ${[...nR].join(", ")}`);let r=typeof t=="object"&&t&&xn(t.model)||null;return r?{provider:n,model:r}:{provider:n}},enabled(e){if(typeof e=="boolean")return e;if(e==="true"||e==="false")return e==="true";throw new Error(`enabled must be true or false, got "${e}"`)}};function y5(e,t){let n=e&&typeof e=="object"?e:{},r=vs.name(n.name),o=vs.schedule(n.schedule),s=vs.prompt(n.prompt),a=vs.expectation(n.expectation),i=vs.notify(n.notify),c=vs.assignment(n.assignment),l=xn(t?.workspace?.repo)||xn(t?.workspace?.base)||null;if(!l)throw new Error("this Track isn't based on a repo, so there's nothing for a loop to run in \u2014 propose from a repo-backed Track");let{nodeId:u,nodeName:d}=m5();return{name:r,schedule:o,prompt:s,expectation:a,notify:i,assignment:c,repo:l,nodeId:u||null,nodeName:d||null}}async function oR(e,t){let n=y5(t,e),r=jy();return await M({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 sR(e,t,n,{loopId:r=null,nextFireAt:o=null}={}){if(!t)throw new Error("proposalId required");let s=await K({id:e.id,cwd:e.cwd}),a=s.find(c=>c.type==="loop.create.offered"&&c.payload?.proposalId===t);if(!a)throw new Error("unknown proposal");if(s.some(c=>c.type==="loop.create.answered"&&c.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await M({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 M({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 M({id:e.id,cwd:e.cwd},{type:"loop.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",loopId:String(r)}}),{proposalId:t,action:"created",loopId:String(r)}}var By=["name","schedule","prompt","expectation","notify","assignment","enabled"],b5=(e,t)=>(e?.provider??"claude")===(t?.provider??"claude")&&(e?.model??null)===(t?.model??null);function aR(e){let t=Array.isArray(e.runs)?e.runs:[],n=t[t.length-1]??null;return{definitionUpdatedAt:Number(e.definitionUpdatedAt??e.updatedAt)||null,name:e.name??"",schedule:e.schedule??"",prompt:e.prompt??"",expectation:e.expectation??null,notify:e.notify??"off",assignment:e.assignment&&typeof e.assignment=="object"?e.assignment:{provider:String(e.assignment||"claude")},enabled:e.enabled!==!1,repo:e.repo??null,nodeId:e.nodeId??null,nodeName:e.nodeName??null,trackId:e.trackId??null,nextFireAt:Number.isFinite(Number(e.nextFireAt))?Number(e.nextFireAt):null,createdAt:Number(e.createdAt)||null,runCount:t.length,lastRun:n?{firedAt:Number(n.firedAt)||null,outcome:n.outcome??(n.error?"errored":null)}:null}}function iR(e,t){let n=xn(t);if(!n)throw new Error("which loop? give an id or a name \u2014 see `bostrat-loop ls`");let r=e.find(a=>a.id===n)||e.find(a=>a.name===n);if(r)return r;let o=n.toLowerCase(),s=e.filter(a=>String(a.id).toLowerCase().startsWith(o)||String(a.name).toLowerCase().startsWith(o));if(s.length===1)return s[0];throw s.length>1?new Error(`"${n}" matches ${s.length} loops: ${s.map(a=>`${a.name} (${a.id})`).join(", ")} \u2014 use the id`):new Error(`no loop matching "${n}" \u2014 use \`bostrat-loop ls\``)}function k5(e,t){let n=e&&typeof e=="object"&&!Array.isArray(e)?e:null;if(!n)throw new Error("a patch must be a JSON object of the fields to change");let r=Object.keys(n).filter(a=>!By.includes(a));if(r.length){let a=r.filter(i=>["repo","nodeId","cwd","userId","owner","id","trackId"].includes(i));throw a.length?new Error(`a proposal can't change ${a.join(", ")} \u2014 retargeting a loop is a Loops-tab edit (scope D5)`):new Error(`unknown field(s) ${r.join(", ")} \u2014 patchable: ${By.join(", ")}`)}let o={};for(let a of By){if(!(a in n))continue;let i=vs[a](n[a]);(a==="assignment"?b5(i,t.assignment):i===(t[a]??(a==="notify"?"off":a==="enabled"?!0:null)))||(o[a]=i)}let s=Object.keys(o);if(!s.length)throw new Error("nothing would change \u2014 the patch equals the loop's current definition");return{patch:o,changed:s}}async function cR(e,t,n){let r=aR(t),{patch:o,changed:s}=k5(n,r),a=jy(),i={ts:Date.now(),proposalId:a,loopId:String(t.id),name:r.name,base:r,patch:o,changed:s,selfEdit:!!(r.trackId&&r.trackId===e.id)};return await M({id:e.id,cwd:e.cwd},{type:"loop.update.offered",actor:"system",source:"orchestrator",payload:i}),i}var rR=600;async function lR(e,t,n){let r=xn(n);if(!r)throw new Error('a delete proposal needs a reason \u2014 bostrat-loop propose-delete <loop> --reason "<why this loop should go>"');if(r.length>rR)throw new Error(`reason is too long (${r.length}); cap is ${rR}`);let o=aR(t),s=jy(),a={ts:Date.now(),proposalId:s,loopId:String(t.id),name:o.name,base:o,reason:r,selfEdit:!!(o.trackId&&o.trackId===e.id)};return await M({id:e.id,cwd:e.cwd},{type:"loop.delete.offered",actor:"system",source:"orchestrator",payload:a}),a}var uR=async(e,t,n)=>{if(!n)throw new Error("proposalId required");let r=await K({id:e.id,cwd:e.cwd}),o=r.find(a=>a.type===t&&a.payload?.proposalId===n);if(!o)throw new Error("unknown proposal");let s=t.replace(".offered",".answered");if(r.some(a=>a.type===s&&a.payload?.proposalId===n))throw new Error("proposal already answered");return o};async function dR(e,t,n,{nextFireAt:r=null}={}){if(!["applied","dismiss","moved"].includes(n))throw new Error("action must be one of applied | dismiss | moved");let s=(await uR(e,"loop.update.offered",t)).payload,a={id:e.id,cwd:e.cwd};return n==="applied"&&await M(a,{type:"loop.updated",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,loopId:s.loopId,name:s.patch?.name??s.name,changed:s.changed??Object.keys(s.patch||{}),nextFireAt:Number.isFinite(Number(r))?Number(r):null}}),await M(a,{type:"loop.update.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:n,loopId:s.loopId}}),{proposalId:t,action:n,loopId:s.loopId}}async function pR(e,t,n){if(!["delete","pause","keep","moved"].includes(n))throw new Error("action must be one of delete | pause | keep | moved");let o=(await uR(e,"loop.delete.offered",t)).payload,s={id:e.id,cwd:e.cwd};return(n==="delete"||n==="pause")&&await M(s,{type:n==="delete"?"loop.deleted":"loop.paused",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,loopId:o.loopId,name:o.name,trackId:o.base?.trackId??null}}),await M(s,{type:"loop.delete.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:n,loopId:o.loopId}}),{proposalId:t,action:n,loopId:o.loopId}}fe();import{randomUUID as x5}from"node:crypto";var Uy=20,v5=300,Ly=120,fR=120,mR=2e3,Mp=new Set(["build","ops","debt","spike"]),hR=new Set(["active","done","abandoned"]),Hy=new Set(["circuit.create","circuit.update","circuit.delete"]),S5=new Set(["person.create","slot.create","slot.update","slot.delete","reservation.create","reservation.update","reservation.delete"]),ol=new Set([...Hy,...S5]),A5=["name","description","status","type"],T5=["person","startDate","endDate","estUsd"],E5=["person","label","startDate","endDate"],_5=/^\d{4}-\d{2}-\d{2}$/,Ht=e=>String(e??"").trim(),Wy=e=>typeof e=="string"&&e.startsWith("@"),yR=864e5;function bR(e){let t=Date.parse(`${e}T00:00:00Z`),n=new Date(t).getUTCDay();return new Date(t-(n+6)%7*yR).toISOString().slice(0,10)}function I5(e){return new Date(Date.parse(`${bR(e)}T00:00:00Z`)+6*yR).toISOString().slice(0,10)}var wR=(e,t)=>{let n=Ht(e);if(!_5.test(n))throw new Error(`${t} must be YYYY-MM-DD, got "${e??""}"`);if(!Number.isFinite(Date.parse(`${n}T00:00:00Z`)))throw new Error(`${t} "${n}" is not a real date`);return n};function $5(e,t){let n=wR(e,"startDate"),r=wR(t,"endDate");if(r<n)throw new Error(`endDate ${r} is before startDate ${n}`);let o=bR(n),s=I5(r);return{startDate:o,endDate:s,snapped:o!==n||s!==r}}var gR=e=>{if(e==null||e==="")return null;let t=Number(e);if(!Number.isFinite(t)||t<0)throw new Error(`estUsd must be a non-negative number, got "${e}"`);return t},So=(e,t,n)=>{let r=Ht(e);if(r.length>t)throw new Error(`${n} is too long (${r.length}); cap is ${t}`);return r};function Fy(e,t){let n=Ht(t);if(!n)throw new Error("a circuit name or id is required");if(Wy(n))return{ref:n,id:null,name:n.slice(1)};let r=e.find(i=>i.id===n);if(r)return r;let o=n.toLowerCase(),s=e.filter(i=>String(i.name).toLowerCase()===o);if(s.length===1)return s[0];if(s.length>1)throw new Error(`"${n}" names ${s.length} circuits \u2014 use an id (bostrat-circuit ls)`);let a=e.filter(i=>String(i.name).toLowerCase().includes(o)).slice(0,5);throw new Error(a.length?`no circuit named "${n}" \u2014 near matches: ${a.map(i=>`${i.name} (${i.id})`).join(", ")}`:`no circuit named "${n}" \u2014 propose a circuit.create op if it should exist (bostrat-circuit ls lists yours)`)}function R5(e,t){let n=Ht(t);if(!n)throw new Error('a person is required \u2014 "me", a person id, or a row label');if(n==="me"||Wy(n))return{ref:n,id:null,label:n==="me"?"you":n.slice(1)};let r=e.find(a=>a.personId===n);if(r)return{...r,id:r.personId};let o=n.toLowerCase(),s=e.filter(a=>String(a.label).toLowerCase()===o);if(s.length===1)return{...s[0],id:s[0].personId};throw s.length>1?new Error(`"${n}" names ${s.length} roadmap rows \u2014 use a person id`):new Error(e.length?`no roadmap row for "${n}" \u2014 rows: ${e.map(a=>`${a.label} (${a.personId})`).join(", ")}, or propose a person.create op`:`no roadmap rows yet \u2014 use "me", or propose a person.create op for "${n}"`)}function O5(e,t,{allow:n=ol}={}){let r=e&&typeof e=="object"&&!Array.isArray(e)?e:null;if(!r)throw new Error("a plan must be a JSON object with an `ops` array");let o=Array.isArray(r.ops)?r.ops:null;if(!o?.length)throw new Error("a plan needs at least one op in `ops`");if(o.length>Uy)throw new Error(`too many ops (${o.length}); cap is ${Uy} \u2014 propose one intent at a time`);let s=Array.isArray(t?.circuits)?t.circuits:[],a=Array.isArray(t?.people)?t.people:[],i=Array.isArray(t?.slots)?t.slots:[],c=Array.isArray(t?.reservations)?t.reservations:[],l={circuits:{},slots:{},reservations:{}},u={},d=new Set,p=!1,f=!1,w=b=>{b.id&&(l.circuits[b.id]={name:b.name,status:b.status,type:b.type??"build",updatedAt:b.updatedAt??null},u[b.id]=b.name)},m=b=>{b.id&&(u[b.id]=b.label)},g=(b,R)=>{let _=Ht(b);if(!_)return null;if(d.has(_))throw new Error(`ref "${_}" is used by two ops \u2014 each ref names one thing`);return d.add(_),u[`@${_}`]=R,_},y=o.map((b,R)=>{let _=b&&typeof b=="object"?b:{},C=Ht(_.op),U=`op ${R+1}`;if(!ol.has(C))throw new Error(`${U}: unknown op "${C}" \u2014 one of ${[...ol].join(", ")}`);if(!n.has(C))throw new Error(`${U}: "${C}" isn't a circuit op \u2014 roadmap changes go through \`bostrat-roadmap propose\` (one card, either CLI)`);let B=A=>{throw new Error(`${U} (${C}): ${A}`)},T=A=>{let S=_.set&&typeof _.set=="object"&&!Array.isArray(_.set)?_.set:null;S||B("needs a `set` object naming the fields to change");let N=Object.keys(S).filter(H=>!A.includes(H));return N.length&&B(`unknown field(s) ${N.join(", ")} \u2014 settable: ${A.join(", ")}`),Object.keys(S).length||B("`set` names no fields"),S},$=A=>{let{startDate:S,endDate:N,snapped:H}=$5(A.startDate,A.endDate);return H&&(p=!0),{startDate:S,endDate:N,snapped:H}},L=A=>{let S=R5(a,A);return Ht(A)==="me"&&(f=!0),m(S),{key:S.id??Ht(A),label:S.label}},J=(A,S,N,H,q)=>{let re=Ht(A);re||B(`needs a ${H} id`);let we=S.find(Re=>Re[N]===re);return we||B(`no ${H} "${re}" \u2014 see \`bostrat-roadmap ls\``),q[re]={...we},we};switch(C){case"circuit.create":{let A=So(_.name,fR,"name");A||B("a circuit needs a name");let S=Ht(_.type)||"build";Mp.has(S)||B(`bad type "${S}" (${[...Mp].join(" | ")})`);let N=s.find(q=>String(q.name).toLowerCase()===A.toLowerCase());N&&B(`a circuit named "${N.name}" already exists (${N.id}) \u2014 update it instead of making a twin`);let H=g(_.ref,A);return{op:C,...H?{ref:H}:{},name:A,description:So(_.description,mR,"description"),type:S}}case"circuit.update":{let A=Fy(s,_.circuit);A.id||B("can't update a circuit created in the same plan \u2014 set its fields on the create op"),w(A);let S=T(A5),N={};if(S.name!==void 0){let H=So(S.name,fR,"name");H||B("name can't be blank"),H!==A.name&&(N.name=H)}return S.description!==void 0&&(N.description=So(S.description,mR,"description")),S.status!==void 0&&(hR.has(S.status)||B(`bad status "${S.status}" (${[...hR].join(" | ")})`),S.status!==A.status&&(N.status=S.status)),S.type!==void 0&&(Mp.has(S.type)||B(`bad type "${S.type}" (${[...Mp].join(" | ")})`),S.type!==(A.type??"build")&&(N.type=S.type)),Object.keys(N).length||B("nothing would change \u2014 the set equals the circuit's current values"),{op:C,circuit:A.id,name:A.name,set:N}}case"circuit.delete":{let A=Fy(s,_.circuit);A.id||B("can't delete a circuit created in the same plan"),w(A);let S=o.some((N,H)=>H<R&&Ht(N?.op)==="circuit.update"&&N?.set?.status&&N.set.status!=="active"&&Ht(N?.circuit)===Ht(_.circuit));return A.status==="active"&&!S&&B(`\u201C${A.name}\u201D is active \u2014 an active circuit can't be deleted; propose a circuit.update to done/abandoned first (both can ride one card)`),{op:C,circuit:A.id,name:A.name,status:A.status}}case"person.create":{let A=So(_.label,Ly,"label");A||B("a person row needs a label");let S=a.find(H=>String(H.label).toLowerCase()===A.toLowerCase());S&&B(`a roadmap row labelled "${S.label}" already exists (${S.personId})`);let N=g(_.ref,A);return{op:C,...N?{ref:N}:{},label:A}}case"slot.create":{let A=Fy(s,_.circuit);w(A);let S=L(_.person),N=$(_);return{op:C,circuit:A.id??A.ref,circuitName:A.name,person:S.key,personLabel:S.label,...N,estUsd:gR(_.estUsd)}}case"slot.update":{let A=J(_.slot,i,"slotId","slot",l.slots),S=T(T5),N={};if(S.person!==void 0){let q=L(S.person);N.person=q.key,N.personLabel=q.label}if(S.startDate!==void 0||S.endDate!==void 0){let q=$({startDate:S.startDate??A.startDate,endDate:S.endDate??A.endDate});q.startDate!==A.startDate&&(N.startDate=q.startDate),q.endDate!==A.endDate&&(N.endDate=q.endDate)}S.estUsd!==void 0&&(N.estUsd=gR(S.estUsd)),Object.keys(N).length||B("nothing would change");let H=s.find(q=>q.id===A.circuitId);return{op:C,slot:A.slotId,circuitName:H?.name??null,set:N}}case"slot.delete":{let A=J(_.slot,i,"slotId","slot",l.slots),S=s.find(N=>N.id===A.circuitId);return{op:C,slot:A.slotId,circuitName:S?.name??null,startDate:A.startDate,endDate:A.endDate}}case"reservation.create":{let A=L(_.person),S=So(_.label,Ly,"label");return S||B("a reservation needs a label (Leave, Support rotation, \u2026)"),{op:C,person:A.key,personLabel:A.label,label:S,...$(_)}}case"reservation.update":{let A=J(_.reservation,c,"reservationId","reservation",l.reservations),S=T(E5),N={};if(S.person!==void 0){let H=L(S.person);N.person=H.key,N.personLabel=H.label}if(S.label!==void 0){let H=So(S.label,Ly,"label");H||B("label can't be blank"),H!==A.label&&(N.label=H)}if(S.startDate!==void 0||S.endDate!==void 0){let H=$({startDate:S.startDate??A.startDate,endDate:S.endDate??A.endDate});H.startDate!==A.startDate&&(N.startDate=H.startDate),H.endDate!==A.endDate&&(N.endDate=H.endDate)}return Object.keys(N).length||B("nothing would change"),{op:C,reservation:A.reservationId,label:A.label,set:N}}case"reservation.delete":{let A=J(_.reservation,c,"reservationId","reservation",l.reservations);return{op:C,reservation:A.reservationId,label:A.label,startDate:A.startDate,endDate:A.endDate}}default:return B("unhandled op")}});y.forEach((b,R)=>{for(let _ of[b.circuit,b.person,b.set?.person])if(Wy(_)&&!d.has(String(_).slice(1)))throw new Error(`op ${R+1} (${b.op}): unknown ref "${_}" \u2014 no earlier op in this plan creates it`)});let x=a.some(b=>b.kind==="user"&&b.userId);return{why:So(r.why,v5,"why"),ops:y,base:l,resolved:u,snapped:p,createsMeRow:f&&!x}}async function kR(e,t,n,r={}){let o=O5(t,n,r),s=x5(),a={ts:Date.now(),proposalId:s,...o};return await M({id:e.id,cwd:e.cwd},{type:"planning.change.offered",actor:"system",source:"orchestrator",payload:a}),a}var M5=async(e,t)=>{if(!t)throw new Error("proposalId required");let n=await K({id:e.id,cwd:e.cwd}),r=n.find(o=>o.type==="planning.change.offered"&&o.payload?.proposalId===t);if(!r)throw new Error("unknown proposal");if(n.some(o=>o.type==="planning.change.answered"&&o.payload?.proposalId===t))throw new Error("proposal already answered");return r};async function xR(e,t,n,{results:r=[]}={}){if(!["applied","dismiss","moved"].includes(n))throw new Error("action must be one of applied | dismiss | moved");let o=await M5(e,t),s={id:e.id,cwd:e.cwd},a=o.payload;return n==="applied"&&await M(s,{type:"planning.changed",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,why:a.why??"",results:Array.isArray(r)?r.slice(0,Uy+1):[]}}),await M(s,{type:"planning.change.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:n,ops:a.ops?.length??0}}),{proposalId:t,action:n}}ud();fe();Cr();fe();Cn();Ad();var vR=10,SR=200,C5=120,N5=24,TR=/^\d{4}-\d{2}-\d{2}$/;function qy(e=process.env){return(e.CHANGELOG_REPOS||"globocodes/bostrat").split(",").map(t=>t.trim()).filter(Boolean)}var P5=(e=Date.now())=>new Date(e).toISOString().slice(0,10),gt=(e,t="i")=>new RegExp(e,t),D5=[{re:gt("^(business|docs|chore|ci|refactor|test|security|sec)(\\([^)]*\\))?!?:"),reason:"non-product PR prefix"},{re:gt("\\bSPC\\b",""),reason:"business (SPC)"},{re:gt("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),reason:"business"},{re:gt("competitor|cloudcli|\\bkiro\\b"),reason:"competitor research"},{re:gt("\\bReplicas\\b",""),reason:"competitor research"},{re:gt("tenanc|tenant|perimeter|ip[- ]gate|access[- ]code|vulnerab|\\bCVE\\b|audit|hardening|security|\\bsweep\\b"),reason:"security / tenancy"},{re:gt("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),reason:"internal codename"},{re:gt("^track/(business|security|spc|sec)-"),reason:"non-product branch"}],B5=[gt("\\bSPC\\b",""),gt("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),gt("competitor|cloudcli|\\bkiro\\b"),gt("\\bReplicas\\b",""),gt("tenanc|\\btenants?\\b|cross-tenant|perimeter|ip[- ]gate|vulnerab|\\bCVE\\b|hardening|security register|audit finding"),gt("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),gt("(^|[^\\w&])#\\d+\\b"),gt("\\btrack/[\\w.-]+")];function j5({title:e="",headRef:t=""}={}){let n=String(e||""),r=String(t||"");for(let{re:o,reason:s}of D5)if(o.test(n)||o.test(r))return s;return null}function AR(e){let t=String(e||"");for(let n of B5){let r=n.exec(t);if(r)return r[0].trim()}return null}function ER(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 L5=/^\*\*([^*]+?)\*\*\s*[:.]?\s*[—–-]?\s*(.*)$/;function F5(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=gc(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(`
759
+ `)){let s=o.trim();if(!s)continue;if(s.startsWith("#")){n==null&&(n=s.replace(/^#+\s*/,"").trim().slice(0,C5)||null);continue}let a=/^[-*]\s+(.*)$/.exec(s);if(!a)continue;let i=a[1].trim(),c=null,l=new RegExp(`^\\[([^\\]]{1,${N5}})\\]\\s+(.*)$`).exec(i);if(l&&(c=l[1].trim(),i=l[2].trim()),!i)continue;let u=L5.exec(i);if(!u||!u[1].trim()||!u[2].trim())throw new Error(`bullet ${r.length+1} must be \`**Short summary** \u2014 the item, one sentence.\` (bold summary title, em dash, then the change) \u2014 got "${i.slice(0,80)}". Rewrite it and re-publish.`);i=`**${u[1].trim().replace(/[:.]\s*$/,"")}** \u2014 ${u[2].trim()}`;let d=AR(i);if(d)throw new Error(`bullet ${r.length+1} mentions "${d}" \u2014 the product changelog never carries business, security/tenancy or internal-ops items, PR numbers, branch names or codenames; drop the bullet or rewrite it as the user-visible change and re-publish.`);if(i.length>SR)throw new Error(`bullet ${r.length+1} is ${i.length} chars \u2014 over the ${SR}-char cap; a changelog bullet is one line`);r.push({text:i,...c?{area:c}:{}})}if(n){let o=AR(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>vR)throw new Error(`${r.length} bullets \u2014 over the ${vR}-bullet cap; group related changes into one line`);return{title:n||null,bullets:r}}async function U5(e,{repos:t=qy()}={}){let n=new Set(t);return(await dn()).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:j5({title:r.title,headRef:r.headRef})}))}async function _R(e,t){let n=await U5(e,t);return{prs:n.filter(r=>!r.excluded),excluded:n.filter(r=>r.excluded)}}async function IR(e,{md:t,day:n=null}){let r=F5(t),o=n==null||n===""?P5():String(n);if(!TR.test(o)||Number.isNaN(Date.parse(o)))throw new Error(`invalid day "${n}" \u2014 expected YYYY-MM-DD`);let s=await M({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 $R(e,{day:t}){let n=String(t||"");if(!TR.test(n)||Number.isNaN(Date.parse(n)))throw new Error(`invalid day "${t}" \u2014 expected YYYY-MM-DD`);let r=await M({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}}Xo();Cn();Qo();fe();Xo();ft();pr();Cn();Wi();sd();qu();Ji();Jt();import{execFile as Q5}from"node:child_process";import{promisify as eK}from"node:util";var H5=new Set(["pull_request","check_suite","workflow_run","push"]),W5=/^[^/\s]+\/[^/\s]+$/,q5=500,Ky=new Set,Gy=[],Cp=new Map,tn={hourStart:0,byEvent:{},duplicates:0,rejected:0};function zy(e,t,n){let r=Math.floor(e/36e5)*36e5;r!==tn.hourStart&&(tn.hourStart=r,tn.byEvent={},tn.duplicates=0,tn.rejected=0),t==="accepted"?tn.byEvent[n]=(tn.byEvent[n]||0)+1:tn[t]+=1}function K5(e){if(!e||typeof e!="object"||e.forge!=="github"||typeof e.event!="string"||!H5.has(e.event)||typeof e.repo!="string"||!W5.test(e.repo))return null;let t=(Array.isArray(e.numbers)?e.numbers:[]).map(Number).filter(r=>Number.isInteger(r)&&r>0),n=Number.isInteger(e.number)&&e.number>0?e.number:t[0]??null;return{forge:"github",deliveryId:typeof e.deliveryId=="string"&&e.deliveryId?e.deliveryId.slice(0,128):null,event:e.event,action:typeof e.action=="string"?e.action.slice(0,64):null,repo:e.repo,number:n,numbers:n&&!t.includes(n)?[n,...t]:t,headSha:typeof e.headSha=="string"?e.headSha.slice(0,64):null,headRef:typeof e.headRef=="string"?e.headRef.slice(0,256):null,baseRef:typeof e.baseRef=="string"?e.baseRef.slice(0,256):null,merged:typeof e.merged=="boolean"?e.merged:null,draft:typeof e.draft=="boolean"?e.draft:null,conclusion:typeof e.conclusion=="string"?e.conclusion.slice(0,64):null,deleted:e.deleted===!0,senderLogin:typeof e.senderLogin=="string"?e.senderLogin.slice(0,128):null,ts:Number.isFinite(e.ts)?e.ts:null}}function RR(e,{now:t=Date.now(),onAccept:n=null,log:r=console}={}){let o=K5(e);if(!o)return zy(t,"rejected"),{ok:!1,error:"malformed github event envelope"};if(o.deliveryId){if(Ky.has(o.deliveryId))return zy(t,"duplicates"),{ok:!0,duplicate:!0,envelope:o};for(Ky.add(o.deliveryId),Gy.push(o.deliveryId);Gy.length>q5;)Ky.delete(Gy.shift())}let s=o.repo.toLowerCase(),a=Cp.get(s)||{lastDeliveryAt:0,count:0};a.lastDeliveryAt=t,a.count+=1,Cp.set(s,a),zy(t,"accepted",o.event),r.log?.(`[github-event] ${o.event}${o.action?` ${o.action}`:""} ${o.repo}${o.number?` #${o.number}`:o.headRef?` ${o.headRef}`:""}${o.conclusion?` (${o.conclusion})`:""}${o.deliveryId?` delivery ${o.deliveryId.slice(0,8)}`:""}`);try{n?.(o)}catch(i){r.error?.("[github-event] onAccept failed:",i?.message||i)}return{ok:!0,duplicate:!1,envelope:o}}function G5(e,t=Date.now()){let n=Cp.get(String(e||"").toLowerCase());return n?{covered:!0,lastDeliveryAt:n.lastDeliveryAt,ageMs:t-n.lastDeliveryAt,count:n.count}:{covered:!1,lastDeliveryAt:null,ageMs:null,count:0}}var OR=1440*6e4;function Vy(e,t=Date.now()){let n=G5(e,t);return n.covered&&n.ageMs<OR}function MR(e=Date.now()){let t={};for(let[n,r]of Cp)t[n]={lastDeliveryAt:r.lastDeliveryAt,count:r.count,covered:e-r.lastDeliveryAt<OR};return{hourStart:tn.hourStart,byEvent:{...tn.byEvent},duplicates:tn.duplicates,rejected:tn.rejected,repos:t}}fe();Cn();$r();pr();Jt();function CR(e){return(e?.checks?.failed??0)>0?"red":e?.mergeable==="CONFLICTING"?"conflict":e?.mergeStateStatus==="BEHIND"?"behind":null}function z5(e){return!(!e?.checks||e.checks.pending>0||e.mergeabilityPending||e.mergeable==="UNKNOWN"||e.mergeStateStatus==="UNKNOWN")}var V5=new Set(["merged","closed","lost"]);function J5(e,t){if(!e?.blocked)return null;let n=CR(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 Y5(e,t){return e.autoMerge?!0:t==="ci-fixed"?!!(e.ciFix||e.ciFixAwait):t==="reconciled"?!!(e.reconcile||e.reconcileAwait):!1}async function X5(e,t,n,r,o){return(await K(e).catch(()=>[])).some(a=>{if(a.type!=="pr.state.changed"||a.payload?.number!==Number(n))return!1;let i=a.payload?.change;return i===t?a.payload?.sha&&r?a.payload.sha===r:(a.payload?.ts||0)>=o:i==="pushed"&&!!r&&a.payload?.sha===r})}async function Z5(e,t,n){await M({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 Np(e,t={}){let{now:n=Date.now(),slugOf:r=_e,lookup:o=at,note:s=DS,tracks:a=async()=>(await he()).filter(d=>!je(d)),asked:i=X5,emitChange:c=Z5}=t,l=[],u=null;for(let d of e??[]){if(!d?.prs?.length)continue;let p=await r(d.path).catch(()=>null);if(p)for(let f of d.prs)try{if(!z5(f))continue;let w=await o(p,f.number).catch(()=>null);if(!w?.trackId||V5.has(w.state))continue;let{prev:m}=await s(p,f.number,{blocked:CR(f),sha:f.headSha??null,at:n});if(!m)continue;let g=J5(m,f);if(!g||Y5(w,g.change))continue;u??=new Map((await a()).map(R=>[R.id,R]));let y=u.get(w.trackId);if(!y)continue;let x=f.headSha??null;if(await i(y,g.change,f.number,x,m.at||0))continue;let b={number:Number(f.number),url:f.url||w.url,title:f.title||w.title,branch:f.headRefName||w.headRef,repo:p,sha:x,delegated:!1,reason:g.reason};g.change==="ci-fixed"?b.passed=f.checks.passed:b.base=f.baseRefName||null,await c(y,g.change,b),l.push({change:g.change,number:f.number,reason:g.reason})}catch{}}return l}var Xy=eK(Q5),FR=3e4,tK=30*6e4,nK=FR,rK=10*6e4,oK=10080*6e4,sK=60*6e4,aK=8,UR=1440*6e4,iK=3,HR="number,url,title,headRefName,headRefOid,state,mergedAt,closedAt",Yy=60*6e4,cK=15*6e4,lK=9e4,uK=1440*6e4,Pp=new Map,Dp=new Map,dK=/could not resolve|not found|no pull requests?/i,pK=e=>dK.test(String(e?.message||e||""));function fK(e,t){return[e.ciFix?.delegatedAt,e.reconcile?.delegatedAt,e.ciFixAwait?.since,e.reconcileAwait?.since].some(n=>n&&t-n<Yy)}var NR={fast:nK,slow:rK,decay:sK};function PR(e,t,n=Vy){return WR(e,t,{grace:0})||!n(e.repo,t)&&(e.armedAt&&t-e.armedAt<tK||fK(e,t))?"fast":t-(e.firstSeen||0)>oK?"decay":"slow"}function al(e,t,n,r){let o=e.lanes?.get(le(t.repo,t.number))||{};return Wu({change:n,repo:t.repo,number:Number(t.number),githubAt:r||null,lane:o.lane||null,intervalMs:o.intervalMs||null,source:"watch"})}async function mK(e,t){ir("watch");try{let{stdout:n}=await Xy("gh",["pr","view",String(t),"--repo",e,"--json",HR],{timeout:3e4,maxBuffer:4194304,env:{...process.env,...await An({slug:e})}});return JSON.parse(n||"null")}catch(n){throw to(n)&&no(n),n}}async function hK(e){ir("watch");try{let{stdout:t}=await Xy("gh",["pr","list","--repo",e,"--state","all","--limit","100","--json",HR],{timeout:3e4,maxBuffer:8388608,env:{...process.env,...await An({slug:e})}}),n=new Map;for(let r of JSON.parse(t||"[]"))n.set(Number(r.number),r);return n}catch(t){throw to(t)&&no(t),t}}async function wK(){let e=new Map;for(let t of await he().catch(()=>[]))e.set(t.id,t);return e}async function gK(e,t){await M({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"merged",...t}}),await od(e,t).catch(()=>{})}async function yK(e,t){let n=await Yo(e);return n?ca(n,t):null}async function bK(e,t,n){let r=await Yo(e);if(!r)throw new Error(`no local checkout for ${e}`);return la(r,t,{method:n})}async function kK(e,t){let n=await Yo(e);if(!n)throw new Error(`no local checkout for ${e}`);return Gi(n,t)}async function xK(e,t){await M({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 Fa(e,t,n,r,o){if(!await r.disarm(e.repo,e.number).catch(()=>null))return;let a=n.get(e.trackId);a&&await r.emitDisarmed(a,{number:Number(e.number),url:t?.url||e.url,title:t?.title||e.title,branch:t?.headRefName||e.headRef,repo:e.repo,reason:o}).catch(()=>{})}var vK=10*6e4;async function SK(e,t,n){let r=e.autoMerge?.armedAt||0;if(r&&(n.now??Date.now())-r>UR){await Fa(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 Fa(e,o,t,n,`check${o.checks.failed===1?"":"s"} failed: ${a}`);return}if(o.mergeable==="CONFLICTING"){await Fa(e,o,t,n,`conflicts with ${o.baseRefName}`);return}if(!o.checks.total){let a=Math.max(e.autoMerge?.armedAt||0,Date.parse(o.updatedAt||"")||0);if((n.now??Date.now())-a<vK)return;await Fa(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 Fa(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 Fa(e,o,t,n,String(a?.message||a).trim()||"merge failed");return}await qR(e,{...o,state:"MERGED"},t,n,{change:"auto-merged",githubAt:o.checks.settledAt||null})}}async function Ua(e,t,n){await M({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 AK(e,t){try{return await Xy("git",["-C",e.cwd,"cat-file","-e",`${t}^{commit}`],{timeout:1e4}),!0}catch{return!1}}async function sl(e,t,n,r=()=>!0){return(await K(e).catch(()=>[])).some(s=>s.type==="pr.state.changed"&&s.payload?.change===t&&s.payload?.number===Number(n)&&r(s))}var Ha=(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 WR(e,t,{grace:n=lK}={}){if(e.announced!==!1)return!1;let r=t-(e.firstSeen||0);return r>=n&&r<=uK}async function TK(e,t,n,r){let o=r.now??Date.now();if(!WR(e,o))return!1;let s=n.get(e.trackId)||null;if(!s||je(s))return!1;let a=(s.boxes||[]).find(d=>d.name===s.leadBox);return await(r.midTurn??Zo)(s.leadBox,a?.agent).catch(()=>!1)?!1:(await K(s).catch(()=>[])).some(d=>d.type==="pr.state.changed"&&d.payload?.number===Number(e.number))?(await(r.claim??sr)(e.repo,e.number).catch(()=>null),!1):await(r.claim??sr)(e.repo,e.number).catch(()=>null)?(await Ua(s,"opened",{...Ha(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 EK(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 Pu(e.repo,e.number,{headSha:s}).catch(()=>{}),e.reconcile?.headSha&&s!==e.reconcile.headSha&&await Bu(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<cK;await PS(e.repo,e.number,s).catch(()=>{}),e.baseFoldAt&&await NS(e.repo,e.number).catch(()=>{}),!i&&!c&&!l&&a&&!await r.localHasCommit(a,s).catch(()=>!1)&&!await sl(a,"pushed",e.number,d=>d.payload?.sha===s)&&await Ua(a,"pushed",{...Ha(e,t),sha:s}).catch(()=>{})}if(e.ciFixAwait)if(o-(e.ciFixAwait.since||0)>Yy)await Du(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 Du(e.repo,e.number).catch(()=>{});else if(i.checks.total>0&&i.checks.pending===0){let c=al(r,e,"ci-fixed",i.checks.settledAt||null),l=e.ciFixAwait.since||0;a&&!await sl(a,"ci-fixed",e.number,u=>(u.payload?.ts||0)>=l)&&await Ua(a,"ci-fixed",{...Ha(e,t),sha:s,delegated:!0,passed:i.checks.passed,githubAt:c.githubAt,latencyMs:c.latencyMs,lane:c.lane}).catch(()=>{}),await Du(e.repo,e.number).catch(()=>{})}}}if(e.reconcileAwait)if(o-(e.reconcileAwait.since||0)>Yy)await ju(e.repo,e.number).catch(()=>{});else{let i=await r.detail(e.repo,e.number).catch(()=>null);if(i){if(i.mergeable==="CONFLICTING")await ju(e.repo,e.number).catch(()=>{});else if(i.mergeable==="MERGEABLE"){al(r,e,"reconciled",null);let c=e.reconcileAwait.since||0;a&&!await sl(a,"reconciled",e.number,l=>(l.payload?.ts||0)>=c)&&await Ua(a,"reconciled",{...Ha(e,t),sha:s,delegated:!0,base:i.baseRefName||null}).catch(()=>{}),await ju(e.repo,e.number).catch(()=>{})}}}}async function _K(e,t,n,r){let o=al(r,e,"closed",Date.parse(t?.closedAt||"")||null),s=n.get(e.trackId);s&&!await sl(s,"closed",e.number)&&await Ua(s,"closed",{...Ha(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 IK(e,t,n){al(n,e,"lost",null);let r=t.get(e.trackId);r&&!await sl(r,"lost",e.number)&&await Ua(r,"lost",Ha(e,null)).catch(()=>{}),await n.notifyIfResolved(e.repo,e.number,"lost").catch(()=>{}),await n.mark(e.repo,e.number,"lost").catch(()=>{})}async function qR(e,t,n,r,o={}){let s=al(r,e,o.change||"merged",o.githubAt??(Date.parse(t.mergedAt||"")||null)),a=n.get(e.trackId);a&&((await K(a).catch(()=>[])).some(l=>l.type==="pr.state.changed"&&l.payload?.change==="merged"&&l.payload?.number===Number(e.number))||await r.emitMerged(a,{number:Number(e.number),url:t.url||e.url,title:t.title||e.title,branch:t.headRefName||e.headRef,repo:e.repo,githubAt:s.githubAt,latencyMs:s.latencyMs,lane:s.lane}).catch(()=>{})),await r.notifyIfArmed(e.repo,e.number).catch(()=>{}),await r.followupsIfMerged(e.repo,e.number).catch(()=>{}),await r.archiveIfArmed(e.repo,e.number).catch(()=>{}),await r.mark(e.repo,e.number,"merged").catch(()=>{})}async function DR(e={}){let{now:t=Date.now(),auth:n=fh,view:r=mK,list:o=hK,links:s=LS,trackMap:a=wK,emitMerged:i=gK,mark:c=Qr,archiveIfArmed:l=ur,notifyIfArmed:u=dr,notifyIfResolved:d=zd,followupsIfMerged:p=ds,batchThreshold:f=iK,detail:w=yK,merge:m=bK,updateBranch:g=kK,lookup:y=at,disarm:x=Hi,emitDisarmed:b=xK,localHasCommit:R=AK,claim:_=sr,midTurn:C=Zo,only:U=null,wantDetail:B=null,covered:T=Vy,verdicts:$=null}=e;if(!(await n().catch(()=>null))?.authenticated||Uu()>0)return 0;let J=await s().catch(()=>[]),A=lA(J),S=Y=>{try{return!!B?.(Y)}catch{return!1}},N=U?J.filter(Y=>{try{return U(Y)}catch{return!1}}):J.filter(Y=>t-(Pp.get(le(Y.repo,Y.number))||0)>=NR[PR(Y,t,T)]);if(!N.length)return 0;let H=Date.now(),q=new Map,re=new Map;for(let Y of[...N].sort(zi)){let ie=U?"event":PR(Y,t,T);q.set(le(Y.repo,Y.number),{lane:ie,intervalMs:NR[ie]??null}),Pp.set(le(Y.repo,Y.number),t),re.has(Y.repo)||re.set(Y.repo,[]),re.get(Y.repo).push(Y)}let we=await a().catch(()=>new Map),Re=new Map,Ee=(Y,ie)=>{let ve=le(Y,ie);if(!Re.has(ve)){let Ne=Promise.resolve().then(()=>w(Y,ie));Ne.catch(()=>{}),Re.set(ve,Ne)}return Re.get(ve)},Z=$??((Y,ie)=>Np([{path:Y,prs:[ie]}],{now:t,slugOf:async()=>Y,tracks:async()=>[...we.values()].filter(ve=>!je(ve))}).catch(()=>{})),ye={now:t,lanes:q,emitMerged:i,mark:c,archiveIfArmed:l,notifyIfArmed:u,notifyIfResolved:d,followupsIfMerged:p,detail:Ee,merge:m,updateBranch:g,lookup:y,disarm:x,emitDisarmed:b,localHasCommit:R,claim:_,midTurn:C};for(let[Y,ie]of re){let ve,Ne=new Set,O=D=>D.ciFixAwait||D.reconcileAwait||S(D)?!0:!D.autoMerge||D.trackId&&A.get(D.trackId)!==le(D.repo,D.number)?!1:t-(D.autoMerge.armedAt||0)<=UR;if(ie.length>f)ve=await o(Y).catch(()=>null);else{ve=new Map;for(let D of ie){if(O(D)){let pe=await Ee(Y,D.number).catch(()=>null);if(pe?.state){ve.set(Number(D.number),{number:Number(D.number),url:pe.url,title:pe.title,headRefName:pe.headRefName,headRefOid:pe.headSha??null,state:pe.state,mergedAt:pe.mergedAt??null,closedAt:pe.closedAt??null});continue}}try{let pe=await r(Y,D.number);pe?.number!=null&&ve.set(Number(pe.number),pe)}catch(pe){pK(pe)&&Ne.add(le(D.repo,D.number))}}}if(ve)for(let D of ie){let pe=le(D.repo,D.number),Le=ve.get(Number(D.number));if(!Le){if(Ne.has(pe)){let Ce=(Dp.get(pe)||0)+1;Dp.set(pe,Ce),Ce>=aK&&(await IK(D,we,ye),Dp.delete(pe),Pp.delete(pe))}continue}if(Dp.delete(pe),Le.state==="MERGED"||Le.state==="CLOSED")Le.state==="MERGED"?await qR(D,Le,we,ye):await _K(D,Le,we,ye),Pp.delete(pe);else{await TK(D,Le,we,ye).catch(()=>{}),await EK(D,Le,we,ye).catch(()=>{});let Ce=!D.trackId||A.get(D.trackId)===pe;D.autoMerge&&Ce&&await SK(D,we,ye).catch(()=>{});try{if(S(D)&&!Re.has(pe)&&Ee(D.repo,D.number),Re.has(pe)){let Kt=await Re.get(pe).catch(()=>null);Kt?.checks&&await Z(D.repo,Kt)}}catch{}}}}let X={};for(let{lane:Y}of q.values())X[Y]=(X[Y]||0)+1;return console.log(`[pr-watch] probed ${N.length} link(s) (${Object.entries(X).map(([Y,ie])=>`${Y} ${ie}`).join(", ")}) in ${Date.now()-H}ms`),N.length}function BR(e,t){return!e||!t?!1:e.all?!0:String(t.repo||"").toLowerCase()!==e.repo?!1:e.numbers?.length?e.numbers.includes(Number(t.number)):e.event==="push"?!!e.branch&&t.headRef===e.branch||!!t.autoMerge:e.branch?t.headRef===e.branch:!0}var Jy=!1,Bp=!1,jp=[],jR=Promise.resolve();async function $K(){for(;Bp||jp.length;){if(Bp){Bp=!1;try{await DR()}catch{}continue}let e=jp;jp=[];let t=e.map(r=>r.spec),n=Object.assign({},...e.map(r=>r.deps||{}));try{await DR({...n,only:r=>t.some(o=>BR(o,r)),wantDetail:r=>t.some(o=>o.detail&&BR(o,r))})}catch{}}}function Lp(e,t){return e===null?Bp=!0:jp.push({spec:e,deps:t}),Jy||(Jy=!0,jR=$K().finally(()=>{Jy=!1})),jR}function KR(e,t=void 0){let n=String(e?.repo||"").toLowerCase();if(!/^[^/\s]+\/[^/\s]+$/.test(n))return Promise.resolve();let r=(Array.isArray(e.numbers)?e.numbers:[]).map(Number).filter(o=>Number.isInteger(o)&&o>0);return Lp({repo:n,numbers:r,branch:e.branch||null,event:e.event||null,detail:e.detail===!0},t)}var RK=6e4,LR=0;function GR(e=void 0){let t=e?.now??Date.now();return t-LR<RK?Promise.resolve():(LR=t,Lp({all:!0},e))}function zR(){Lp(null),setInterval(()=>Lp(null),FR)}Xo();ad();fc();pr();Jt();var OK=new Set(["opened","reopened","closed","synchronize","ready_for_review","converted_to_draft","edited"]);async function MK({tracks:e=he,reconcile:t=yd}={}){for(let n of(await e().catch(()=>[])).filter(r=>!je(r)))await t(n,{bypassThrottle:!0}).catch(()=>{})}function VR(e,t={}){let{invalidate:n=Xt,probe:r=KR,poke:o=GA,reconcileOpened:s=MK}=t;try{n()}catch{}let a={probe:null,poked:!1,reconciled:!1};if(!e?.repo)return a;if(e.event==="pull_request"&&OK.has(e.action)){if(e.action==="opened"||e.action==="reopened"){a.poked=!0,a.reconciled=!0;try{o()}catch{}s()}a.probe={repo:e.repo,numbers:e.numbers,branch:e.headRef||null,event:e.event}}else(e.event==="check_suite"||e.event==="workflow_run")&&e.action==="completed"?a.probe={repo:e.repo,numbers:e.numbers,branch:e.headRef||null,event:e.event,detail:!0}:e.event==="push"&&!e.deleted&&(a.probe={repo:e.repo,branch:e.headRef||null,event:"push"});return a.probe&&r(a.probe),a}ct();fe();pr();Jt();import{randomUUID as CK}from"node:crypto";var NK=2e4,JR=3,Wa=new Map,Zy=new Set;async function YR(e,t,n){let r=await n(e).catch(()=>[]),o=null;for(let s of r)s.type==="box.fullscreen.detected"&&s.boxId===t?o=s.payload?.offerId||null:s.type==="box.fullscreen.answered"&&o&&s.payload?.offerId===o&&(o=null);return o}async function PK(e={}){let{sessions:t=null,tracks:n=null,append:r=M,read:o=K,now:s=Date.now()}=e;if(process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1")return;let a,i;try{a=t??await on(),i=n??await he()}catch{return}let c=new Map(a.map(u=>[u.name,u])),l=new Set;for(let u of i){if(je(u)||!u.leadBox)continue;let d=(u.boxes||[]).find(f=>f.name===u.leadBox);if(!d||d.agent!=="claude"||d.state!=="live")continue;let p=c.get(d.name);if(p)if(l.add(d.name),p.alternateOn){let f=(Wa.get(d.name)||0)+1;Wa.set(d.name,f),f===JR&&(Zy.add(d.name),await YR(u,d.name,o)||await r(u,{type:"box.fullscreen.detected",actor:"system",source:"orchestrator",boxId:d.name,provider:d.agent,payload:{ts:s,offerId:CK(),box:d.name,agent:d.agent}}).catch(()=>{}))}else{let f=(Wa.get(d.name)||0)>=JR;if(Wa.delete(d.name),f||!Zy.has(d.name)){Zy.add(d.name);let w=await YR(u,d.name,o);w&&await r(u,{type:"box.fullscreen.answered",actor:"system",source:"orchestrator",boxId:d.name,provider:d.agent,payload:{ts:s,offerId:w,action:"cleared"}}).catch(()=>{})}}}for(let u of[...Wa.keys()])l.has(u)||Wa.delete(u)}var il=null,Qy=!1;function XR(){return il?()=>{}:(il=setInterval(()=>{Qy||(Qy=!0,PK().catch(()=>{}).finally(()=>{Qy=!1}))},NK),il.unref?.(),()=>{clearInterval(il),il=null})}Go();fc();fe();Xo();Qo();Go();ec();import{randomUUID as DK}from"node:crypto";async function BK(){let e=await Promise.resolve().then(()=>(pr(),V_));return{sayToLead:e.sayToLead,queueShipCompleteNotify:e.queueShipCompleteNotify}}var eb={listRepoPrs:Nn,readEvents:K,appendEvent:M,sayDeps:BK,currentBranch:ro};async function jK(e,t=eb,{branch:n=null}={}){if(!e?.cwd)return null;let r=n||await(t.currentBranch??ro)(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 tb(e,t,{actions:n,notify:r=!1}={},o=eb){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 jK(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=DK();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 nb(e,{offerId:t,choice:n}={},r=eb){if(!t)throw new Error("offerId required");if(!["push","new","dismiss"].includes(n))throw new Error('choice "push" | "new" | "dismiss" required');return so(`prx:${e.id}:${t}`,()=>LK(e,{offerId:t,choice:n},r))}async function LK(e,{offerId:t,choice:n},r){let o=await r.readEvents(e),s=o.find(u=>u.type==="pr.exists.offered"&&u.payload?.offerId===t);if(!s)throw new Error("unknown offer");if(o.some(u=>u.type==="pr.exists.answered"&&u.payload?.offerId===t))throw new Error("offer already answered");let a=s.payload||{},i=Array.isArray(a.actions)&&a.actions.length?a.actions:["commit","push","pr"],c=null,l=null;if(n==="push"){let{sayToLead:u}=await r.sayDeps();l=Xr.filter(d=>d!=="pr"&&(i.includes(d)||d==="push")),c=await u(e.id,oa(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,SS(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}}ec();import Er from"node:fs/promises";import qa from"node:path";import oO from"node:os";import ZR from"node:fs/promises";import Fp from"node:path";import{execFile as FK}from"node:child_process";import{promisify as UK}from"node:util";import{fileURLToPath as HK}from"node:url";var WK=UK(FK),eO=Fp.dirname(HK(import.meta.url)),qK=Fp.resolve(eO,"..","..","client","dist"),KK="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",GK=new Map([...KK].map((e,t)=>[e,t]));function zK(e){let t=[],n=0,r=0;for(let o of e){let s=GK.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 VK(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=zK(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 JK(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 QR=new Map;async function YK(e){let t;try{t=await ZR.stat(e)}catch{return null}let n=QR.get(e);if(n&&n.mtimeMs===t.mtimeMs)return n;try{let r=JSON.parse(await ZR.readFile(e,"utf8")),o={mtimeMs:t.mtimeMs,sources:r.sources||[],lines:VK(r.mappings||"")};return QR.set(e,o),o}catch{return null}}var rb=null;function XK(){return rb||(rb=process.env.BOSTRAT_RELEASE?Promise.resolve(process.env.BOSTRAT_RELEASE):WK("git",["rev-parse","--short","HEAD"],{cwd:Fp.resolve(eO,"..","..")}).then(e=>e.stdout.trim()).catch(()=>null)),rb}var ZK=/(?:https?:\/\/[^\s()]*)?\/assets\/([^\s()/]+\.js):(\d+):(\d+)/g;async function QK(e,{distDir:t=qK}={}){let n=[],r=0,o=!1;for(let s of e.matchAll(ZK)){let[a,i,c,l]=s,u=await YK(Fp.join(t,"assets",`${i}.map`)),d=u?JK(u.lines[Number(c)-1],Number(l)-1):null;if(n.push(e.slice(r,s.index)),d&&u.sources[d[1]]){let p=u.sources[d[1]].replace(/^(\.\.\/)+/,"");n.push(`${p}:${d[2]+1}:${d[3]+1}`),o=!0}else n.push(a);r=s.index+a.length}return n.push(e.slice(r)),{stack:n.join(""),symbolicated:o}}async function tO(e,t={}){try{if(!e?.error?.stack||!e.release||e.release==="unknown")return e;let n=t.release??await XK();if(!n||e.release!==n)return e;let{stack:r,symbolicated:o}=await QK(e.error.stack,t);o&&(e.error.stack=r,e.error.symbolicated=!0)}catch{}return e}var e6=()=>process.env.BOSTRAT_STATE_DIR||qa.join(process.env.HOME||oO.tmpdir(),".bostrat"),Ao=()=>qa.join(e6(),"telemetry"),sO=()=>qa.join(Ao(),".relay-offsets.json"),t6=50,n6=14,r6=3e4,nO=500,Wt=(e,t)=>typeof e=="string"?e.slice(0,t):"";function o6(e,t){if(!e||typeof e!="object")return null;let n=Wt(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:Wt(e.anonId,64),sessionId:Wt(e.sessionId,64),userId:Wt(e.userId,64),release:Wt(e.release,64),appVersion:Wt(e.appVersion,32),route:Wt(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:Wt(e.error.kind,256),message:Wt(e.error.message,8192),stack:Wt(e.error.stack,32768),fingerprint:Wt(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:Wt(s?.n,64),r:Wt(s?.r,128)}))),o}var aO=e=>new Date(e).toISOString().slice(0,10),rO=0;async function iO(e,t=Date.now()){let r=(Array.isArray(e?.events)?e.events.slice(0,t6):[]).map(s=>o6(s,t)).filter(Boolean);if(!r.length)return 0;for(let s of r)s.error?.stack&&await tO(s);await Er.mkdir(Ao(),{recursive:!0});let o=qa.join(Ao(),`${aO(t)}.ndjson`);return await Er.appendFile(o,r.map(s=>JSON.stringify(s)+`
760
+ `).join(""),"utf8"),t-rO>6*3600*1e3&&(rO=t,s6(t).catch(()=>{})),r.length}async function s6(e=Date.now()){let t=aO(e-n6*24*3600*1e3),n=[];try{n=await Er.readdir(Ao())}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 Er.rm(qa.join(Ao(),s),{force:!0});let o=await lO();for(let s of r)delete o[s];await uO(o)}var Up=new Map;function cO(e,t=Date.now()){let n=e||"unknown",r=Up.get(n);return r||(Up.size>512&&Up.clear(),r={tokens:40,at:t},Up.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 lO(){try{return JSON.parse(await Er.readFile(sO(),"utf8"))||{}}catch{return{}}}async function uO(e){await Er.mkdir(Ao(),{recursive:!0}),await Er.writeFile(sO(),JSON.stringify(e),"utf8")}function a6(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||oO.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 i6({fetchImpl:e=fetch}={}){let t=await OI();if(!t)return{sent:0,disabled:!0};let n;try{n=(await Er.readdir(Ao())).filter(s=>s.endsWith(".ndjson")).sort()}catch{return{sent:0,disabled:!1}}let r=await lO(),o=0;for(let s of n){let a=qa.join(Ao(),s),i=r[s]||0,c;try{let p=await Er.open(a,"r");try{let f=(await p.stat()).size;if(f<=i)continue;c=Buffer.alloc(f-i),await p.read(c,0,c.length,i)}finally{await p.close()}}catch{continue}let l=c.lastIndexOf(10);if(l<0)continue;let u=c.toString("utf8",0,l+1).split(`
761
+ `).filter(Boolean),d=[];for(let p of u)try{d.push(JSON.parse(p))}catch{}for(let p=0;p<d.length;p+=nO){let f=d.slice(p,p+nO).map(m=>a6(m)),w=await e(`${t.url.replace(/\/$/,"")}/v1/logs`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${t.ingestKey}`},body:JSON.stringify({events:f})}).catch(()=>null);if(!w||!w.ok)return{sent:o,disabled:!1};o+=f.length}r[s]=i+l+1,await uO(r)}return{sent:o,disabled:!1}}var ob=null,sb=!1;function dO(){ob||(ob=setInterval(async()=>{if(!sb){sb=!0;try{await i6()}catch(e){console.error("[telemetry] relay failed:",e?.message||e)}finally{sb=!1}}},r6),ob.unref?.())}import Wp from"node:fs/promises";import wO from"node:path";import c6 from"node:os";var gO=()=>process.env.BOSTRAT_STATE_DIR||wO.join(process.env.HOME||c6.tmpdir(),".bostrat"),yO=()=>wO.join(gO(),"dictation-glossary.json"),l6=100,u6=500,d6=["bostrat","globopi","codex","tmux","worktree","Deepgram","Linear","Firecracker","Tigris","WireGuard","misous","postyx","cedar","gerbil","Anthropic","Opus","Haiku","Sonnet","keyterm","monorepo","dogfood"],qp=null,ab=null,ib=Promise.resolve();function pO(){let e={},t=Date.now();for(let n of d6)e[n.toLowerCase()]={term:n,count:1,lastUsed:t,source:"seed"};return e}async function bO(){return qp||(ab??=Wp.readFile(yO(),"utf8").then(e=>JSON.parse(e)?.terms??pO()).catch(()=>pO()).then(e=>qp=e).finally(()=>ab=null),ab)}async function fO(){let e=JSON.stringify({terms:qp},null,2),t=yO(),n=`${t}.${process.pid}.tmp`;await Wp.mkdir(gO(),{recursive:!0}),await Wp.writeFile(n,e),await Wp.rename(n,t)}function p6(){return ib=ib.then(fO,fO),ib.catch(()=>{})}async function cb(){return Object.values(await bO()).sort((t,n)=>n.count-t.count||n.lastUsed-t.lastUsed)}var f6=e=>Math.max(1,Math.ceil(e.length/4));async function m6(){let e=[],t=0;for(let{term:n}of await cb()){let r=f6(n);if(!(t+r>u6)&&(e.push(n),t+=r,e.length>=l6))break}return e}async function h6(e,t){let n=await bO(),r=e.toLowerCase(),o=n[r];n[r]={term:e,count:(o?.count??0)+1,lastUsed:Date.now(),source:o?.source??t}}var mO=e=>(e||"").split(/\s+/).map(t=>t.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"")).filter(Boolean),Hp=e=>e.toLowerCase();function hO(e){return!new RegExp("\\p{L}","u").test(e)||e.length<3?!1:/^[a-z]+$/.test(e)?e.length>=4:!0}async function kO(e,t){let n=mO(e),r=mO(t);if(!n.length||!r.length)return[];let o=n.length,s=r.length,a=Array.from({length:o+1},()=>new Array(s+1).fill(0));for(let u=o-1;u>=0;u--)for(let d=s-1;d>=0;d--)a[u][d]=Hp(n[u])===Hp(r[d])?a[u+1][d+1]+1:Math.max(a[u+1][d],a[u][d+1]);let i=new Set,c=0,l=0;for(;c<o&&l<s;)Hp(n[c])===Hp(r[l])?(c++,l++):a[c+1][l]>=a[c][l+1]?c++:(hO(r[l])&&i.add(r[l]),l++);for(;l<s;l++)hO(r[l])&&i.add(r[l]);if(!i.size)return[];for(let u of i)await h6(u,"learned");return await p6(),[...i]}var cl=null;function w6(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 xO(){if(!cl)return null;let e=await Wc();if(!e||e.apiKey.slice(-6)!==cl.keyTail)return null;let{keyTail:t,...n}=cl;return n}async function vO(e,t){let n=await Wc();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 m6())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=w6(o.status,i);c.persistent&&(cl={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 cl=null,{transcript:(await o.json())?.results?.channels?.[0]?.alternatives?.[0]?.transcript??""}}fe();var lb={"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 g6(e){if(!e)return null;let t=String(e).trim();if(lb[t])return t;let n=null;for(let r of Object.keys(lb))t.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function y6(e,t={}){let n=lb[g6(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 b6(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 ll=null;async function k6(){if(!ll)return null;let e=await hp();if(!e||e.apiKey.slice(-6)!==ll.keyTail)return null;let{keyTail:t,...n}=ll;return n}async function x6(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=b6(t.status,o);s.persistent&&(ll={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}ll=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 v6={openai:x6};async function SO(){let e=await hp();return e?{configured:!0,provider:e.provider,model:e.model,voice:e.voice,problem:await k6()}:{configured:!1}}async function AO(){let e=await hp();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 v6[e.provider](e);return{provider:e.provider,model:e.model,voice:e.voice,...t}}async function TO(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=y6(t,s),i=await M(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}}Jt();var CO=Te.dirname(A6(import.meta.url)),EO=Number(process.env.PORT)||3362,Gp=Gg(process.env),NO=Number(process.env.BOSTRAT_AUTO_TRIGGER_PCT)||80,Ka=F$(process.env.BOSTRAT_ALLOW_IPS),mb=U$(process.env.BOSTRAT_VIEW_FRONT_CIDRS,Op),hb=W$(),PO=process.env.BOSTRAT_ALLOW_LAN_TOKENLESS!=="1",E=qt();E.disable("x-powered-by");E.use((e,t,n)=>{t.setHeader("x-content-type-options","nosniff"),Rp(e.headers.host)||(t.setHeader("x-frame-options","DENY"),t.setHeader("referrer-policy","strict-origin-when-cross-origin")),n()});E.use((e,t,n)=>{if(rl(e)||Ka.allowed(Ka.clientIp(e))||mb.allows(e))return n();t.status(403).type("text/plain").send("bostrat: access restricted to the allowlist")});E.use(J$);E.use(G$({token:hb,enforce:PO}));E.use("/api/mocks",qt.json({limit:"1mb"}));E.use("/api/mocks",qt.raw({type:"image/png",limit:"24mb"}));E.use("/api/mocks",qt.raw({type:["video/mp4","video/webm"],limit:"105mb"}));E.use("/api/runbooks",qt.json({limit:"1mb"}));E.use("/api/tracks/adopt",qt.json({limit:"1mb"}));E.use("/api/telemetry",qt.json({limit:"256kb"}));E.use("/api/hook",qt.json({limit:"2mb"}));E.use("/api/dictation",qt.raw({type:["audio/*","video/mp4","application/octet-stream"],limit:"32mb"}));E.use("/api/tracks/:id/upload",qt.raw({type:()=>!0,limit:"25mb"}));E.use(qt.json({limit:"64kb"}));E.get("/api/health",async(e,t)=>{t.json({ok:!0,tmuxSocket:Dt,hostTmuxAlive:await Pr(),autoTriggerPct:NO,plane:Ga?Ga.status():null})});E.get("/api/sessions",async(e,t)=>{t.json({sessions:await on()})});E.post("/api/sessions",async(e,t)=>{let{displayName:n,cwd:r}=e.body||{};if(typeof n!="string")return t.status(400).json({error:"displayName (string) required"});try{let o=await _n(n,r||void 0);t.json({ok:!0,...o})}catch(o){let s=o?.message||String(o),a=/already exists/i.test(s)?409:/must be|invalid/i.test(s)?400:500;t.status(a).json({error:s})}});E.delete("/api/sessions/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!De(n))return t.status(400).json({error:"invalid session name"});if(!await be(n))return t.status(404).json({error:"session not found"});try{await $t(n),t.json({ok:!0})}catch(r){t.status(500).json({error:`failed to kill: ${r?.message||r}`})}});E.get("/api/context/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!De(n))return t.status(400).json({error:"invalid session name"});let r=await be(n);if(!r)return t.status(404).json({error:"session not found"});let o=await bi(r.cwd,r.sessionId);if(!o)return t.json({available:!1,cwd:r.cwd,sessionId:r.sessionId||null});t.json({available:!0,...o})});E.post("/api/handoff/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!De(n))return t.status(400).json({error:"invalid session name"});try{let r=await Bx(n);t.json({ok:!0,step:r.step,file:r.file,startedAt:r.startedAt})}catch(r){t.status(409).json({error:r?.message||String(r)})}});E.get("/api/handoff/:name",(e,t)=>{let n=decodeURIComponent(e.params.name),r=fu(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 _O=10;async function DO(){let e=await he(),[t,n]=await Promise.all([tI(e),rI(e)]);return{tracks:e,views:await dw(),queuedOf:r=>as(r),jobsOf:r=>t.get(r)??[],prPendingOf:r=>n.get(r)??[]}}E.get("/api/idle-guard",async(e,t)=>{try{t.json(Hg(await DO()))}catch{t.status(500).json({busy:!0,reasons:["error"]})}});var nn=fs(),R6=gI({kind:nn}),ul=null,At=()=>ul&&["auto","prompt","off"].includes(ul)?ul:R6,fb=null,O6=Uc.has(nn),BO=async({to:e,from:t})=>!O6||cp(await Hc())?!1:(pl.arm({to:e,from:t,kind:nn}),!0);async function M6(e){let t=At();ul=e??null;let n=At();if(t!==n){if(console.log(`[self-update] policy ${t} \u2192 ${n} (${e?"plane row":"node default"})`),n!=="auto"){pl.cancel();return}fb&&await BO(fb)}}var jO=(()=>{try{return $6(import.meta.url)("../package.json").version||null}catch{return null}})(),pl=bI({isBusy:async()=>Hg(await DO()).busy,onStuck:({to:e,from:t})=>Gn({current:t,latest:e,installKind:nn,policy:At(),status:"stuck"}).catch(()=>{}),onStarted:({to:e,from:t,result:n})=>(n?.ok?Gn({current:t,latest:e,installKind:nn,policy:At(),status:"updating",reason:"auto"}):Gn({current:t,latest:e,installKind:nn,policy:At(),status:"failed",error:n?.reason})).catch(()=>{})});E.get("/api/node/self-update",async(e,t)=>{t.json({installKind:nn,policy:At(),policySource:ul?"plane":"node",current:jO,status:await Hc(),armed:pl.armed})});E.post("/api/node/self-update",async(e,t)=>{let n=typeof e.body?.to=="string"?e.body.to.trim():"";if(!/^\d+\.\d+\.\d+$/.test(n))return t.status(400).json({error:"body.to must be a release version (X.Y.Z)"});let r=await lp({to:n,kind:nn,reason:"manual"});if(r.ok)return pl.cancel(),Gn({current:r.from,latest:n,installKind:nn,policy:At(),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 LO(){try{let e=await yI();e&&await Gn({current:e.from,latest:e.to,installKind:e.kind||nn,policy:At(),status:e.status,error:e.error,reason:e.reason}),await rg({current:jO,installKind:nn,policy:At()})}catch{}}LO();setInterval(LO,3e4).unref();E.get("/api/tracks",async(e,t)=>{let n=(await he()).filter(s=>!s.transferredTo),r=n.filter(s=>s.archivedAt&&!s.archiving),o=n;if(e.query.archived!=="all"&&r.length>_O){let s=new Set([...r].sort((a,i)=>(i.archivedAt||0)-(a.archivedAt||0)).slice(0,_O).map(a=>a.id));o=n.filter(a=>!a.archivedAt||a.archiving||s.has(a.id))}t.json({tracks:o,archivedTotal:r.length,agents:Mc,agentAvailability:await Ld(),tickets:await KI()})});E.get("/api/cost",async(e,t)=>{try{let n=await he();e.query.track&&(n=n.filter(o=>o.id===e.query.track));let r=await _y(n);if(r.cursorUsage=Jh(),e.query.format==="text")return t.type("text/plain").send(w$(r));t.json(r)}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/usage/roundup",async(e,t)=>{try{let n=await $y(await he(),{window:e.query.window,from:e.query.from,to:e.query.to});if(e.query.format==="text")return t.type("text/plain").send(x$(n));t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/usage/spend",async(e,t)=>{try{let n=await E$(await he(),{window:e.query.window,from:e.query.from,to:e.query.to});n.cursorUsage=Jh(),n.subscriptionMonthlyUsd=Number(process.env.BOSTRAT_SUBSCRIPTION_MONTHLY_USD)||null,n.caps=Li(),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/usage/caps",(e,t)=>{t.json(Li())});E.post("/api/usage/caps",async(e,t)=>{try{t.json(await _u(e.body?.caps??{},{source:"local"}))}catch(n){t.status(400).json({error:n?.message||String(n)})}});E.get("/api/usage/limits",async(e,t)=>{try{let n=e.query.fresh==="1"||e.query.fresh==="true";t.json(await P$(await he(),{fresh:n}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/hook",async(e,t)=>{try{let{mode:n,target:r}=await Ib(e.get(Xn),{byToken:Cc,legacy:()=>rc(e.body?.session_id,e.body?.cwd)});if(n==="refused")return Xa("refused",{reason:"unknown-token",hook:e.body?.hook_event_name}),t.json({ok:!1,error:"unknown hook token"});if(n==="legacy-denied")return Xa("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&&Xa("mismatch",{track:r.track.id,box:r.box.name}),Xa(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 f$(e.body||{},()=>r);e.body?.hook_event_name==="Stop"&&r?.box?.cwd&&Ol(r.box.cwd),t.json({ok:!0,events:o.length})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});E.get("/api/git/trailers",async(e,t)=>{t.type("text/plain");try{let n=await Cc(e.get(Xn));if(!n?.track||!n?.box)return t.status(204).end();t.send((await RA(n.track,n.box)).join(`
758
762
  `)+`
759
- `)}catch{t.status(204).end()}});S.post("/api/git/committed",async(e,t)=>{try{let n=await _c(e.get(Vn));if(!n?.track||!n?.box)return t.json({ok:!1,error:"unknown hook token"});let r=String(e.body?.sha||"").trim();if(!/^[0-9a-f]{7,40}$/i.test(r))return t.json({ok:!1,error:"sha required"});t.json({ok:!0});let o=n.box.cwd?Te.resolve(n.box.cwd):null,s=typeof e.body?.cwd=="string"&&e.body.cwd?Te.resolve(e.body.cwd):null,a=o&&s&&(s===o||s.startsWith(o+Te.sep))?s:o;wT(n.track,n.box,r,{cwd:a}).catch(i=>console.warn(`[rework] ${n.track.id}: recordCommit failed: ${i?.message||i}`))}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});S.post("/api/tracks/:id/rework-cause",async(e,t)=>{try{let n=await se(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let{sha:r,cause:o}=e.body||{};t.json({ok:!0,event:await yT(n,String(r||""),String(o||""))})}catch(n){let r=n?.message||String(n);t.status(/unknown rework/i.test(r)?404:/already answered/i.test(r)?409:400).json({error:r})}});S.post("/api/tracks/:id/rework-cause/retract",async(e,t)=>{try{let n=await se(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,event:await bT(n,String(e.body?.sha||""))})}catch(n){let r=n?.message||String(n);t.status(/no standing answer/i.test(r)?409:400).json({error:r})}});S.get("/api/usage/rework",async(e,t)=>{try{t.json(await p$(await we(),{window:e.query.window,from:e.query.from,to:e.query.to}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.post("/api/telemetry",async(e,t)=>{try{if(!zR(Da.clientIp(e)))return t.json({ok:!0,dropped:!0});let n=await GR(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 Jn(),r=new Set((await Promise.all(n.map(a=>_e(a.path)))).filter(Boolean).map(a=>a.toLowerCase())),s=((await za()).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 yl(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:gl(),calls:NS(),latency:jS(),webhook:gR()})});S.post("/api/github/event",Ut.json({limit:"64kb"}),(e,t)=>{let n=hR(e.body,{onAccept:r=>CR(r)});if(!n.ok)return t.status(400).json({error:n.error});t.json({ok:!0,duplicate:n.duplicate})});S.post("/api/github/refresh",(e,t)=>{vb(),t.json({ok:!0})});S.get("/api/gmail/search",async(e,t)=>{try{let n=await v$(String(e.query.q||""),{max:Number(e.query.max)||10});t.json({messages:n})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});S.get("/api/gmail/messages/:id",async(e,t)=>{try{t.json({message:await S$(String(e.params.id))})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});async function il({repo:e=null,number:t=null,branch:n=null}){let r=e?await _e(e):null;if(r&&t!=null){let s=await at(r,t),a=s&&await se(s.trackId);if(a)return a}if(!n)return null;let o=await we();return Wu(o,n,s=>Ku(s,{branch:n,repo:e,slug:r}))}async function AO({repo:e=null,number:t=null,branch:n=null}){let r=await il({repo:e,number:t,branch:n}).catch(()=>null);if(r&&!De(r))return r;if(!n)return null;let o=e?await _e(e).catch(()=>null):null,s=await we();return Wu(s,n,a=>!De(a)&&Ku(a,{branch:n,repo:e,slug:o}))}async function kn(e,{number:t,url:n=null,title:r=null,branch:o=null,repo:s=null,track:a=null,extra:i={}}){let c=a||await il({repo:s,number:t,branch:o}).catch(()=>null);if(!c)return;let l=i.repo??(s?await _e(s).catch(()=>null):null);await M({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 f6(e){let t=(await we()).filter(n=>!De(n));for(let n of e??[]){if(!n.prs?.length)continue;let r=await _e(n.path);if(r)for(let o of n.prs){if(await at(r,o.number))continue;let s=await Wu(t,o.headRefName,a=>Ku(a,{branch:o.headRefName,repo:n.path,slug: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 KS();await f6(n.repos).catch(()=>{}),await yp(n.repos).catch(()=>{}),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.post("/api/git/prs/merge",async(e,t)=>{let{repo:n,number:r,method:o,auto:s,update:a,archive:i,notify:c,headRefName:l,title:u,url:d}=e.body||{},p=null,f=null,w=null;try{if(s){let x=o||"merge";if(!Li.has(x))throw new Error(`invalid merge method: ${x}`);let b=Number(r);if(!Number.isInteger(b)||b<=0)throw new Error("invalid PR number");let O=await _e((await or(n)).path);if(!O)throw new Error("repo has no GitHub remote");let $=await il({repo:n,number:b,branch:l}).catch(()=>null);if(!$)throw new Error("auto-merge needs a Track to watch this PR \u2014 none owns it");if(p=$,f=await vd($,"merge",{count:1,summary:`arming auto-merge on PR #${b}`}),a&&await Fi(n,b),await Mt({repo:O,number:b,trackId:$.id,url:d,headRef:l,title:u,source:"matched"}).catch(()=>{}),!await Pi(O,b,{merge:{method:x}}))throw new Error("couldn't record the auto-merge arm");return await Bo(O,b,i===!0),await jo(O,b,c===!0&&i!==!0),Vt(),await kn("auto-armed",{number:b,url:d,title:u,branch:l,repo:n,track:$,...a?{extra:{updated:!0}}:{}}),t.json({ok:!0,number:b,auto:!0})}p=await il({repo:n,number:r,branch:l}).catch(()=>null),p&&(f=await vd(p,"merge",{count:1,summary:`merging PR #${r}`}));let m=await ea(n,r,{method:o||"squash"});await kn("merged",{number:m.number,url:d,title:u,branch:l,repo:n});let g=await _e(n).catch(()=>null),y=!1;if(g&&(i===!0&&await Bo(g,m.number,!0).catch(()=>{}),c===!0&&i!==!0&&await jo(g,m.number,!0).catch(()=>{}),await ir(g,m.number).catch(()=>{}),await Qo(g,m.number).catch(()=>{}),y=await ar(g,m.number).catch(()=>!1),await Vr(g,m.number,"merged").catch(()=>{})),i===!0&&!y){let x=await il({repo:n,number:m.number,branch:l}).catch(()=>null);x&&!x.archivedAt&&await Zo(x.id).catch(()=>{})}t.json(m)}catch(m){w=m;let g=m?.message||String(m),y=/invalid|unknown repo|required|needs a Track|no GitHub remote/i.test(g)?400:502;t.status(y).json({error:g})}finally{p&&f&&await Tw(p,f,w?"failed":"completed",w).catch(()=>{})}});S.post("/api/git/prs/disarm-auto",async(e,t)=>{let{repo:n,number:r,headRefName:o,title:s,url:a}=e.body||{};try{let i=Number(r);if(!Number.isInteger(i)||i<=0)throw new Error("invalid PR number");let c=await _e((await or(n)).path).catch(()=>null),l=c?await Di(c,i).catch(()=>null):null;try{await eh(n,i)}catch(u){if(!l)throw u}Vt(),await kn("auto-canceled",{number:i,url:a,title:s,branch:o,repo:n}),t.json({ok:!0,number:i})}catch(i){let c=i?.message||String(i),l=/invalid|unknown repo|required/i.test(c)?400:502;t.status(l).json({error:c})}});S.post("/api/git/prs/merge-all",async(e,t)=>{let{repo:n,method:r}=e.body||{};try{let o=await _e(n).catch(()=>null),s=await YS(n,{method:r||"merge",onMerged:a=>{kn("merged",{number:a.number,url:a.url,title:a.title,branch:a.headRefName,repo:n}),o&&ir(o,a.number).catch(()=>{}).then(()=>Qo(o,a.number)).catch(()=>{}).then(()=>ar(o,a.number)).catch(()=>{}).then(()=>Vr(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:JS()})});S.post("/api/git/prs/merge-track",async(e,t)=>{let{trackId:n,update:r,archive:o,notify:s,method:a}=e.body||{},i=null,c=null,l=null;try{let u=a||"merge";if(!Li.has(u))throw new Error(`invalid merge method: ${u}`);if(!n)return t.status(400).json({error:"trackId required"});let d=await se(n);if(!d)return t.status(404).json({error:`Track ${n} isn't on this node`});i=d;let p=(await un()).filter(m=>m.trackId===d.id&&m.state!=="merged"&&m.state!=="closed").sort(Ui);if(!p.length)return t.status(409).json({error:"no open PRs on this Track"});c=await vd(d,"merge",{count:p.length,summary:p.length===1?"merging 1 PR":`merging ${p.length} PRs`});for(let m of p)await Bo(m.repo,m.number,o===!0).catch(()=>{}),await jo(m.repo,m.number,s===!0&&o!==!0).catch(()=>{});let f=[],w=[];for(let m of p){let g={repo:m.repo,number:m.number,ok:!0,action:"armed"};f.push(g);try{let y=await Fo(m.repo);if(!y)throw new Error(`no local checkout for ${m.repo}`);let x=await Qs(y,m.number);w.push({r:g,l:m,repoPath:y,pr:x,plan:GS(x,{update:r!==!1})})}catch(y){g.ok=!1,g.action="failed",g.reason=y?.message||String(y)}}for(let{r:m,l:g,repoPath:y,pr:x,plan:b}of zS(w))try{if(b.action==="skip")m.action="skipped",m.reason=b.reason;else if(b.action==="merge")await ea(y,g.number,{method:u}),await kn("merged",{number:g.number,url:x.url,title:x.title,branch:x.headRefName,repo:y,track:d}),await ir(g.repo,g.number).catch(()=>{}),await Qo(g.repo,g.number).catch(()=>{}),await ar(g.repo,g.number).catch(()=>{}),await Vr(g.repo,g.number,"merged").catch(()=>{}),m.action="merged";else{if(b.action==="update-arm"&&(await Fi(y,g.number).catch(()=>{}),m.action="updated-armed"),!await Pi(g.repo,g.number,{merge:{method:u}}))throw new Error("couldn't record the auto-merge arm");await kn("auto-armed",{number:g.number,url:x.url,title:x.title,branch:x.headRefName,repo:y,track:d,...m.action==="updated-armed"?{extra:{updated:!0}}:{}})}}catch(O){m.ok=!1,m.action="failed",m.reason=O?.message||String(O)}if(Vt(),!f.some(m=>m.ok)){if(o===!0)for(let m of p)await Bo(m.repo,m.number,!1).catch(()=>{});if(s===!0&&o!==!0)for(let m of p)await jo(m.repo,m.number,!1).catch(()=>{});return t.status(502).json({error:f.map(m=>`${m.repo}#${m.number}: ${m.reason}`).join("; "),results:f})}t.json({ok:!0,trackId:d.id,results:f})}catch(u){l=u;let d=u?.message||String(u),p=/invalid|required/i.test(d)?400:502;t.status(p).json({error:d})}finally{i&&c&&await Tw(i,c,l?"failed":"completed",l).catch(()=>{})}});S.post("/api/git/prs/disarm-track",async(e,t)=>{let{trackId:n}=e.body||{};try{if(!n)return t.status(400).json({error:"trackId required"});let r=await se(n);if(!r)return t.status(404).json({error:`Track ${n} isn't on this node`});let o=(await un()).filter(a=>a.trackId===r.id&&a.state!=="merged"&&a.state!=="closed"),s=[];for(let a of o){let i=await Di(a.repo,a.number).catch(()=>null),c=await Fo(a.repo).catch(()=>null);c&&await eh(c,a.number).catch(()=>{}),i&&(await kn("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}))}Vt(),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 se(n);if(!i)return t.status(404).json({error:`Track ${n} isn't on this node`});if(i.workspace?.kind==="multi"){let u=Bt(i.workspace),d,p=Array.isArray(a)?a.filter(Boolean):[];if(p.length)d=p.map(m=>{let g=u.find(y=>y.name===m||y.repo===m||y.base===m||y.dir===m);if(!g)throw new Error(`invalid repo "${m}" \u2014 not tagged on this Track`);return g});else if(d=await Ko(i),!d.length)return t.status(409).json({error:"no tagged repo has work to ship"});let f=[];for(let m of d)try{let g=await nh(m.dir,{title:r,body:o,base:s}),y=m.repo||await _e(m.dir).catch(()=>null);y&&g.number&&await Mt({repo:y,number:g.number,trackId:i.id,url:g.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await kn("opened",{number:g.number,url:g.url,title:r,track:i,branch:i.workspace?.branch,extra:{repo:y??m.name}}),f.push({repo:m.name,slug:y??null,ok:!0,url:g.url,number:g.number})}catch(g){f.push({repo:m.name,slug:m.repo??null,ok:!1,error:g?.message||String(g)})}let w=f.filter(m=>m.ok);return w.length?t.json({ok:!0,multi:!0,results:f,url:w[0].url,number:w[0].number}):t.status(502).json({error:f.map(m=>`${m.repo}: ${m.error}`).join("; "),results:f})}let c=await nh(i.cwd,{title:r,body:o,base:s}),l=await _e(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 kn("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 se(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await Ko(n),o=new Map(r.map(a=>[a.base,a])),s=Bt(n.workspace).map(a=>{let i=o.get(a.base);return{name:a.name,base:a.base,baseRef:a.baseRef??null,repo:a.repo??null,dirty:i?.dirty??!1,ahead:i?.ahead??0,changed:!!i}});t.json({repos:s,branch:n.workspace?.branch??null,kind:n.workspace?.kind??null})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.post("/api/tracks/:id/repos",async(e,t)=>{let{repo:n}=e.body||{};try{if(!n||typeof n!="string")return t.status(400).json({error:"repo (path or owner/name) required"});let r=await ng(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 rg(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 Qs(n,r),s=await _e(n).catch(()=>null),a=await AO({repo:n,number:r,branch:o.headRefName});if(!a)return t.status(404).json({error:`no active Track owns PR #${o.number} (branch "${o.headRefName}")`});let i=Bt(a.workspace).find(y=>y.base===n||s&&y.repo===s)??null,c=a.workspace?.kind==="multi",l=await XS(n,o.number);if(!l.length)return t.status(409).json({error:"no failing checks on this PR"});let u=c&&i?Te.join("ci",i.name):"ci",d=Te.join(a.cwd,".bostrat",u),p=Te.join(".bostrat",u,`pr-${o.number}-fail.log`);await gt.promises.mkdir(d,{recursive:!0}),await gt.promises.writeFile(Te.join(a.cwd,p),l.map(y=>`\u2550\u2550\u2550\u2550 ${y.name}${y.link?` \xB7 ${y.link}`:""} \u2550\u2550\u2550\u2550
763
+ `)}catch{t.status(204).end()}});E.post("/api/git/committed",async(e,t)=>{try{let n=await Cc(e.get(Xn));if(!n?.track||!n?.box)return t.json({ok:!1,error:"unknown hook token"});let r=String(e.body?.sha||"").trim();if(!/^[0-9a-f]{7,40}$/i.test(r))return t.json({ok:!1,error:"sha required"});t.json({ok:!0});let o=n.box.cwd?Te.resolve(n.box.cwd):null,s=typeof e.body?.cwd=="string"&&e.body.cwd?Te.resolve(e.body.cwd):null,a=o&&s&&(s===o||s.startsWith(o+Te.sep))?s:o;OA(n.track,n.box,r,{cwd:a}).catch(i=>console.warn(`[rework] ${n.track.id}: recordCommit failed: ${i?.message||i}`))}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});E.post("/api/tracks/:id/rework-cause",async(e,t)=>{try{let n=await ce(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let{sha:r,cause:o}=e.body||{};t.json({ok:!0,event:await CA(n,String(r||""),String(o||""))})}catch(n){let r=n?.message||String(n);t.status(/unknown rework/i.test(r)?404:/already answered/i.test(r)?409:400).json({error:r})}});E.post("/api/tracks/:id/rework-cause/retract",async(e,t)=>{try{let n=await ce(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,event:await NA(n,String(e.body?.sha||""))})}catch(n){let r=n?.message||String(n);t.status(/no standing answer/i.test(r)?409:400).json({error:r})}});E.get("/api/usage/rework",async(e,t)=>{try{t.json(await _$(await he(),{window:e.query.window,from:e.query.from,to:e.query.to}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/telemetry",async(e,t)=>{try{if(!cO(Ka.clientIp(e)))return t.json({ok:!0,dropped:!0});let n=await iO(e.body||{});t.json({ok:!0,events:n})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});E.get("/api/repos",async(e,t)=>{try{let n=await Zn(),r=new Set((await Promise.all(n.map(a=>_e(a.path)))).filter(Boolean).map(a=>a.toLowerCase())),s=((await ti()).repos||[]).filter(a=>!r.has(String(a.slug).toLowerCase())).map(a=>({slug:a.slug,name:a.slug.split("/")[1],branch:a.defaultBranch||null,private:!!a.private,remote:!0}));t.json({repos:[...n,...s]})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/github/token",async(e,t)=>{try{t.json(await vl(String(e.query.repo||"")))}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});E.get("/api/github/status",(e,t)=>{t.json({configured:xl(),calls:JS(),latency:QS(),webhook:MR()})});E.post("/api/github/event",qt.json({limit:"64kb"}),(e,t)=>{let n=RR(e.body,{onAccept:r=>VR(r)});if(!n.ok)return t.status(400).json({error:n.error});t.json({ok:!0,duplicate:n.duplicate})});E.post("/api/github/refresh",(e,t)=>{jb(),t.json({ok:!0})});E.get("/api/gmail/search",async(e,t)=>{try{let n=await B$(String(e.query.q||""),{max:Number(e.query.max)||10});t.json({messages:n})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});E.get("/api/gmail/messages/:id",async(e,t)=>{try{t.json({message:await j$(String(e.params.id))})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});async function dl({repo:e=null,number:t=null,branch:n=null}){let r=e?await _e(e):null;if(r&&t!=null){let s=await at(r,t),a=s&&await ce(s.trackId);if(a)return a}if(!n)return null;let o=await he();return Yu(o,n,s=>Xu(s,{branch:n,repo:e,slug:r}))}async function FO({repo:e=null,number:t=null,branch:n=null}){let r=await dl({repo:e,number:t,branch:n}).catch(()=>null);if(r&&!je(r))return r;if(!n)return null;let o=e?await _e(e).catch(()=>null):null,s=await he();return Yu(s,n,a=>!je(a)&&Xu(a,{branch:n,repo:e,slug:o}))}async function vn(e,{number:t,url:n=null,title:r=null,branch:o=null,repo:s=null,track:a=null,extra:i={}}){let c=a||await dl({repo:s,number:t,branch:o}).catch(()=>null);if(!c)return;let l=i.repo??(s?await _e(s).catch(()=>null):null);await M({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 C6(e){let t=(await he()).filter(n=>!je(n));for(let n of e??[]){if(!n.prs?.length)continue;let r=await _e(n.path);if(r)for(let o of n.prs){if(await at(r,o.number))continue;let s=await Yu(t,o.headRefName,a=>Xu(a,{branch:o.headRefName,repo:n.path,slug:r}));s&&await Bt({repo:r,number:o.number,trackId:s.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"})}}}E.get("/api/git/prs",async(e,t)=>{try{let n=await aA();await C6(n.repos).catch(()=>{}),await Np(n.repos).catch(()=>{}),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/git/prs/merge",async(e,t)=>{let{repo:n,number:r,method:o,auto:s,update:a,archive:i,notify:c,headRefName:l,title:u,url:d}=e.body||{},p=null,f=null,w=null;try{if(s){let x=o||"merge";if(!Ki.has(x))throw new Error(`invalid merge method: ${x}`);let b=Number(r);if(!Number.isInteger(b)||b<=0)throw new Error("invalid PR number");let R=await _e((await cr(n)).path);if(!R)throw new Error("repo has no GitHub remote");let _=await dl({repo:n,number:b,branch:l}).catch(()=>null);if(!_)throw new Error("auto-merge needs a Track to watch this PR \u2014 none owns it");if(p=_,f=await Id(_,"merge",{count:1,summary:`arming auto-merge on PR #${b}`}),a&&await Gi(n,b),await Bt({repo:R,number:b,trackId:_.id,url:d,headRef:l,title:u,source:"matched"}).catch(()=>{}),!await Ui(R,b,{merge:{method:x}}))throw new Error("couldn't record the auto-merge arm");return await zo(R,b,i===!0),await Vo(R,b,c===!0&&i!==!0),Xt(),await vn("auto-armed",{number:b,url:d,title:u,branch:l,repo:n,track:_,...a?{extra:{updated:!0}}:{}}),t.json({ok:!0,number:b,auto:!0})}p=await dl({repo:n,number:r,branch:l}).catch(()=>null),p&&(f=await Id(p,"merge",{count:1,summary:`merging PR #${r}`}));let m=await la(n,r,{method:o||"squash"});await vn("merged",{number:m.number,url:d,title:u,branch:l,repo:n});let g=await _e(n).catch(()=>null),y=!1;if(g&&(i===!0&&await zo(g,m.number,!0).catch(()=>{}),c===!0&&i!==!0&&await Vo(g,m.number,!0).catch(()=>{}),await dr(g,m.number).catch(()=>{}),await ds(g,m.number).catch(()=>{}),y=await ur(g,m.number).catch(()=>!1),await Qr(g,m.number,"merged").catch(()=>{})),i===!0&&!y){let x=await dl({repo:n,number:m.number,branch:l}).catch(()=>null);x&&!x.archivedAt&&await us(x.id).catch(()=>{})}t.json(m)}catch(m){w=m;let g=m?.message||String(m),y=/invalid|unknown repo|required|needs a Track|no GitHub remote/i.test(g)?400:502;t.status(y).json({error:g})}finally{p&&f&&await Uw(p,f,w?"failed":"completed",w).catch(()=>{})}});E.post("/api/git/prs/disarm-auto",async(e,t)=>{let{repo:n,number:r,headRefName:o,title:s,url:a}=e.body||{};try{let i=Number(r);if(!Number.isInteger(i)||i<=0)throw new Error("invalid PR number");let c=await _e((await cr(n)).path).catch(()=>null),l=c?await Hi(c,i).catch(()=>null):null;try{await wh(n,i)}catch(u){if(!l)throw u}Xt(),await vn("auto-canceled",{number:i,url:a,title:s,branch:o,repo:n}),t.json({ok:!0,number:i})}catch(i){let c=i?.message||String(i),l=/invalid|unknown repo|required/i.test(c)?400:502;t.status(l).json({error:c})}});E.post("/api/git/prs/merge-all",async(e,t)=>{let{repo:n,method:r}=e.body||{};try{let o=await _e(n).catch(()=>null),s=await dA(n,{method:r||"merge",onMerged:a=>{vn("merged",{number:a.number,url:a.url,title:a.title,branch:a.headRefName,repo:n}),o&&dr(o,a.number).catch(()=>{}).then(()=>ds(o,a.number)).catch(()=>{}).then(()=>ur(o,a.number)).catch(()=>{}).then(()=>Qr(o,a.number,"merged")).catch(()=>{})}});t.json(s)}catch(o){let s=o?.message||String(o),a=/already running/i.test(s)?409:/invalid|unknown repo|no PRs ready/i.test(s)?400:502;t.status(a).json({error:s})}});E.get("/api/git/prs/merge-all",(e,t)=>{t.json({jobs:uA()})});E.post("/api/git/prs/merge-track",async(e,t)=>{let{trackId:n,update:r,archive:o,notify:s,method:a}=e.body||{},i=null,c=null,l=null;try{let u=a||"merge";if(!Ki.has(u))throw new Error(`invalid merge method: ${u}`);if(!n)return t.status(400).json({error:"trackId required"});let d=await ce(n);if(!d)return t.status(404).json({error:`Track ${n} isn't on this node`});i=d;let p=(await dn()).filter(m=>m.trackId===d.id&&m.state!=="merged"&&m.state!=="closed").sort(zi);if(!p.length)return t.status(409).json({error:"no open PRs on this Track"});c=await Id(d,"merge",{count:p.length,summary:p.length===1?"merging 1 PR":`merging ${p.length} PRs`});for(let m of p)await zo(m.repo,m.number,o===!0).catch(()=>{}),await Vo(m.repo,m.number,s===!0&&o!==!0).catch(()=>{});let f=[],w=[];for(let m of p){let g={repo:m.repo,number:m.number,ok:!0,action:"armed"};f.push(g);try{let y=await Yo(m.repo);if(!y)throw new Error(`no local checkout for ${m.repo}`);let x=await ca(y,m.number);w.push({r:g,l:m,repoPath:y,pr:x,plan:iA(x,{update:r!==!1})})}catch(y){g.ok=!1,g.action="failed",g.reason=y?.message||String(y)}}for(let{r:m,l:g,repoPath:y,pr:x,plan:b}of cA(w))try{if(b.action==="skip")m.action="skipped",m.reason=b.reason;else if(b.action==="merge")await la(y,g.number,{method:u}),await vn("merged",{number:g.number,url:x.url,title:x.title,branch:x.headRefName,repo:y,track:d}),await dr(g.repo,g.number).catch(()=>{}),await ds(g.repo,g.number).catch(()=>{}),await ur(g.repo,g.number).catch(()=>{}),await Qr(g.repo,g.number,"merged").catch(()=>{}),m.action="merged";else{if(b.action==="update-arm"&&(await Gi(y,g.number).catch(()=>{}),m.action="updated-armed"),!await Ui(g.repo,g.number,{merge:{method:u}}))throw new Error("couldn't record the auto-merge arm");await vn("auto-armed",{number:g.number,url:x.url,title:x.title,branch:x.headRefName,repo:y,track:d,...m.action==="updated-armed"?{extra:{updated:!0}}:{}})}}catch(R){m.ok=!1,m.action="failed",m.reason=R?.message||String(R)}if(Xt(),!f.some(m=>m.ok)){if(o===!0)for(let m of p)await zo(m.repo,m.number,!1).catch(()=>{});if(s===!0&&o!==!0)for(let m of p)await Vo(m.repo,m.number,!1).catch(()=>{});return t.status(502).json({error:f.map(m=>`${m.repo}#${m.number}: ${m.reason}`).join("; "),results:f})}t.json({ok:!0,trackId:d.id,results:f})}catch(u){l=u;let d=u?.message||String(u),p=/invalid|required/i.test(d)?400:502;t.status(p).json({error:d})}finally{i&&c&&await Uw(i,c,l?"failed":"completed",l).catch(()=>{})}});E.post("/api/git/prs/disarm-track",async(e,t)=>{let{trackId:n}=e.body||{};try{if(!n)return t.status(400).json({error:"trackId required"});let r=await ce(n);if(!r)return t.status(404).json({error:`Track ${n} isn't on this node`});let o=(await dn()).filter(a=>a.trackId===r.id&&a.state!=="merged"&&a.state!=="closed"),s=[];for(let a of o){let i=await Hi(a.repo,a.number).catch(()=>null),c=await Yo(a.repo).catch(()=>null);c&&await wh(c,a.number).catch(()=>{}),i&&(await vn("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}))}Xt(),t.json({ok:!0,trackId:r.id,canceled:s})}catch(r){let o=r?.message||String(r),s=/invalid|required/i.test(o)?400:502;t.status(s).json({error:o})}});E.post("/api/git/prs/open",async(e,t)=>{let{trackId:n,title:r,body:o,base:s,repos:a}=e.body||{};try{if(!n)return t.status(400).json({error:"trackId required"});let i=await ce(n);if(!i)return t.status(404).json({error:`Track ${n} isn't on this node`});if(i.workspace?.kind==="multi"){let u=Nt(i.workspace),d,p=Array.isArray(a)?a.filter(Boolean):[];if(p.length)d=p.map(m=>{let g=u.find(y=>y.name===m||y.repo===m||y.base===m||y.dir===m);if(!g)throw new Error(`invalid repo "${m}" \u2014 not tagged on this Track`);return g});else if(d=await ts(i),!d.length)return t.status(409).json({error:"no tagged repo has work to ship"});let f=[];for(let m of d)try{let g=await yh(m.dir,{title:r,body:o,base:s}),y=m.repo||await _e(m.dir).catch(()=>null);y&&g.number&&await Bt({repo:y,number:g.number,trackId:i.id,url:g.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await vn("opened",{number:g.number,url:g.url,title:r,track:i,branch:i.workspace?.branch,extra:{repo:y??m.name}}),f.push({repo:m.name,slug:y??null,ok:!0,url:g.url,number:g.number})}catch(g){f.push({repo:m.name,slug:m.repo??null,ok:!1,error:g?.message||String(g)})}let w=f.filter(m=>m.ok);return w.length?t.json({ok:!0,multi:!0,results:f,url:w[0].url,number:w[0].number}):t.status(502).json({error:f.map(m=>`${m.repo}: ${m.error}`).join("; "),results:f})}let c=await yh(i.cwd,{title:r,body:o,base:s}),l=await _e(i.cwd).catch(()=>null);l&&c.number&&await Bt({repo:l,number:c.number,trackId:i.id,url:c.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await vn("opened",{number:c.number,url:c.url,title:r,track:i,branch:i.workspace?.branch,extra:{...l?{repo:l}:{}}}),t.json(c)}catch(i){let c=i?.message||String(i),l=/required|invalid/i.test(c)?400:502;t.status(l).json({error:c})}});E.get("/api/tracks/:id/repos",async(e,t)=>{try{let n=await ce(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await ts(n),o=new Map(r.map(a=>[a.base,a])),s=Nt(n.workspace).map(a=>{let i=o.get(a.base);return{name:a.name,base:a.base,baseRef:a.baseRef??null,repo:a.repo??null,dirty:i?.dirty??!1,ahead:i?.ahead??0,changed:!!i}});t.json({repos:s,branch:n.workspace?.branch??null,kind:n.workspace?.kind??null})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/tracks/:id/repos",async(e,t)=>{let{repo:n}=e.body||{};try{if(!n||typeof n!="string")return t.status(400).json({error:"repo (path or owner/name) required"});let r=await qd(e.params.id,n);t.json({ok:!0,added:{name:r.name,base:r.base,baseRef:r.baseRef??null,repo:r.repo??null}})}catch(r){let o=r?.message||String(r),s=/not found/i.test(o)?404:/already tagged|needs a multi|not a usable|archived|required/i.test(o)?400:502;t.status(s).json({error:o})}});E.delete("/api/tracks/:id/repos/:name",async(e,t)=>{try{let n=await Kd(e.params.id,e.params.name);t.json({ok:!0,...n})}catch(n){let r=n?.message||String(n),o=/track .* not found/i.test(r)?404:/has work|still running|last repo/i.test(r)?409:/needs a multi|not tagged/i.test(r)?400:502;t.status(o).json({error:r})}});E.post("/api/tracks/:id/reshape",async(e,t)=>{let{repos:n,skipPermissions:r}=e.body||{};try{let o=await bg(e.params.id,n,{skipPermissions:r!==!1});t.status(o.finishedAt?200:202).json({ok:!0,...UO(o)})}catch(o){let s=o?.message||String(o),a=o?.status||(/not found/i.test(s)?404:/has work|still running|already|running|archived|last repo/i.test(s)?409:/required|not a usable|tagged twice/i.test(s)?400:502);t.status(a).json({error:s})}});E.get("/api/tracks/:id/reshape",(e,t)=>{t.json(UO(yg(e.params.id))??{running:!1})});function UO(e){return e?{running:!e.finishedAt,step:e.step,error:e.error??null,inPlace:e.inPlace===!0,added:e.added??[],removed:e.removed??[],scratch:e.scratch===!0,views:e.views??0,checkpoint:e.checkpoint??null,startedAt:e.startedAt??null,finishedAt:e.finishedAt??null}:null}E.post("/api/git/prs/fix",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await ca(n,r),s=await _e(n).catch(()=>null),a=await FO({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=Nt(a.workspace).find(y=>y.base===n||s&&y.repo===s)??null,c=a.workspace?.kind==="multi",l=await pA(n,o.number);if(!l.length)return t.status(409).json({error:"no failing checks on this PR"});let u=c&&i?Te.join("ci",i.name):"ci",d=Te.join(a.cwd,".bostrat",u),p=Te.join(".bostrat",u,`pr-${o.number}-fail.log`);await yt.promises.mkdir(d,{recursive:!0}),await yt.promises.writeFile(Te.join(a.cwd,p),l.map(y=>`\u2550\u2550\u2550\u2550 ${y.name}${y.link?` \xB7 ${y.link}`:""} \u2550\u2550\u2550\u2550
760
764
  ${y.log??"(no fetchable log \u2014 see link)"}
761
765
  `).join(`
762
- `));let f=l.map(y=>y.name).join(", "),w=c&&i?` in the ${i.name}/ checkout`:"",m=await Dt(a.id,`CI is red on PR #${o.number} "${o.title}" (${o.url}) \u2014 branch ${o.headRefName}${w}. Failing check${l.length===1?"":"s"}: ${f}. The failure log is at ${p} in this ${c?"workspace":"worktree"} \u2014 read it, fix the root cause${c&&i?` in ${i.name}/`:""}, run the relevant tests locally, then commit and push to update the PR.`,{kind:"ci-fix"}),g=s;g&&(await Mt({repo:g,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await wS(g,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await kn("fix-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{checks:l.map(y=>y.name)}}),t.json({ok:!0,leadBox:m.leadBox,queued:!!m.queued,checks:l.map(y=>y.name),log:p})}catch(o){let s=o?.message||String(o),a=/unknown repo|invalid|required/i.test(s)?400:/not found|no active Track/i.test(s)?404:502;t.status(a).json({error:s})}});S.post("/api/git/prs/reconcile",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await Qs(n,r);if(o.mergeable!=="CONFLICTING")return t.status(409).json({error:"this PR does not conflict with its base branch"});let s=await _e(n).catch(()=>null),a=await AO({repo:n,number:r,branch:o.headRefName});if(!a)return t.status(404).json({error:`no active Track owns PR #${o.number} (branch "${o.headRefName}")`});let i=Bt(a.workspace).find(d=>d.base===n||s&&d.repo===s)??null,c=a.workspace?.kind==="multi"&&i?` In the ${i.name}/ checkout:`:"",l=await Dt(a.id,`PR #${o.number} "${o.title}" (${o.url}) \u2014 branch ${o.headRefName} \u2014 has merge conflicts with ${o.baseRefName}.${c} Bring ${o.baseRefName} into this branch (fetch origin, then merge origin/${o.baseRefName} \u2014 don't rebase this pushed PR branch), and resolve every conflict so that BOTH sides' intent is preserved. Run the relevant tests, then commit and push to update the PR. If any conflict is a genuine ambiguity \u2014 where you can't confidently tell which side's behavior should win, or reconciling would drop work from either side \u2014 STOP and ask me here rather than guessing, laying out the specific choice and your recommendation.`,{kind:"reconcile"}),u=s;u&&(await Mt({repo:u,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await gS(u,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await kn("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=Gr.filter(a=>e.body.actions.includes(a)),!o.length)return t.status(400).json({error:"actions must include commit, rebase, push and/or pr"})}else if(r==="pr")o=["commit","push","pr"];else if(r==="push")o=["commit","push"];else if(r!=="dismiss")return t.status(400).json({error:'offerId and actions ["commit"|"rebase"|"push"|"pr"] (or action "dismiss") required'});if(!n)return t.status(400).json({error:"offerId required"});let s=o!=null&&e.body?.notify===!0;await eo(`pr:${e.params.id}:${n}`,async()=>{let a=await se(e.params.id);if(!a)return t.status(404).json({error:"track not found"});let i=await K(a),c=i.find(d=>d.type==="pr.offered"&&d.payload?.offerId===n);if(!c)return t.status(404).json({error:"unknown offer"});if(i.some(d=>d.type==="pr.offer.answered"&&d.payload?.offerId===n))return t.status(409).json({error:"offer already answered"});if(o?.includes("pr")){let d=await Ly(a,c,{actions:o,notify:s});if(d)return t.json({ok:!0,offerId:n,action:"pr-exists",actions:o,notify:s,existingPr:d.pr})}let l=null;o&&(l=await Dt(a.id,Js(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 M({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&&Xw(a.id,{actions:o}),t.json({ok:!0,offerId:n,action:u,actions:o,notify:s,queued:!!l?.queued})})}catch(o){let s=o?.message||String(o),a=/required|invalid/i.test(s)?400:/already answered|not found|not running|archived/i.test(s)?409:502;t.status(a).json({error:s})}});S.post("/api/tracks/:id/pr-exists",async(e,t)=>{let{offerId:n,choice:r}=e.body||{};try{let o=await se(e.params.id);if(!o)return t.status(404).json({error:"track not found"});let{say:s}=await Fy(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 ll=e=>t=>({...t,url:D$(t,e.headers)});S.get("/api/views",async(e,t)=>{try{let n=await Jh({trackId:e.query.track||void 0});t.json({views:n.map(ll(e)),maxLive:no})}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.get("/api/views/:id",async(e,t)=>{let n=await NA(e.params.id);if(!n)return t.status(404).json({error:"view not found"});t.json({view:ll(e)(n),session:ia(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 se(n):null;if(!i&&s&&(i=(await we()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Te.sep)))||null),!i)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let c=await Xh({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:ll(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:ll(e)(await PA(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:ll(e)(await DA(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 BA(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});var m6=[["linear",ns,Hg],["jira",Zd,Fg]],Vy=new Map;S.get("/api/integrations/ticketing",async(e,t)=>{try{let n=await Lg(),r={};for(let[o,s,a]of m6){let i=await s();if(!i){Vy.delete(o),r[o]={configured:!1};continue}let c=Vy.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},Vy.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 Lg()})}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 hI(o),i=n?await se(n):null;!i&&r&&(i=(await we()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+Te.sep)))||null),i&&await M({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 ds=async(e,t)=>{let n=e?await se(e):null;return!n&&t&&(n=(await we()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+Te.sep)))||null),n};S.get("/api/circuits",async(e,t)=>{try{t.json({circuits:await Cg()})}catch(n){t.status(502).json({error:n?.message||String(n)})}});S.get("/api/roadmap",async(e,t)=>{try{t.json(await Ng())}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 ds(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 Aa(o);await Vd(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 ds(n,r);if(!o)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});await Vd(o,null,{source:"chat"}),t.json({ok:!0,trackId:o.id})}catch(o){t.status(502).json({error:o?.message||String(o)})}});var EO=async(e,t,n)=>{if(e)return{ref:e,track:await ds(t,n)};let r=await ds(t,n),o=r?await Dg(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 EO(o,n,r),l=await iI({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 EO(e.query.circuit,e.query.track,e.query.cwd);t.json(await Pg(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 ds(n,r);if(!u)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let d=await uI(u,{title:o,context:s,decision:a,summary:i,alternatives:c,supersedesId:l});t.json({ok:!0,trackId:u.id,...d})}catch(u){let d=u?.message||String(u);t.status(/required/i.test(d)?400:502).json({error:d})}});S.get("/api/decisions",async(e,t)=>{try{let n=await ds(e.query.track,e.query.cwd);if(!n)return t.status(400).json({error:"run from inside a Track workspace"});t.json(await dI(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 ds(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=await Dg(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 cI(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 se(n):null;if(!s&&r&&(s=(await we()).find(c=>c.cwd&&(r===c.cwd||r.startsWith(c.cwd+Te.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});if(!o)return t.status(400).json({error:"ref (issue URL or key) required"});let a=await Ia(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 se(r):null;if(!o&&n&&(o=(await we()).find(a=>a.cwd&&(n===a.cwd||String(n).startsWith(a.cwd+Te.sep)))||null),!o)return t.status(400).json({error:"track (or a cwd inside a Track workspace) required"});t.json({trackId:o.id,configured:await OI(),ticket:await Kn(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 Kn(e.params.id)})});S.post("/api/tracks/:id/ticket",async(e,t)=>{try{let n=await se(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await Ia(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 ey(e.params.id)})});var Op=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 PI(e.params.id))}catch(n){let r=n?.message||String(n);t.status(Op(r)).json({error:r})}});S.post("/api/tracks/:id/ticket/state",async(e,t)=>{try{t.json({ok:!0,...await ty(e.params.id,(e.body||{}).stateId)})}catch(n){let r=n?.message||String(n);t.status(Op(r)).json({error:r})}});S.post("/api/tracks/:id/ticket/comment",async(e,t)=>{try{t.json({ok:!0,...await DI(e.params.id,(e.body||{}).body)})}catch(n){let r=n?.message||String(n);t.status(Op(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 se(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await BI(o,n,r===!0)})}catch(o){let s=o?.message||String(o);t.status(Op(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 fg(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 se(n):null;if(!s&&r&&(s=(await we()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+Te.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,proposal:await LI(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 jI()})}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 se(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await FI(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 uc({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 pr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});t.json({mock:n})});var ul={dotfiles:"allow"};S.get("/api/mocks/:id/png",async(e,t)=>{let n=await pr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=pn(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=cc(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,ul,s=>{s&&!t.headersSent&&t.status(404).json({error:"rendered artifact missing"})})});S.get("/api/mocks/:id/media",async(e,t)=>{let n=await pr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=pn(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=cc(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,ul,s=>{s&&!t.headersSent&&t.status(404).json({error:"video artifact missing"})})});S.get("/api/mocks/:id/html",async(e,t)=>{let n=await pr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=pn(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(Yt(n,r.v).html,ul,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&&md(n)?n:null,o=n&&!r?n:null,s=n?e.query:e.body||{},{trackId:a,name:i,cwd:c,width:l,group:u}=s;try{let d=a?await se(a):null;if(!d&&c&&(d=(await we()).find(m=>m.cwd&&(c===m.cwd||c.startsWith(m.cwd+Te.sep)))||null),!d)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let p=(d.boxes||[]).find(w=>w.name===d.leadBox),f=await QA({trackId:d.id,name:i,html:n?null:s.html,image:r,video:o,cwd:d.cwd,width:l,group:u,box:d.leadBox,agent:p?.agent||null});t.json({ok:!0,mock:f})}catch(d){let p=d?.message||String(d);t.status(/required|invalid|must be/i.test(p)?400:500).json({error:p})}});S.post("/api/mocks/:id/update",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&md(n)?n:null;try{let o=await eE(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 rE(e.params.id),o=r.length?` over ${r.map(s=>`"${s.name}"`).join(", ")}`:"";await Dt(n.trackId,`Design decision: go with "${n.name}" (mock:${n.id})${o} \u2014 proceed with this design.`,{kind:"mock-picked"}).catch(()=>{}),t.json({ok:!0,mock:n,siblings:r})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/nothing to pick/i.test(r)?409:500;t.status(o).json({error:r})}});S.delete("/api/mocks/:id",async(e,t)=>{try{let n=(await xE(e.params.id)).map(r=>({id:r.id,name:r.name}));t.json({...await oE(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 wE({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 gE(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 se(n):null;if(!a&&s&&(a=(await we()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Te.sep)))||null),!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=(a.boxes||[]).find(l=>l.name===a.leadBox),c=await yE({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 bE(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 kE(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 we(),a=String(e.query.cwd);if(n=s.find(i=>i.cwd&&(a===i.cwd||a.startsWith(i.cwd+Te.sep)))?.id,!n)return t.json({runbooks:[]})}let{runbooks:r,fleetDegraded:o}=await $E({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 dw(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 dw(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});let r=_E(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 RE(n,r.v);return typeof o!="string"?t.status(404).json({error:"runbook artifact missing"}):t.send(o)}t.sendFile(wr(n,r.v),ul,o=>{o&&!t.headersSent&&t.status(404).json({error:"runbook artifact missing"})})});S.get("/api/loops",async(e,t)=>{t.json(await Gi())});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 we()).find(u=>u.cwd&&(o===u.cwd||o.startsWith(u.cwd+Te.sep)))||null;if(!a)return t.status(400).json({error:"cwd is not inside a Track workspace"});let i=await Gi();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 kh({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 se(n):null;if(!s&&r&&(s=(await we()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+Te.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,proposal:await q$(s,o)})}catch(s){t.status(400).json({error:s?.message||String(s)})}});var ja=async(e,t)=>{let n=e?await se(e):null;return!n&&t&&(n=(await we()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+Te.sep)))||null),n};S.post("/api/followups/offer",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await ja(n,r);if(!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,result:await VT(s,o,{ship:{changedRepos:Ko}})})}catch(s){t.status(400).json({error:s?.message||String(s)})}});S.post("/api/followups/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await ja(n,r);if(!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,proposal:await YT(s,o)})}catch(s){let a=s?.message||String(s);t.status(/unreachable/i.test(a)?503:400).json({error:a})}});S.get("/api/followups",async(e,t)=>{let n=typeof e.query?.cwd=="string"?e.query.cwd:null,r=await ja(null,n).catch(()=>null);t.json({ok:!0,trackId:r?.id??null,triggers:Eh,...await tA(r)})});var fO=new Set(["reconcile","fixing-ci","rebase","merge"]);S.get("/api/status",async(e,t)=>{let n=await ja(null,typeof e.query?.cwd=="string"?e.query.cwd:null).catch(()=>null);if(!n)return t.status(400).json({error:"a cwd inside a Track workspace is required"});t.json({ok:!0,trackId:n.id,status:n.status})});S.post("/api/status",async(e,t)=>{try{let{trackId:n,cwd:r,phase:o,summary:s,scope:a,reason:i}=e.body||{},c=await ja(n,r);if(!c)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let l=o==="fix-ci"?"fixing-ci":o;if(l!=null&&!fO.has(l))throw new Error(`phase must be one of ${[...fO].join(" | ")}`);let u=s==null?null:String(s).trim();if(u&&u.length>120)throw new Error("summary is too long (cap is 120 characters)");let d=i6();await M(c,{type:"track.phase.changed",actor:"agent",source:"cli",boxId:c.leadBox,provider:c.boxes?.find(p=>p.name===c.leadBox)?.agent??null,payload:{ts:Date.now(),phase:l||null,phaseId:d,summary:u,scope:a&&typeof a=="object"?a:null,...l?{}:{reason:i||"completed"}}}),t.json({ok:!0,trackId:c.id,phase:l||null,phaseId:d})}catch(n){t.status(400).json({error:n?.message||String(n)})}});S.post("/api/tracks/:id/followup-offer",async(e,t)=>{let{offerId:n,followupId:r,armId:o,promoted:s}=e.body||{};try{let a=await se(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await ZT(a,{offerId:n,followupId:r||null,armId:o||null,promoted:s||null},{sayToLead:Dt,unarchiveTrack:Nd})})}catch(a){let i=a?.message||String(a),c=a?.code==="removed"?410:/unknown offer/i.test(i)?404:/already answered/i.test(i)?409:/required|not on this card/i.test(i)?400:/unreachable/i.test(i)?503:502;t.status(c).json({error:i})}});S.post("/api/tracks/:id/followup-arm-cancel",async(e,t)=>{try{let n=await se(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await JT(n,e.body?.armId)})}catch(n){let r=n?.message||String(n);t.status(/unknown/i.test(r)?404:400).json({error:r})}});S.post("/api/tracks/:id/followup-create-offer",async(e,t)=>{let{proposalId:n,accept:r,followupId:o}=e.body||{};try{let s=await se(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await XT(s,n,r===!0,{followupId:o||null})})}catch(s){let a=s?.message||String(s);t.status(/unknown proposal/i.test(a)?404:/already answered/i.test(a)?409:400).json({error:a})}});Je.on("event",e=>{let t=e?.type==="pr.state.changed"?e.payload?.change:null;if(!t||!e.trackId)return;let n=t==="opened"?"pr.opened":t==="ci-fixed"?"checks.green":null,r=e.payload||{},o={repo:r.repo??null,prNumber:r.number??null,prTitle:r.title??null,prUrl:r.url??null};!n&&t!=="pushed"||se(e.trackId).then(async s=>{if(s&&(n&&await Ji(s,n,o),t==="opened"||t==="pushed")){let a=eA(await K(s).catch(()=>[]));a&&await Ji(s,"ship.done",{...o,shipOfferId:a})}}).catch(()=>{})});var _O=async(e,t,{trackId:n,cwd:r,loop:o})=>{let s=n?await se(n):null;if(!s&&r&&(s=(await we()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+Te.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"}),null;let a=await Gi();if(a.source!=="plane")return t.status(503).json({error:a.source==="unconfigured"?"this node isn't linked to a plane \u2014 loops live in the plane":`plane unreachable (${a.error||"no detail"})`}),null;let i;try{i=G$(a.loops,o)}catch(c){return t.status(/matches \d+ loops/.test(c.message)?409:404).json({error:c.message}),null}return{track:s,loop:i}};S.post("/api/loops/propose-update",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await _O(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await z$(s.track,s.loop,e.body?.patch)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});S.post("/api/loops/propose-delete",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await _O(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await V$(s.track,s.loop,e.body?.reason)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});S.post("/api/planning/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o,scope:s}=e.body||{},a=await ja(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i;try{i=await Ng()}catch(c){return t.status(503).json({error:c?.message||String(c)})}try{let c=s==="circuit"?Ey:el;t.json({ok:!0,trackId:a.id,proposal:await sR(a,o,i,{allow:c})})}catch(c){t.status(400).json({error:c?.message||String(c)})}});var eb=e=>/unknown proposal/i.test(e)?404:/already answered/i.test(e)?409:400;S.post("/api/tracks/:id/planning-offer",async(e,t)=>{let{proposalId:n,action:r,results:o}=e.body||{};try{let s=await se(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await aR(s,n,r,{results:o||[]})})}catch(s){let a=s?.message||String(s);t.status(eb(a)).json({error:a})}});S.post("/api/tracks/:id/loop-update-offer",async(e,t)=>{let{proposalId:n,action:r,nextFireAt:o}=e.body||{};try{let s=await se(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await Y$(s,n,r,{nextFireAt:o??null})})}catch(s){let a=s?.message||String(s);t.status(eb(a)).json({error:a})}});S.post("/api/tracks/:id/loop-delete-offer",async(e,t)=>{let{proposalId:n,action:r}=e.body||{};try{let o=await se(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await X$(o,n,r)})}catch(o){let s=o?.message||String(o);t.status(eb(s)).json({error:s})}});S.post("/api/tracks/:id/loop-create-offer",async(e,t)=>{let{proposalId:n,accept:r,loopId:o,nextFireAt:s}=e.body||{};try{let a=await se(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await W$(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 se(n):null;if(!a&&s&&(a=(await we()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Te.sep)))||null),!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=(a.boxes||[]).find(l=>l.name===a.leadBox),c=await OE({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 ME(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 CE(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 NE(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=dR(e.query.since||null);t.json({since:n,repos:Iy(),...await pR(n)})}catch(n){let r=n?.message||String(n);t.status(/unparseable/i.test(r)?400:500).json({error:r})}});var IO=async({trackId:e,cwd:t})=>{let n=e?await se(e):null;return!n&&t&&(n=(await we()).find(o=>o.cwd&&(t===o.cwd||String(t).startsWith(o.cwd+Te.sep)))||null),n};S.post("/api/changelog/publish",async(e,t)=>{let{md:n,day:r,trackId:o,cwd:s}=e.body||{};try{let a=await IO({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 fR(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 IO({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 mR(s,{day:n})})}catch(s){let a=s?.message||String(s);t.status(/required|invalid/i.test(a)?400:500).json({error:a})}});var h6=120,Jy=400,Ba=null,mO=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>Jy)return t.status(400).json({error:`message is ${i.length} chars \u2014 over the ${Jy} cap; a notification is a nudge, put the detail in chat`});let c=dc(`${n||""}
763
- ${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 se(a):null;if(!l&&s&&(l=(await we()).find(w=>w.cwd&&(s===w.cwd||s.startsWith(w.cwd+Te.sep)))||null),!l)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let u=(l.boxes||[]).find(f=>f.name===l.leadBox),d=(f,w)=>String(f).replace(/\s+/g," ").trim().slice(0,w),p={title:n?d(n,h6):l.name,body:d(i,Jy),urgency:o==="high"?"high":"normal",trackName:l.name,ts:Date.now()};await M(l,{type:"notify.raised",actor:"agent",boxId:l.leadBox??null,provider:u?.agent||null,payload:p}),t.json({ok:!0,notification:p,delivered:Ba?Ba.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 iO(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 Lc(),terms:await Gy(),problem:await aO()})});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 sO(n,r)})});S.get("/api/tracks/:id/voice-chat",async(e,t)=>{if(!await se(e.params.id))return t.status(404).json({error:"track not found"});t.json(await cO())});S.post("/api/tracks/:id/voice-chat/session",async(e,t)=>{try{let n=await se(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 lO())}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 se(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 uO(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 Md({name:n,cwd:r,repo:o,repos:s,agent:a,skipPermissions:i!==!1}),d=null;if(c)try{await Ia(u,c,{source:"create"})}catch(f){d=f?.message||String(f)}let p=null;if(l)try{await Vd(u,await Aa(l),{source:"picker"})}catch(f){p=f?.message||String(f)}t.json({ok:!0,track:u,...d?{ticketWarning:d}:{},...p?{circuitWarning:p}:{}})}catch(u){let d=u?.message||String(u);t.status(/required|unknown agent|invalid|must be/i.test(d)?400:500).json({error:d})}});S.get("/api/tracks/:id",async(e,t)=>{let n=await se(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({track:n,handoff:$O(Ta(e.params.id)),subtasks:es(e.params.id).map(dl),pendingOffers:await Kw(n)})});S.delete("/api/tracks/:id",async(e,t)=>{try{let n=await ig(e.params.id,{cascadeMocks:e.query.mocks!=="0",cascadeRunbooks:e.query.runbooks==="1"});await ey(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 Zo(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 ug(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 Nd(e.params.id,{freshSession:e.body?.freshSession===!0})})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/not archived/i.test(r)?409:500).json({error:r})}});S.get("/api/tracks/:id/messages",async(e,t)=>{let n=await Id(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 se(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}
766
+ `));let f=l.map(y=>y.name).join(", "),w=c&&i?` in the ${i.name}/ checkout`:"",m=await Ft(a.id,`CI is red on PR #${o.number} "${o.title}" (${o.url}) \u2014 branch ${o.headRefName}${w}. Failing check${l.length===1?"":"s"}: ${f}. The failure log is at ${p} in this ${c?"workspace":"worktree"} \u2014 read it, fix the root cause${c&&i?` in ${i.name}/`:""}, run the relevant tests locally, then commit and push to update the PR.`,{kind:"ci-fix"}),g=s;g&&(await Bt({repo:g,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await OS(g,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await vn("fix-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{checks:l.map(y=>y.name)}}),t.json({ok:!0,leadBox:m.leadBox,queued:!!m.queued,checks:l.map(y=>y.name),log:p})}catch(o){let s=o?.message||String(o),a=/unknown repo|invalid|required/i.test(s)?400:/not found|no active Track/i.test(s)?404:502;t.status(a).json({error:s})}});E.post("/api/git/prs/reconcile",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await ca(n,r);if(o.mergeable!=="CONFLICTING")return t.status(409).json({error:"this PR does not conflict with its base branch"});let s=await _e(n).catch(()=>null),a=await FO({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=Nt(a.workspace).find(d=>d.base===n||s&&d.repo===s)??null,c=a.workspace?.kind==="multi"&&i?` In the ${i.name}/ checkout:`:"",l=await Ft(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 Bt({repo:u,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await MS(u,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await vn("reconcile-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{base:o.baseRefName}}),t.json({ok:!0,leadBox:l.leadBox,queued:!!l.queued,base:o.baseRefName})}catch(o){let s=o?.message||String(o),a=/unknown repo|invalid|required/i.test(s)?400:/not found|no active Track/i.test(s)?404:502;t.status(a).json({error:s})}});E.post("/api/tracks/:id/pr-offer",async(e,t)=>{let{offerId:n,action:r}=e.body||{};try{let o=null;if(Array.isArray(e.body?.actions)){if(o=Xr.filter(a=>e.body.actions.includes(a)),!o.length)return t.status(400).json({error:"actions must include commit, rebase, push and/or pr"})}else if(r==="pr")o=["commit","push","pr"];else if(r==="push")o=["commit","push"];else if(r!=="dismiss")return t.status(400).json({error:'offerId and actions ["commit"|"rebase"|"push"|"pr"] (or action "dismiss") required'});if(!n)return t.status(400).json({error:"offerId required"});let s=o!=null&&e.body?.notify===!0;await so(`pr:${e.params.id}:${n}`,async()=>{let a=await ce(e.params.id);if(!a)return t.status(404).json({error:"track not found"});let i=await K(a),c=i.find(d=>d.type==="pr.offered"&&d.payload?.offerId===n);if(!c)return t.status(404).json({error:"unknown offer"});if(i.some(d=>d.type==="pr.offer.answered"&&d.payload?.offerId===n))return t.status(409).json({error:"offer already answered"});if(o?.includes("pr")){let d=await tb(a,c,{actions:o,notify:s});if(d)return t.json({ok:!0,offerId:n,action:"pr-exists",actions:o,notify:s,existingPr:d.pr})}let l=null;o&&(l=await Ft(a.id,oa(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 M({id:a.id,cwd:a.cwd},{type:"pr.offer.answered",actor:"user",source:"orchestrator",boxId:c.boxId,payload:{ts:Date.now(),offerId:n,action:u,actions:o,...s?{notify:!0}:{}}}),s&&dg(a.id,{actions:o}),t.json({ok:!0,offerId:n,action:u,actions:o,notify:s,queued:!!l?.queued})})}catch(o){let s=o?.message||String(o),a=/required|invalid/i.test(s)?400:/already answered|not found|not running|archived/i.test(s)?409:502;t.status(a).json({error:s})}});E.post("/api/tracks/:id/pr-exists",async(e,t)=>{let{offerId:n,choice:r}=e.body||{};try{let o=await ce(e.params.id);if(!o)return t.status(404).json({error:"track not found"});let{say:s}=await nb(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 fl=e=>t=>({...t,url:X$(t,e.headers)});E.get("/api/views",async(e,t)=>{try{let n=await dw({trackId:e.query.track||void 0});t.json({views:n.map(fl(e)),maxLive:io})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/views/:id",async(e,t)=>{let n=await JT(e.params.id);if(!n)return t.status(404).json({error:"view not found"});t.json({view:fl(e)(n),session:wa(n.slug)})});E.post("/api/views",async(e,t)=>{let{trackId:n,name:r,cmd:o,cwd:s,port:a}=e.body||{};try{let i=n?await ce(n):null;if(!i&&s&&(i=(await he()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Te.sep)))||null),!i)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let c=await fw({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:fl(e)(c)})}catch(i){let c=i?.message||String(i),l=i?.status??(/cap reached/i.test(c)?409:/required|invalid|already owned|no free/i.test(c)?400:500);t.status(l).json({error:c})}});E.post("/api/views/:id/stop",async(e,t)=>{try{t.json({ok:!0,view:fl(e)(await YT(e.params.id))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});E.post("/api/views/:id/restart",async(e,t)=>{try{t.json({ok:!0,view:fl(e)(await XT(e.params.id))})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/cap reached|no known command/i.test(r)?409:500;t.status(o).json({error:r})}});E.delete("/api/views/:id",async(e,t)=>{try{t.json(await ZT(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});var N6=[["linear",ms,oy],["jira",mp,ny]],ub=new Map;E.get("/api/integrations/ticketing",async(e,t)=>{try{let n=await ty(),r={};for(let[o,s,a]of N6){let i=await s();if(!i){ub.delete(o),r[o]={configured:!1};continue}let c=ub.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},ub.set(o,c)}r[o]={...c.body,flow:n},o==="jira"&&i.tokenExpiresAt&&(r[o].tokenExpiresAt=i.tokenExpiresAt)}t.json(r)}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/tickets/flow",async(e,t)=>{try{t.json({flow:await ty()})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/tickets/flow",async(e,t)=>{let{trackId:n,cwd:r,set:o,actor:s}=e.body||{};try{let a=await RI(o),i=n?await ce(n):null;!i&&r&&(i=(await he()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+Te.sep)))||null),i&&await M({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 Ss=async(e,t)=>{let n=e?await ce(e):null;return!n&&t&&(n=(await he()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+Te.sep)))||null),n};E.get("/api/circuits",async(e,t)=>{try{t.json({circuits:await Jg()})}catch(n){t.status(502).json({error:n?.message||String(n)})}});E.get("/api/roadmap",async(e,t)=>{try{t.json(await Yg())}catch(n){t.status(502).json({error:n?.message||String(n)})}});E.post("/api/circuits/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=await Ss(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 Na(o);await up(s,a,{source:"chat"}),t.json({ok:!0,trackId:s.id,circuit:a})}catch(s){let a=s?.message||String(s);t.status(/required|no circuit|names \d|no plane/i.test(a)?400:502).json({error:a})}});E.post("/api/circuits/unlink",async(e,t)=>{let{trackId:n,cwd:r}=e.body||{};try{let o=await Ss(n,r);if(!o)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});await up(o,null,{source:"chat"}),t.json({ok:!0,trackId:o.id})}catch(o){t.status(502).json({error:o?.message||String(o)})}});var HO=async(e,t,n)=>{if(e)return{ref:e,track:await Ss(t,n)};let r=await Ss(t,n),o=r?await Zg(r.id):null;if(!o)throw new Error(r?"this Track isn't in a circuit \u2014 pass --circuit <name-or-id> (or link one first: bostrat-circuit link \u2026)":"run from inside a Track workspace, or pass --circuit <name-or-id>");return{ref:o,track:r}};E.post("/api/blueprints/publish",async(e,t)=>{let{trackId:n,cwd:r,circuit:o,newCircuit:s,name:a,markdown:i}=e.body||{};try{if(!i||!String(i).trim())return t.status(400).json({error:"markdown required"});let{ref:c}=s?{ref:null}:await HO(o,n,r),l=await vI({circuitRef:c,newCircuitName:s,name:a,markdown:i});t.json({ok:!0,...l})}catch(c){let l=c?.message||String(c);t.status(/required|no circuit|names \d|no plane|isn't in a circuit|run from inside/i.test(l)?400:502).json({error:l})}});E.get("/api/blueprints/show",async(e,t)=>{try{let{ref:n}=await HO(e.query.circuit,e.query.track,e.query.cwd);t.json(await Xg(n))}catch(n){let r=n?.message||String(n);t.status(/no blueprint|no circuit|isn't in a circuit|run from inside|names \d/i.test(r)?404:502).json({error:r})}});E.post("/api/decisions/record",async(e,t)=>{let{trackId:n,cwd:r,title:o,context:s,decision:a,summary:i,alternatives:c,supersedesId:l}=e.body||{};try{let u=await Ss(n,r);if(!u)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let d=await TI(u,{title:o,context:s,decision:a,summary:i,alternatives:c,supersedesId:l});t.json({ok:!0,trackId:u.id,...d})}catch(u){let d=u?.message||String(u);t.status(/required/i.test(d)?400:502).json({error:d})}});E.get("/api/decisions",async(e,t)=>{try{let n=await Ss(e.query.track,e.query.cwd);if(!n)return t.status(400).json({error:"run from inside a Track workspace"});t.json(await EI(n.id))}catch(n){let r=n?.message||String(n);t.status(/no plane|required|run from inside/i.test(r)?400:502).json({error:r})}});E.post("/api/blueprints/tag",async(e,t)=>{let{trackId:n,cwd:r,itemIds:o}=e.body||{};try{let s=Array.isArray(o)?o.map(String):[];if(!s.length)return t.status(400).json({error:"itemIds required (BP-\u2026 ids)"});let a=await Ss(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=await Zg(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 SI(a,i,s);t.json({ok:!0,trackId:a.id,...c})}catch(s){let a=s?.message||String(s);t.status(/unknown\/unbindable|required|no blueprint|isn't in a circuit/i.test(a)?400:502).json({error:a})}});E.post("/api/tickets/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=n?await ce(n):null;if(!s&&r&&(s=(await he()).find(c=>c.cwd&&(r===c.cwd||r.startsWith(c.cwd+Te.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});if(!o)return t.status(400).json({error:"ref (issue URL or key) required"});let a=await Ba(s,o,{source:n?"api":"cli"});t.json({ok:!0,trackId:s.id,ticket:a})}catch(s){let a=s?.message||String(s);t.status(/not a Linear|not found|no ticketing|required/i.test(a)?400:502).json({error:a})}});E.get("/api/tickets/status",async(e,t)=>{let{cwd:n,track:r}=e.query;try{let o=r?await ce(r):null;if(!o&&n&&(o=(await he()).find(a=>a.cwd&&(n===a.cwd||String(n).startsWith(a.cwd+Te.sep)))||null),!o)return t.status(400).json({error:"track (or a cwd inside a Track workspace) required"});t.json({trackId:o.id,configured:await GI(),ticket:await Vn(o.id)})}catch(o){t.status(500).json({error:o?.message||String(o)})}});E.get("/api/tracks/:id/ticket",async(e,t)=>{t.json({ticket:await Vn(e.params.id)})});E.post("/api/tracks/:id/ticket",async(e,t)=>{try{let n=await ce(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await Ba(n,(e.body||{}).ref,{source:"api"});t.json({ok:!0,ticket:r})}catch(n){let r=n?.message||String(n);t.status(/not a Linear|not found|no ticketing|required/i.test(r)?400:502).json({error:r})}});E.delete("/api/tracks/:id/ticket",async(e,t)=>{t.json({ok:!0,removed:await wy(e.params.id)})});var zp=e=>/no ticket linked|unknown offer|unknown state/i.test(e)?404:/already answered/i.test(e)?409:/required|no ticketing/i.test(e)?400:502;E.get("/api/tracks/:id/ticket/states",async(e,t)=>{try{t.json(await YI(e.params.id))}catch(n){let r=n?.message||String(n);t.status(zp(r)).json({error:r})}});E.post("/api/tracks/:id/ticket/state",async(e,t)=>{try{t.json({ok:!0,...await gy(e.params.id,(e.body||{}).stateId)})}catch(n){let r=n?.message||String(n);t.status(zp(r)).json({error:r})}});E.post("/api/tracks/:id/ticket/comment",async(e,t)=>{try{t.json({ok:!0,...await XI(e.params.id,(e.body||{}).body)})}catch(n){let r=n?.message||String(n);t.status(zp(r)).json({error:r})}});E.post("/api/tracks/:id/ticket-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{let o=await ce(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await ZI(o,n,r===!0)})}catch(o){let s=o?.message||String(o);t.status(zp(s)).json({error:s})}});E.post("/api/tracks/:id/fullscreen-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{t.json(await Rg(e.params.id,n,r===!0))}catch(o){let s=o?.message||String(o),a=/not found|unknown offer/.test(s)?404:/already answered/.test(s)||/mid-turn/.test(s)?409:500;t.status(a).json({error:s})}});E.post("/api/tickets/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await ce(n):null;if(!s&&r&&(s=(await he()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+Te.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,proposal:await e$(s,o)})}catch(s){let a=s?.message||String(s);t.status(/no ticketing|are off|needs an epic|too many|required/i.test(a)?400:502).json({error:a})}});E.get("/api/tickets/teams",async(e,t)=>{try{t.json({teams:await QI()})}catch(n){let r=n?.message||String(n);t.status(/no ticketing/i.test(r)?400:502).json({error:r})}});E.post("/api/tracks/:id/ticket-create-offer",async(e,t)=>{let{proposalId:n,accept:r,teamId:o}=e.body||{};try{let s=await ce(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await t$(s,n,r===!0,{teamId:o||null})})}catch(s){let a=s?.message||String(s);t.status(/unknown proposal|unknown team/i.test(a)?404:/already answered/i.test(a)?409:/required|no ticketing|pick one/i.test(a)?400:502).json({error:a})}});E.get("/api/mocks",async(e,t)=>{try{t.json({mocks:await wc({trackId:e.query.track||void 0,group:e.query.group||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/mocks/:id",async(e,t)=>{let n=await wr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});t.json({mock:n})});var ml={dotfiles:"allow"};E.get("/api/mocks/:id/png",async(e,t)=>{let n=await wr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=fn(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=mc(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,ml,s=>{s&&!t.headersSent&&t.status(404).json({error:"rendered artifact missing"})})});E.get("/api/mocks/:id/media",async(e,t)=>{let n=await wr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=fn(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=mc(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,ml,s=>{s&&!t.headersSent&&t.status(404).json({error:"video artifact missing"})})});E.get("/api/mocks/:id/html",async(e,t)=>{let n=await wr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=fn(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(Qt(n,r.v).html,ml,o=>{o&&!t.headersSent&&t.status(404).json({error:"source artifact missing"})})});E.post("/api/mocks",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&kd(n)?n:null,o=n&&!r?n:null,s=n?e.query:e.body||{},{trackId:a,name:i,cwd:c,width:l,group:u}=s;try{let d=a?await ce(a):null;if(!d&&c&&(d=(await he()).find(m=>m.cwd&&(c===m.cwd||c.startsWith(m.cwd+Te.sep)))||null),!d)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let p=(d.boxes||[]).find(w=>w.name===d.leadBox),f=await fE({trackId:d.id,name:i,html:n?null:s.html,image:r,video:o,cwd:d.cwd,width:l,group:u,box:d.leadBox,agent:p?.agent||null});t.json({ok:!0,mock:f})}catch(d){let p=d?.message||String(d);t.status(/required|invalid|must be/i.test(p)?400:500).json({error:p})}});E.post("/api/mocks/:id/update",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&kd(n)?n:null;try{let o=await mE(e.params.id,{html:n?null:(e.body||{}).html,image:r,video:n&&!r?n:null,width:n?e.query.width:(e.body||{}).width});t.json({ok:!0,mock:o})}catch(o){let s=o?.message||String(o),a=/not found/i.test(s)?404:/required|invalid|must be/i.test(s)?400:500;t.status(a).json({error:s})}});E.post("/api/mocks/:id/pick",async(e,t)=>{try{let{mock:n,siblings:r}=await gE(e.params.id),o=r.length?` over ${r.map(s=>`"${s.name}"`).join(", ")}`:"";await Ft(n.trackId,`Design decision: go with "${n.name}" (mock:${n.id})${o} \u2014 proceed with this design.`,{kind:"mock-picked"}).catch(()=>{}),t.json({ok:!0,mock:n,siblings:r})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/nothing to pick/i.test(r)?409:500;t.status(o).json({error:r})}});E.delete("/api/mocks/:id",async(e,t)=>{try{let n=(await PE(e.params.id)).map(r=>({id:r.id,name:r.name}));t.json({...await yE(e.params.id),...n.length?{danglingFlows:n}:{}})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});E.get("/api/flows",async(e,t)=>{try{t.json({flows:await RE({trackId:e.query.track||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/flows/:id",async(e,t)=>{let n=await OE(e.params.id);if(!n)return t.status(404).json({error:"flow not found"});t.json({flow:n})});E.post("/api/flows",async(e,t)=>{let{trackId:n,name:r,steps:o,cwd:s}=e.body||{};try{let a=n?await ce(n):null;if(!a&&s&&(a=(await he()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Te.sep)))||null),!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=(a.boxes||[]).find(l=>l.name===a.leadBox),c=await ME({trackId:a.id,name:r,steps:o,cwd:a.cwd,box:a.leadBox,agent:i?.agent||null});t.json({ok:!0,flow:c})}catch(a){let i=a?.message||String(a),c=/already exists/i.test(i)?409:/required|invalid|no mock|ambiguous|over \d+ chars|must be|no captured/i.test(i)?400:500;t.status(c).json({error:i})}});E.post("/api/flows/:id/update",async(e,t)=>{try{let{steps:n,note:r}=e.body||{};t.json({ok:!0,flow:await CE(e.params.id,{steps:n,note:r})})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/required|invalid|no mock|ambiguous|over \d+ chars|must be|no captured/i.test(r)?400:500;t.status(o).json({error:r})}});E.delete("/api/flows/:id",async(e,t)=>{try{t.json(await NE(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});E.get("/api/runbooks",async(e,t)=>{try{let n=e.query.track||void 0;if(!n&&e.query.cwd){let s=await he(),a=String(e.query.cwd);if(n=s.find(i=>i.cwd&&(a===i.cwd||a.startsWith(i.cwd+Te.sep)))?.id,!n)return t.json({runbooks:[]})}let{runbooks:r,fleetDegraded:o}=await WE({trackId:n,status:e.query.status||void 0});t.json({runbooks:r,...o?{fleetDegraded:!0}:{}})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/runbooks/:id",async(e,t)=>{let n=await Iw(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});t.json({runbook:n})});E.get("/api/runbooks/:id/md",async(e,t)=>{let n=await Iw(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});let r=UE(n,e.query.v??null);if(!r)return t.status(404).json({error:"no such version"});if(t.set("content-security-policy","sandbox"),t.set("cache-control","private, max-age=31536000, immutable"),t.type("text/markdown; charset=utf-8"),n.remote){let o=await qE(n,r.v);return typeof o!="string"?t.status(404).json({error:"runbook artifact missing"}):t.send(o)}t.sendFile(kr(n,r.v),ml,o=>{o&&!t.headersSent&&t.status(404).json({error:"runbook artifact missing"})})});E.get("/api/loops",async(e,t)=>{t.json(await Zi())});E.post("/api/loops/report",async(e,t)=>{let{outcome:n,note:r,cwd:o}=e.body||{};if(!["ok","acted","attention"].includes(n))return t.status(400).json({error:"outcome must be one of ok | acted | attention"});if(!o)return t.status(400).json({error:"cwd required"});let a=(await he()).find(u=>u.cwd&&(o===u.cwd||o.startsWith(u.cwd+Te.sep)))||null;if(!a)return t.status(400).json({error:"cwd is not inside a Track workspace"});let i=await Zi();if(i.source!=="plane")return t.status(503).json({error:i.source==="unconfigured"?"this node isn't linked to a plane \u2014 loops live in the plane":`plane unreachable (${i.error||"no detail"})`});let c=i.loops.find(u=>u.trackId===a.id);if(!c)return t.status(404).json({error:`Track "${a.name}" is not a loop's run Track \u2014 nothing to report on`});let l=await Dh({loopId:c.id,outcome:n,note:r});if(!l.ok)return t.status(l.status||503).json({error:l.error||"report failed"});t.json({ok:!0,loop:{id:c.id,name:c.name},run:l.run})});E.post("/api/loops/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await ce(n):null;if(!s&&r&&(s=(await he()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+Te.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,proposal:await oR(s,o)})}catch(s){t.status(400).json({error:s?.message||String(s)})}});var za=async(e,t)=>{let n=e?await ce(e):null;return!n&&t&&(n=(await he()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+Te.sep)))||null),n};E.post("/api/followups/offer",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await za(n,r);if(!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,result:await lT(s,o,{ship:{changedRepos:ts}})})}catch(s){t.status(400).json({error:s?.message||String(s)})}});E.post("/api/followups/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await za(n,r);if(!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,proposal:await dT(s,o)})}catch(s){let a=s?.message||String(s);t.status(/unreachable/i.test(a)?503:400).json({error:a})}});E.get("/api/followups",async(e,t)=>{let n=typeof e.query?.cwd=="string"?e.query.cwd:null,r=await za(null,n).catch(()=>null);t.json({ok:!0,trackId:r?.id??null,triggers:Hh,...await wT(r)})});var IO=new Set(["reconcile","fixing-ci","rebase","merge"]);E.get("/api/status",async(e,t)=>{let n=await za(null,typeof e.query?.cwd=="string"?e.query.cwd:null).catch(()=>null);if(!n)return t.status(400).json({error:"a cwd inside a Track workspace is required"});t.json({ok:!0,trackId:n.id,status:n.status})});E.post("/api/status",async(e,t)=>{try{let{trackId:n,cwd:r,phase:o,summary:s,scope:a,reason:i}=e.body||{},c=await za(n,r);if(!c)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let l=o==="fix-ci"?"fixing-ci":o;if(l!=null&&!IO.has(l))throw new Error(`phase must be one of ${[...IO].join(" | ")}`);let u=s==null?null:String(s).trim();if(u&&u.length>120)throw new Error("summary is too long (cap is 120 characters)");let d=_6();await M(c,{type:"track.phase.changed",actor:"agent",source:"cli",boxId:c.leadBox,provider:c.boxes?.find(p=>p.name===c.leadBox)?.agent??null,payload:{ts:Date.now(),phase:l||null,phaseId:d,summary:u,scope:a&&typeof a=="object"?a:null,...l?{}:{reason:i||"completed"}}}),t.json({ok:!0,trackId:c.id,phase:l||null,phaseId:d})}catch(n){t.status(400).json({error:n?.message||String(n)})}});E.post("/api/tracks/:id/followup-offer",async(e,t)=>{let{offerId:n,followupId:r,armId:o,promoted:s}=e.body||{};try{let a=await ce(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await fT(a,{offerId:n,followupId:r||null,armId:o||null,promoted:s||null},{sayToLead:Ft,unarchiveTrack:Vd})})}catch(a){let i=a?.message||String(a),c=a?.code==="removed"?410:/unknown offer/i.test(i)?404:/already answered/i.test(i)?409:/required|not on this card/i.test(i)?400:/unreachable/i.test(i)?503:502;t.status(c).json({error:i})}});E.post("/api/tracks/:id/followup-arm-cancel",async(e,t)=>{try{let n=await ce(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await uT(n,e.body?.armId)})}catch(n){let r=n?.message||String(n);t.status(/unknown/i.test(r)?404:400).json({error:r})}});E.post("/api/tracks/:id/followup-create-offer",async(e,t)=>{let{proposalId:n,accept:r,followupId:o}=e.body||{};try{let s=await ce(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await pT(s,n,r===!0,{followupId:o||null})})}catch(s){let a=s?.message||String(s);t.status(/unknown proposal/i.test(a)?404:/already answered/i.test(a)?409:400).json({error:a})}});Je.on("event",e=>{let t=e?.type==="pr.state.changed"?e.payload?.change:null;if(!t||!e.trackId)return;let n=t==="opened"?"pr.opened":t==="ci-fixed"?"checks.green":null,r=e.payload||{},o={repo:r.repo??null,prNumber:r.number??null,prTitle:r.title??null,prUrl:r.url??null};!n&&t!=="pushed"||ce(e.trackId).then(async s=>{if(s&&(n&&await tc(s,n,o),t==="opened"||t==="pushed")){let a=hT(await K(s).catch(()=>[]));a&&await tc(s,"ship.done",{...o,shipOfferId:a})}}).catch(()=>{})});var WO=async(e,t,{trackId:n,cwd:r,loop:o})=>{let s=n?await ce(n):null;if(!s&&r&&(s=(await he()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+Te.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"}),null;let a=await Zi();if(a.source!=="plane")return t.status(503).json({error:a.source==="unconfigured"?"this node isn't linked to a plane \u2014 loops live in the plane":`plane unreachable (${a.error||"no detail"})`}),null;let i;try{i=iR(a.loops,o)}catch(c){return t.status(/matches \d+ loops/.test(c.message)?409:404).json({error:c.message}),null}return{track:s,loop:i}};E.post("/api/loops/propose-update",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await WO(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await cR(s.track,s.loop,e.body?.patch)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});E.post("/api/loops/propose-delete",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await WO(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await lR(s.track,s.loop,e.body?.reason)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});E.post("/api/planning/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o,scope:s}=e.body||{},a=await za(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i;try{i=await Yg()}catch(c){return t.status(503).json({error:c?.message||String(c)})}try{let c=s==="circuit"?Hy:ol;t.json({ok:!0,trackId:a.id,proposal:await kR(a,o,i,{allow:c})})}catch(c){t.status(400).json({error:c?.message||String(c)})}});var wb=e=>/unknown proposal/i.test(e)?404:/already answered/i.test(e)?409:400;E.post("/api/tracks/:id/planning-offer",async(e,t)=>{let{proposalId:n,action:r,results:o}=e.body||{};try{let s=await ce(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await xR(s,n,r,{results:o||[]})})}catch(s){let a=s?.message||String(s);t.status(wb(a)).json({error:a})}});E.post("/api/tracks/:id/loop-update-offer",async(e,t)=>{let{proposalId:n,action:r,nextFireAt:o}=e.body||{};try{let s=await ce(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await dR(s,n,r,{nextFireAt:o??null})})}catch(s){let a=s?.message||String(s);t.status(wb(a)).json({error:a})}});E.post("/api/tracks/:id/loop-delete-offer",async(e,t)=>{let{proposalId:n,action:r}=e.body||{};try{let o=await ce(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await pR(o,n,r)})}catch(o){let s=o?.message||String(o);t.status(wb(s)).json({error:s})}});E.post("/api/tracks/:id/loop-create-offer",async(e,t)=>{let{proposalId:n,accept:r,loopId:o,nextFireAt:s}=e.body||{};try{let a=await ce(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await sR(a,n,r===!0,{loopId:o||null,nextFireAt:s??null})})}catch(a){let i=a?.message||String(a);t.status(/unknown proposal/i.test(i)?404:/already answered/i.test(i)?409:400).json({error:i})}});E.post("/api/runbooks",async(e,t)=>{let{trackId:n,name:r,md:o,cwd:s}=e.body||{};try{let a=n?await ce(n):null;if(!a&&s&&(a=(await he()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Te.sep)))||null),!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=(a.boxes||[]).find(l=>l.name===a.leadBox),c=await KE({trackId:a.id,trackName:a.name,name:r,md:o,cwd:a.cwd,box:a.leadBox,agent:i?.agent||null});t.json({ok:!0,runbook:c})}catch(a){let i=a?.message||String(a);t.status(/required|invalid|over the|secret VALUE/i.test(i)?400:500).json({error:i})}});E.post("/api/runbooks/:id/update",async(e,t)=>{try{let{md:n,note:r}=e.body||{};t.json({ok:!0,runbook:await GE(e.params.id,{md:n,note:r})})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/orphaned/i.test(r)?410:/required|invalid|over the|secret VALUE/i.test(r)?400:500;t.status(o).json({error:r})}});E.post("/api/runbooks/:id/status",async(e,t)=>{try{t.json({ok:!0,runbook:await zE(e.params.id,(e.body||{}).status)})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/orphaned/i.test(r)?410:/must be/i.test(r)?400:500;t.status(o).json({error:r})}});E.delete("/api/runbooks/:id",async(e,t)=>{try{t.json(await VE(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});E.get("/api/changelog/draft",async(e,t)=>{try{let n=ER(e.query.since||null);t.json({since:n,repos:qy(),...await _R(n)})}catch(n){let r=n?.message||String(n);t.status(/unparseable/i.test(r)?400:500).json({error:r})}});var qO=async({trackId:e,cwd:t})=>{let n=e?await ce(e):null;return!n&&t&&(n=(await he()).find(o=>o.cwd&&(t===o.cwd||String(t).startsWith(o.cwd+Te.sep)))||null),n};E.post("/api/changelog/publish",async(e,t)=>{let{md:n,day:r,trackId:o,cwd:s}=e.body||{};try{let a=await qO({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 IR(a,{md:n,day:r})})}catch(a){let i=a?.message||String(a);t.status(/required|invalid|no `- `|over the|secret VALUE|mentions "/i.test(i)?400:500).json({error:i})}});E.post("/api/changelog/retract",async(e,t)=>{let{day:n,trackId:r,cwd:o}=e.body||{};try{let s=await qO({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 $R(s,{day:n})})}catch(s){let a=s?.message||String(s);t.status(/required|invalid/i.test(a)?400:500).json({error:a})}});var P6=120,db=400,Ga=null,$O=null;E.post("/api/notify",async(e,t)=>{let{title:n,body:r,urgency:o,cwd:s,trackId:a}=e.body||{};try{let i=typeof r=="string"?r.trim():"";if(!i)return t.status(400).json({error:"body (the message) required"});if(i.length>db)return t.status(400).json({error:`message is ${i.length} chars \u2014 over the ${db} cap; a notification is a nudge, put the detail in chat`});let c=gc(`${n||""}
767
+ ${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 ce(a):null;if(!l&&s&&(l=(await he()).find(w=>w.cwd&&(s===w.cwd||s.startsWith(w.cwd+Te.sep)))||null),!l)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let u=(l.boxes||[]).find(f=>f.name===l.leadBox),d=(f,w)=>String(f).replace(/\s+/g," ").trim().slice(0,w),p={title:n?d(n,P6):l.name,body:d(i,db),urgency:o==="high"?"high":"normal",trackName:l.name,ts:Date.now()};await M(l,{type:"notify.raised",actor:"agent",boxId:l.leadBox??null,provider:u?.agent||null,payload:p}),t.json({ok:!0,notification:p,delivered:Ga?Ga.status().connected:null})}catch(i){t.status(500).json({error:i?.message||String(i)})}});E.post("/api/dictation",async(e,t)=>{if(!Buffer.isBuffer(e.body)||e.body.length===0)return t.status(400).json({error:"expected a raw audio body"});try{t.json(await vO(e.body,e.headers["content-type"]))}catch(n){t.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});E.get("/api/dictation/glossary",async(e,t)=>{t.json({configured:!!await Wc(),terms:await cb(),problem:await xO()})});E.post("/api/dictation/learn",async(e,t)=>{let{transcript:n,finalText:r}=e.body||{};if(typeof n!="string"||typeof r!="string")return t.status(400).json({error:"transcript and finalText are required"});t.json({learned:await kO(n,r)})});E.get("/api/tracks/:id/voice-chat",async(e,t)=>{if(!await ce(e.params.id))return t.status(404).json({error:"track not found"});t.json(await SO())});E.post("/api/tracks/:id/voice-chat/session",async(e,t)=>{try{let n=await ce(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 AO())}catch(n){t.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});E.post("/api/tracks/:id/voice-chat/usage",async(e,t)=>{try{let n=await ce(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 TO(n,{model:r,usage:o,seconds:s})})}catch(n){t.status(n?.status||500).json({error:n?.message||String(n)})}});E.post("/api/tracks",async(e,t)=>{let{name:n,cwd:r,repo:o,repos:s,agent:a,model:i,skipPermissions:c,ticket:l,circuit:u}=e.body||{};try{let d=await Gd({name:n,cwd:r,repo:o,repos:s,agent:a,model:i,skipPermissions:c!==!1}),p=null;if(l)try{await Ba(d,l,{source:"create"})}catch(w){p=w?.message||String(w)}let f=null;if(u)try{await up(d,await Na(u),{source:"picker"})}catch(w){f=w?.message||String(w)}t.json({ok:!0,track:d,...p?{ticketWarning:p}:{},...f?{circuitWarning:f}:{}})}catch(d){let p=d?.message||String(d);t.status(/required|unknown agent|invalid|must be/i.test(p)?400:500).json({error:p})}});E.get("/api/tracks/:id",async(e,t)=>{let n=await ce(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({track:n,handoff:KO(Ca(e.params.id)),subtasks:ps(e.params.id).map(hl),pendingOffers:await sg(n)})});E.delete("/api/tracks/:id",async(e,t)=>{try{let n=await Ag(e.params.id,{cascadeMocks:e.query.mocks!=="0",cascadeRunbooks:e.query.runbooks==="1"});await wy(e.params.id).catch(()=>{}),t.json(n)}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});E.post("/api/tracks/:id/archive",async(e,t)=>{try{t.json({ok:!0,track:await us(e.params.id)})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/already archived/i.test(r)?409:500).json({error:r})}});E.post("/api/tracks/:id/rename",async(e,t)=>{try{t.json({ok:!0,track:await _g(e.params.id,e.body?.name)})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/loop run Tracks/i.test(r)?409:/required|too long/i.test(r)?400:500;t.status(o).json({error:r})}});E.post("/api/tracks/:id/unarchive",async(e,t)=>{try{t.json({ok:!0,track:await Vd(e.params.id,{freshSession:e.body?.freshSession===!0})})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/not archived/i.test(r)?409:500).json({error:r})}});E.get("/api/tracks/:id/messages",async(e,t)=>{let n=await Fd(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json(n)});E.get("/api/tracks/:id/events",async(e,t)=>{let n=await ce(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}
764
768
  data: ${JSON.stringify(i)}
765
769
 
766
- `),o=Number(e.query.since??e.headers["last-event-id"])||0;for(let i of await K(n))i.seq>o&&r(i);let s=Mb(n.id,r),a=setInterval(()=>t.write(`: hb
770
+ `),o=Number(e.query.since??e.headers["last-event-id"])||0;for(let i of await K(n))i.seq>o&&r(i);let s=Vb(n.id,r),a=setInterval(()=>t.write(`: hb
767
771
 
768
- `),25e3);e.on("close",()=>{clearInterval(a),s()})});S.get("/api/tracks/:id/search",async(e,t)=>{let n=await se(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=Ei(await K(n)),a=Ql(s,r,{k:o,role:e.query.role||null,tag:e.query.tag||null});t.json({q:r,indexed:s.N,hits:a.map(i=>({score:Number(i.score.toFixed(3)),seq:i.chunk.seq,ts:i.chunk.ts,role:i.chunk.role,box:i.chunk.boxId,provider:i.chunk.provider,tags:i.chunk.tags,text:i.chunk.text}))})});S.get("/api/memory",async(e,t)=>{t.json({stores:await Jb(),harvest:Kb()})});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 Yb(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 w6=["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(`
769
- `);S.post("/api/tracks/:id/memory/consolidate",async(e,t)=>{try{t.json({ok:!0,...await Dt(e.params.id,w6)})}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 Pd(e.params.id,{freshSession:e.body?.freshSession===!0})})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:n?.transferredTo||/mid-turn|terminal|archived/i.test(r)?409:500;t.status(o).json({error:r,...n?.transferredTo?{transferredTo:n.transferredTo}:{}})}});S.post("/api/tracks/:id/say",async(e,t)=>{let{text:n,attachments:r,producer:o}=e.body||{};try{t.json(await Dt(e.params.id,n,{attachments:r,producer:typeof o=="string"?o:null,dismissPrompt:!0}))}catch(s){let a=s?.message||String(s);if(s?.usageCap)return t.status(429).json({error:"usage_cap",message:a,cap:s.usageCap});if(s?.transferredTo)return t.status(409).json({error:a,transferredTo:s.transferredTo});t.status(/not found/i.test(a)?404:/archived/i.test(a)?409:/required|not running/i.test(a)?400:500).json({error:a})}});S.post("/api/tracks/:id/upload",async(e,t)=>{try{let n=await se(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 FE(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 se(e.params.id);if(!n)return t.status(404).json({error:`track "${e.params.id}" not found`});if(!n.cwd)return t.status(404).json({error:"track has no workspace"});let r=Te.basename(String(e.params.file||""));if(!r||!mw(Te.extname(r).slice(1)))return t.status(400).json({error:"not an upload path"});t.set("cache-control","private, max-age=31536000, immutable"),t.set("content-security-policy","sandbox");let o=fw(n.cwd),s,a;try{s=await gt.promises.realpath(o),a=await gt.promises.realpath(Te.join(o,r))}catch{return t.status(404).json({error:"upload not found"})}if(!a.startsWith(s+Te.sep))return t.status(404).json({error:"upload not found"});t.sendFile(r,{root:o},i=>{i&&!t.headersSent&&t.status(404).json({error:"upload not found"})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});var g6=/^[0-9a-fA-F-]{8,64}$/;S.get("/api/tracks/:id/chat-images/:box/:uuid/:idx",async(e,t)=>{try{let n=await se(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(!g6.test(o)||!Number.isInteger(s)||s<0)return t.status(400).json({error:"bad image ref"});let a=(n.boxes||[]).find(p=>p.name===r);if(!a||a.agent!=="claude"||!a.cwd||!a.sessionId)return t.status(404).json({error:"image source not available"});let i=sn(a.cwd,a.sessionId);if(!i)return t.status(404).json({error:"transcript not found"});let c=`"${o}"`,l=null,u=r6.createInterface({input:gt.createReadStream(i,{encoding:"utf8"}),crlfDelay:1/0});for await(let p of u){if(!p.includes(c))continue;let f;try{f=JSON.parse(p)}catch{continue}if(f.uuid===o){l=f,u.close();break}}let d=l?If(l)[s]:null;if(!d||!/^image\//.test(d.mediaType))return t.status(404).json({error:"image not found"});t.set("content-type",d.mediaType),t.set("cache-control","private, max-age=31536000, immutable"),t.set("content-security-policy","sandbox"),t.send(Buffer.from(d.data,"base64"))}catch(n){t.status(500).json({error:n?.message||String(n)})}});S.post("/api/tracks/:id/interrupt",async(e,t)=>{try{t.json(await Od(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 Jw(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,custom:s}=e.body||{};try{t.json(await $d(e.params.id,{promptId:n,answers:r,text:o,custom:s}))}catch(a){let i=a?.message||String(a),c=/not found/i.test(i)?404:/no pending prompt|changed since|not running|not supported|needs a code|look like a sign-in code|no answer selected|custom answer|didn't take/i.test(i)?409:500;t.status(c).json({error:i})}});S.post("/api/setup/:provider/start",async(e,t)=>{try{let n=await sg({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 zw(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 eg(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 se(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 dp(r,{fresh:o}))});S.post("/api/tracks/:id/model",async(e,t)=>{let{model:n}=e.body||{};try{t.json(await tg(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 Sg(e.params.id,{agent:n,task:r,skipPermissions:o!==!1,reason:s});t.json({ok:!0,subtask:dl(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:es(e.params.id).map(dl)})});S.get("/api/tracks/:id/subtask/:sid/messages",async(e,t)=>{let n=await Gw(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:dl(Ld(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:dl(Tg(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});function dl(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 Dd(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 Zw(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($O(Ta(e.params.id))??{running:!1})});S.post("/api/tracks/:id/transfer-out",async(e,t)=>{try{let n=await gg(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=wg(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 Bd(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 kg({...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 $O(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:Nl(),paths:dk,trace:await uk({limit:n})})});var Yy=Te.resolve(yO,"..","..","client","dist");gt.existsSync(Yy)&&(S.use(Ut.static(Yy)),S.get(/^(?!\/api\/).*/,(e,t)=>t.sendFile(Te.join(Yy,"index.html"),ul)));var RO=s6.createServer(S),y6=new c6({noServer:!0}),OO=(e,t,n)=>{if(!(Qc(e)||Da.allowed(Da.clientIp(e))||Zy.allows(e))){t.write(`HTTP/1.1 403 Forbidden\r
772
+ `),25e3);e.on("close",()=>{clearInterval(a),s()})});E.get("/api/tracks/:id/search",async(e,t)=>{let n=await ce(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=Ci(await K(n)),a=ou(s,r,{k:o,role:e.query.role||null,tag:e.query.tag||null});t.json({q:r,indexed:s.N,hits:a.map(i=>({score:Number(i.score.toFixed(3)),seq:i.chunk.seq,ts:i.chunk.ts,role:i.chunk.role,box:i.chunk.boxId,provider:i.chunk.provider,tags:i.chunk.tags,text:i.chunk.text}))})});E.get("/api/memory",async(e,t)=>{t.json({stores:await dk(),harvest:ik()})});E.delete("/api/memory/:key/:file",async(e,t)=>{let n=String(e.params.key||"");if(!/^[a-z0-9][a-z0-9._-]*$/.test(n))return t.status(400).json({error:"bad store key"});try{t.json({ok:!0,...await pk(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 D6=["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(`
773
+ `);E.post("/api/tracks/:id/memory/consolidate",async(e,t)=>{try{t.json({ok:!0,...await Ft(e.params.id,D6)})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/archived/i.test(r)?409:/not running/i.test(r)?400:500).json({error:r})}});E.post("/api/tracks/:id/lead/restart",async(e,t)=>{try{t.json({ok:!0,track:await Jd(e.params.id,{freshSession:e.body?.freshSession===!0})})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:n?.transferredTo||/mid-turn|terminal|archived/i.test(r)?409:500;t.status(o).json({error:r,...n?.transferredTo?{transferredTo:n.transferredTo}:{}})}});E.post("/api/tracks/:id/say",async(e,t)=>{let{text:n,attachments:r,producer:o}=e.body||{};try{t.json(await Ft(e.params.id,n,{attachments:r,producer:typeof o=="string"?o:null,dismissPrompt:!0}))}catch(s){let a=s?.message||String(s);if(s?.usageCap)return t.status(429).json({error:"usage_cap",message:a,cap:s.usageCap});if(s?.transferredTo)return t.status(409).json({error:a,transferredTo:s.transferredTo});t.status(/not found/i.test(a)?404:/archived/i.test(a)?409:/required|not running/i.test(a)?400:500).json({error:a})}});E.post("/api/tracks/:id/upload",async(e,t)=>{try{let n=await ce(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 e_(n.cwd,{filename:e.query.filename,buffer:r});t.json({ok:!0,attachment:o})}catch(n){let r=n?.message||String(n);t.status(/too large|unsupported|empty|required/i.test(r)?400:500).json({error:r})}});E.get("/api/tracks/:id/uploads/:file",async(e,t)=>{try{let n=await ce(e.params.id);if(!n)return t.status(404).json({error:`track "${e.params.id}" not found`});if(!n.cwd)return t.status(404).json({error:"track has no workspace"});let r=Te.basename(String(e.params.file||""));if(!r||!Ow(Te.extname(r).slice(1)))return t.status(400).json({error:"not an upload path"});t.set("cache-control","private, max-age=31536000, immutable"),t.set("content-security-policy","sandbox");let o=Rw(n.cwd),s,a;try{s=await yt.promises.realpath(o),a=await yt.promises.realpath(Te.join(o,r))}catch{return t.status(404).json({error:"upload not found"})}if(!a.startsWith(s+Te.sep))return t.status(404).json({error:"upload not found"});t.sendFile(r,{root:o},i=>{i&&!t.headersSent&&t.status(404).json({error:"upload not found"})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});var B6=/^[0-9a-fA-F-]{8,64}$/;E.get("/api/tracks/:id/chat-images/:box/:uuid/:idx",async(e,t)=>{try{let n=await ce(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(!B6.test(o)||!Number.isInteger(s)||s<0)return t.status(400).json({error:"bad image ref"});let a=(n.boxes||[]).find(p=>p.name===r);if(!a||a.agent!=="claude"||!a.cwd||!a.sessionId)return t.status(404).json({error:"image source not available"});let i=an(a.cwd,a.sessionId);if(!i)return t.status(404).json({error:"transcript not found"});let c=`"${o}"`,l=null,u=S6.createInterface({input:yt.createReadStream(i,{encoding:"utf8"}),crlfDelay:1/0});for await(let p of u){if(!p.includes(c))continue;let f;try{f=JSON.parse(p)}catch{continue}if(f.uuid===o){l=f,u.close();break}}let d=l?Wf(l)[s]:null;if(!d||!/^image\//.test(d.mediaType))return t.status(404).json({error:"image not found"});t.set("content-type",d.mediaType),t.set("cache-control","private, max-age=31536000, immutable"),t.set("content-security-policy","sandbox"),t.send(Buffer.from(d.data,"base64"))}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/tracks/:id/interrupt",async(e,t)=>{try{t.json(await Wd(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/archived/i.test(r)?409:500).json({error:r})}});E.delete("/api/tracks/:id/queue",async(e,t)=>{try{let{removed:n,restored:r,draftRev:o}=await lg(e.params.id);t.json({ok:!0,removed:n.filter(s=>s.kind!=="ship-notify"),restored:r,draftRev:o})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/tracks/:id/answer-prompt",async(e,t)=>{let{promptId:n,answers:r,text:o,custom:s}=e.body||{};try{t.json(await Ud(e.params.id,{promptId:n,answers:r,text:o,custom:s}))}catch(a){let i=a?.message||String(a),c=/not found/i.test(i)?404:/no pending prompt|changed since|not running|not supported|needs a code|look like a sign-in code|no answer selected|custom answer|didn't take/i.test(i)?409:500;t.status(c).json({error:i})}});E.post("/api/setup/:provider/start",async(e,t)=>{try{let n=await vg({provider:e.params.provider,fresh:e.body?.fresh===!0});t.json({ok:!0,track:n})}catch(n){let r=n?.message||String(n);t.status(/unknown setup provider|isn't available/i.test(r)?400:500).json({error:r})}});E.post("/api/tracks/:id/navigate-prompt",async(e,t)=>{let{promptId:n,questionIndex:r}=e.body||{};try{t.json(await ig(e.params.id,{promptId:n,questionIndex:r}))}catch(o){let s=o?.message||String(o),a=/not found/i.test(s)?404:/no pending prompt|changed since|not running|not supported|out of range|review screen/i.test(s)?409:500;t.status(a).json({error:s})}});E.put("/api/tracks/:id/draft",async(e,t)=>{let{text:n,rev:r}=e.body||{};try{t.json(await mg(e.params.id,typeof n=="string"?n:"",{rev:typeof r=="number"?r:null}))}catch(o){let s=o?.message||String(o),a=/not found/i.test(s)?404:/required/i.test(s)?400:500;t.status(a).json({error:s})}});E.get("/api/tracks/:id/usage",async(e,t)=>{let n=await ce(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 _p(r,{fresh:o}))});E.post("/api/tracks/:id/model",async(e,t)=>{let{model:n}=e.body||{};try{t.json(await hg(e.params.id,n))}catch(r){let o=r?.message||String(r),s=/not found/i.test(o)?404:/required|unknown model|not running/i.test(o)?400:500;t.status(s).json({error:o})}});E.post("/api/tracks/:id/subtask",async(e,t)=>{let{agent:n,task:r,skipPermissions:o,reason:s}=e.body||{};try{let a=await Lg(e.params.id,{agent:n,task:r,skipPermissions:o!==!1,reason:s});t.json({ok:!0,subtask:hl(a)})}catch(a){let i=a?.message||String(a);if(a?.usageCap)return t.status(429).json({error:"usage_cap",message:i,cap:a.usageCap});let c=/not found/i.test(i)?404:/required|unknown agent|git repo|not running|can't resolve/i.test(i)?400:500;t.status(c).json({error:i})}});E.get("/api/tracks/:id/subtasks",(e,t)=>{t.json({subtasks:ps(e.params.id).map(hl)})});E.get("/api/tracks/:id/subtask/:sid/messages",async(e,t)=>{let n=await ag(e.params.id,e.params.sid);if(!n)return t.status(404).json({error:"subtask not found"});t.json(n)});E.post("/api/tracks/:id/subtask/:sid/cancel",(e,t)=>{try{t.json({ok:!0,subtask:hl(tp(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});E.post("/api/tracks/:id/subtask/:sid/merge-now",(e,t)=>{try{t.json({ok:!0,subtask:hl(Fg(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});function hl(e){return e?{id:e.id,agent:e.agent,task:e.task,skipPermissions:e.skipPermissions,step:e.step,running:!e.finishedAt,box:e.box,branch:e.branch,stat:e.stat,files:e.files||null,conflicts:e.conflicts||[],applied:e.applied,error:e.error,canceled:e.canceled,startedAt:e.startedAt,finishedAt:e.finishedAt}:null}E.post("/api/tracks/:id/handoff-lead",async(e,t)=>{let{toAgent:n,skipPermissions:r,reason:o}=e.body||{};try{let s=await Yd(e.params.id,n,r!==!1,o);t.json({ok:!0,step:s.step,toAgent:s.toAgent,fromBox:s.fromBox,skipPermissions:s.skipPermissions})}catch(s){let a=s?.message||String(s);if(s?.usageCap)return t.status(429).json({error:"usage_cap",message:a,cap:s.usageCap});t.status(/already running/i.test(a)?409:/not found/i.test(a)?404:400).json({error:a})}});E.post("/api/tracks/:id/spin-up-view",async(e,t)=>{try{t.json(await pg(e.params.id,e.body||{}))}catch(n){let r=n?.message||String(n);t.status(/already being spun up/i.test(r)?409:/not found/i.test(r)?404:400).json({error:r})}});E.get("/api/tracks/:id/handoff-lead",(e,t)=>{t.json(KO(Ca(e.params.id))??{running:!1})});E.post("/api/tracks/:id/transfer-out",async(e,t)=>{try{let n=await Pg(e.params.id);t.json({ok:!0,step:n.step,startedAt:n.startedAt})}catch(n){let r=n?.message||String(n);t.status(/already running/i.test(r)?409:/not found/i.test(r)?404:400).json({error:r})}});E.get("/api/tracks/:id/transfer-out",(e,t)=>{let n=Ng(e.params.id);if(!n)return t.json({running:!1});t.json({running:!n.finishedAt,step:n.step,error:n.error,startedAt:n.startedAt,finishedAt:n.finishedAt,...n.result??{}})});E.post("/api/tracks/:id/transfer-out/commit",async(e,t)=>{try{t.json(await Zd(e.params.id,e.body||{}))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:400).json({error:r})}});E.post("/api/tracks/adopt",async(e,t)=>{let{trackId:n}=e.body||{};try{t.json(await Bg({...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 KO(e){return e?{running:!e.finishedAt,step:e.step,error:e.error,fromBox:e.fromBox,toBox:e.toBox,toAgent:e.toAgent,skipPermissions:e.skipPermissions,startedAt:e.startedAt,finishedAt:e.finishedAt}:null}E.get("/api/debug/handoff",async(e,t)=>{let n=Math.min(Number(e.query.limit)||80,500);t.json({verbose:Ll(),paths:_k,trace:await Ek({limit:n})})});var pb=Te.resolve(CO,"..","..","client","dist");yt.existsSync(pb)&&(E.use(qt.static(pb)),E.get(/^(?!\/api\/).*/,(e,t)=>t.sendFile(Te.join(pb,"index.html"),ml)));var GO=T6.createServer(E),j6=new I6({noServer:!0}),zO=(e,t,n)=>{if(!(rl(e)||Ka.allowed(Ka.clientIp(e))||mb.allows(e))){t.write(`HTTP/1.1 403 Forbidden\r
770
774
  \r
771
- `),t.destroy();return}if(P$(e,t,n))return;if(!M$(e,Qy,{enforce:kO})){t.write(`HTTP/1.1 401 Unauthorized\r
775
+ `),t.destroy();return}if(Y$(e,t,n))return;if(!z$(e,hb,{enforce:PO})){t.write(`HTTP/1.1 401 Unauthorized\r
772
776
  \r
773
- `),t.destroy();return}let r=Mk(e.url);if(!r.ok){t.write(`HTTP/1.1 ${r.status} ${r.status===400?"Bad Request":"Not Found"}\r
777
+ `),t.destroy();return}let r=Vk(e.url);if(!r.ok){t.write(`HTTP/1.1 ${r.status} ${r.status===400?"Bad Request":"Not Found"}\r
774
778
  \r
775
- `),t.destroy();return}let o=r.sessionName;if(!je(o)){t.write(`HTTP/1.1 400 Bad Request\r
779
+ `),t.destroy();return}let o=r.sessionName;if(!De(o)){t.write(`HTTP/1.1 400 Bad Request\r
776
780
  \r
777
- `),t.destroy();return}let{cols:s,rows:a}=r;y6.handleUpgrade(e,t,n,i=>$k(i,o,{cols:s,rows:a}))};RO.on("upgrade",OO);var MO=process.env.BOSTRAT_CERT_DIR||Te.join(process.env.HOME||$p.tmpdir(),".bostrat","certs"),hO=Number(process.env.BOSTRAT_TLS_PORT)||3443,wO=Te.join(MO,"bostrat.globopi.key"),gO=Te.join(MO,"bostrat.globopi.crt");if(gt.existsSync(wO)&&gt.existsSync(gO)){let e=a6.createServer({key:gt.readFileSync(wO),cert:gt.readFileSync(gO)},S);e.on("upgrade",OO),e.on("error",t=>{console.error(`[bostrat-agent] https listener failed (${t?.code||t?.message}) \u2014 continuing HTTP-only`)}),e.listen(hO,Rp,()=>{console.log(`[bostrat-agent] https listening on ${Rp||"0.0.0.0"}:${hO}`)})}RO.listen(dO,Rp,()=>{console.log(`[bostrat-agent] listening on ${Rp||"0.0.0.0"}:${dO}`);let e=q_(process.env);e&&console.warn(`[bostrat-agent] \u26A0 SECURITY: plane-linked node bound to ${e.host?e.host:"ALL interfaces (BOSTRAT_HOST=all)"} \u2014 the API + Views are reachable off-loopback (LAN/VPN), where the IP allowlist is spoofable and Views need no token. The plane tunnel does not require this; set BOSTRAT_HOST=127.0.0.1 once any local reverse-proxy/WireGuard path is retired (F-2).`),console.log(`[bostrat-agent] tmux socket: ${Rt}`),console.log(`[bostrat-agent] auto-trigger default: ${bO}%`),console.log(`[bostrat-agent] ip allowlist: ${Da.open?"OPEN":process.env.BOSTRAT_ALLOW_IPS||"CLOSED (BOSTRAT_ALLOW_IPS unset)"}`+(Zy.active?` \xB7 view front-door: ${process.env.BOSTRAT_VIEW_FRONT_CIDRS} (registered views only)`:"")),hg().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted handoff(s)")).catch(t=>console.error("[bostrat-agent] handoff reconcile failed:",t?.message||t)),xg().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted subtask(s)")).catch(t=>console.error("[bostrat-agent] subtask reconcile failed:",t?.message||t)),dg().then(t=>t&&console.log(`[bostrat-agent] healed ${t} half-demoted transferred track(s)`)).catch(t=>console.error("[bostrat-agent] demoted-track reconcile failed:",t?.message||t)).then(()=>pg()).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)),og().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)),E6(),U_({listTracks:we}),QE({trackOf:Ww}),x6(),v6(),A6(),Pv({listTracks:we,getTrack:se}).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)),KE()&&GE({listTracks:we}),fk().then(t=>console.log(`[bostrat-agent] git hook shims at ${t}`)).catch(t=>console.error("[bostrat-agent] git hook shims failed (commits go unstamped):",t?.message||t)),MR(),DR(),UI({resolveTrack:se}),XI({listTracks:we,createTrack:Md,archiveTrack:Zo,listRepos:Jn,resolveTrack:se,sayToLead:Dt,answerPrompt:$d,startLeadHandoff:Dd,interruptLead:Od,listSubtaskJobs:es,cancelSubtask:Ld,readEvents:K,appendEvent:M,divertShip:Ly,answerPrExists:Fy,knownAgents:Ac}),b6(),ci().then(t=>{t||console.warn(`[boot] no host tmux server on ${Rt} and auto-start failed \u2014 boxes cannot spawn until one runs`)}),YR(),process.env.BOSTRAT_PLANE_URL&&process.env.BOSTRAT_PLANE_TOKEN&&(Ba=Q_({url:process.env.BOSTRAT_PLANE_URL,token:process.env.BOSTRAT_PLANE_TOKEN,apiToken:Qy,nodeId:process.env.BOSTRAT_NODE_ID||$p.hostname(),name:process.env.BOSTRAT_NODE_NAME||$p.hostname(),listTracks:we,detectAgents:_d,sampleMetrics:m$,deliverySample:()=>kA(Vw()),onHashKey:hA,onTracksTransferred:bg,onDegraded:({since:t,unacked:n,oldestAgeMs:r,mode:o})=>{let s=Math.round(r/6e4),a=`${process.env.BOSTRAT_NODE_NAME||$p.hostname()} \u2192 plane spine sync has stalled: ${n} event(s) unanswered for ${s} min (${o} door). New Tracks won't open from the plane until it recovers; the node is redialing with backoff.`;console.error(`[plane-link] ${a}`),process.env.BOSTRAT_NTFY_URL&&fetch(process.env.BOSTRAT_NTFY_URL,{method:"POST",headers:{Title:"bostrat: plane sync stalled",Tags:"rotating_light"},body:a}).catch(()=>{}),mO=t},onRecovered:async({downMs:t})=>{let n=Math.round(t/6e4);process.env.BOSTRAT_NTFY_URL&&n>=5&&fetch(process.env.BOSTRAT_NTFY_URL,{method:"POST",headers:{Title:"bostrat: plane sync recovered",Tags:"white_check_mark"},body:`Spine sync to the plane recovered after ${n} min; the backlog is delivered.`}).catch(()=>{}),mO=null},onConnected:()=>{OR()},onUpdateAvailable:async t=>{try{Xy={latest:t.latest,current:t.current},await qn({...t,policy:vt()}),vt()==="auto"&&await vO({to:t.latest,from:t.current})}catch(n){console.error(`[plane-link] update notice failed: ${n?.message||n}`)}},onUpdatePolicy:t=>p6(t).catch(()=>{}),onHelloRefused:async({current:t,min:n,latest:r,installKind:o,fix:s})=>{try{let a=r||n;if(await qn({current:t,latest:a,min:n,installKind:o,required:!0,policy:vt(),status:"available",reason:"refused"}),vt()!=="off"&&a){let i=await zd({to:a,kind:en,reason:"hard-floor"});i.ok?(cl.cancel(),await qn({current:t,latest:a,min:n,installKind:o,required:!0,policy:vt(),status:"updating",reason:"hard-floor"})):console.error(`[self-update] hard-floor update not started: ${i.reason} \u2014 ${s}`)}}catch(a){console.error(`[plane-link] hard-floor handling failed: ${a?.message||a}`)}},updatePolicy:vt}),console.log(`[bostrat-agent] plane link \u2192 ${process.env.BOSTRAT_PLANE_URL}`),vs().catch(()=>{}),BE().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} runbooks to the plane`),()=>{}),HI().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} ticket links to the plane`),()=>{}),iE().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} mocks to the plane`),()=>{}),TE().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} flows to the plane`),()=>{}),AS().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} PR links to the plane`),()=>{}))});process.on("SIGTERM",()=>{try{Ba?.stop()}catch{}setTimeout(()=>process.exit(0),150)});function b6(){k6(),ud().catch(()=>{}),setInterval(()=>ud().catch(()=>{}),1e4)}function k6(){for(let e of["bostrat-view","bostrat-mock","bostrat-flow","bostrat-ticket","bostrat-circuit","bostrat-roadmap","bostrat-blueprint","bostrat-decision","bostrat-runbook","bostrat-loop","bostrat-followup","bostrat-ship","bostrat-status","bostrat-notify","bostrat-gmail","bostrat-changelog","gh"])try{let t=Te.resolve(yO,"..","bin",e),n=Te.join(process.env.HOME||"",".local","bin");if(!process.env.HOME||!gt.existsSync(t))continue;gt.mkdirSync(n,{recursive:!0});let r=Te.join(n,e);(gt.existsSync(r)?gt.readlinkSync(r):null)!==t&&(gt.rmSync(r,{force:!0}),gt.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 x6(){let e=!1,t=async()=>{if(!e){e=!0;try{let n=await we(),r=await g$({tracks:n});r.committed&&console.log(`[state-sync] committed (${r.staged} file(s) staged${r.pushed?", pushed":""})`)}catch{}finally{e=!1}}};setInterval(t,6e4),t()}function v6(){let e=null,t=async()=>{try{let n=Bs(),r=0,o=[],s=null,a=null;try{let u=await we(),d=await dy(u);r=d.fleet.unpricedTurns||0,o=d.fleet.unpricedModels||[],s=await h$(u,{days:7}),a=(await fy(u,{window:"7d"})).categorization}catch{}let i=[...n.problems,...a?.problems||[]];s&&!s.ok&&i.push(`${s.divergent} recent row(s) diverge from the table (implied-rate audit) \u2014 run \`npm run cost -- --audit\``);let c=o.filter(u=>u!=="unknown");c.length&&i.push(`${r} unpriced turn(s) \u2014 add rates for: ${c.join(", ")}`);let l=i.join(`
781
+ `),t.destroy();return}let{cols:s,rows:a}=r;j6.handleUpgrade(e,t,n,i=>Kk(i,o,{cols:s,rows:a}))};GO.on("upgrade",zO);var VO=process.env.BOSTRAT_CERT_DIR||Te.join(process.env.HOME||Kp.tmpdir(),".bostrat","certs"),RO=Number(process.env.BOSTRAT_TLS_PORT)||3443,OO=Te.join(VO,"bostrat.globopi.key"),MO=Te.join(VO,"bostrat.globopi.crt");if(yt.existsSync(OO)&&yt.existsSync(MO)){let e=E6.createServer({key:yt.readFileSync(OO),cert:yt.readFileSync(MO)},E);e.on("upgrade",zO),e.on("error",t=>{console.error(`[bostrat-agent] https listener failed (${t?.code||t?.message}) \u2014 continuing HTTP-only`)}),e.listen(RO,Gp,()=>{console.log(`[bostrat-agent] https listening on ${Gp||"0.0.0.0"}:${RO}`)})}GO.listen(EO,Gp,()=>{console.log(`[bostrat-agent] listening on ${Gp||"0.0.0.0"}:${EO}`);let e=oI(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: ${Dt}`),console.log(`[bostrat-agent] auto-trigger default: ${NO}%`),console.log(`[bostrat-agent] ip allowlist: ${Ka.open?"OPEN":process.env.BOSTRAT_ALLOW_IPS||"CLOSED (BOSTRAT_ALLOW_IPS unset)"}`+(mb.active?` \xB7 view front-door: ${process.env.BOSTRAT_VIEW_FRONT_CIDRS} (registered views only)`:"")),Mg().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted handoff(s)")).catch(t=>console.error("[bostrat-agent] handoff reconcile failed:",t?.message||t)),kg().then(t=>t&&console.log(`[bostrat-agent] rolled back ${t} interrupted reshape(s)`)).catch(t=>console.error("[bostrat-agent] reshape reconcile failed:",t?.message||t)),jg().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted subtask(s)")).catch(t=>console.error("[bostrat-agent] subtask reconcile failed:",t?.message||t)),Ig().then(t=>t&&console.log(`[bostrat-agent] healed ${t} half-demoted transferred track(s)`)).catch(t=>console.error("[bostrat-agent] demoted-track reconcile failed:",t?.message||t)).then(()=>$g()).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)),xg().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)),G6(),nI({listTracks:he}),h_({trackOf:og}),U6(),H6(),K6(),Xv({listTracks:he,getTrack:ce}).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)),s_()&&c_({listTracks:he}),$k().then(t=>console.log(`[bostrat-agent] git hook shims at ${t}`)).catch(t=>console.error("[bostrat-agent] git hook shims failed (commits go unstamped):",t?.message||t)),zR(),XR(),n$({resolveTrack:ce}),p$({listTracks:he,createTrack:Gd,archiveTrack:us,listRepos:Zn,resolveTrack:ce,sayToLead:Ft,answerPrompt:Ud,startLeadHandoff:Yd,interruptLead:Wd,listSubtaskJobs:ps,cancelSubtask:tp,readEvents:K,appendEvent:M,divertShip:tb,answerPrExists:nb,knownAgents:Mc}),L6(),wi().then(t=>{t||console.warn(`[boot] no host tmux server on ${Dt} and auto-start failed \u2014 boxes cannot spawn until one runs`)}),dO(),process.env.BOSTRAT_PLANE_URL&&process.env.BOSTRAT_PLANE_TOKEN&&(Ga=mI({url:process.env.BOSTRAT_PLANE_URL,token:process.env.BOSTRAT_PLANE_TOKEN,apiToken:hb,nodeId:process.env.BOSTRAT_NODE_ID||Kp.hostname(),name:process.env.BOSTRAT_NODE_NAME||Kp.hostname(),listTracks:he,detectAgents:Ld,sampleMetrics:$$,deliverySample:()=>PT(cg()),onHashKey:RT,onTracksTransferred:Dg,onDegraded:({since:t,unacked:n,oldestAgeMs:r,mode:o})=>{let s=Math.round(r/6e4),a=`${process.env.BOSTRAT_NODE_NAME||Kp.hostname()} \u2192 plane spine sync has stalled: ${n} event(s) unanswered for ${s} min (${o} door). New Tracks won't open from the plane until it recovers; the node is redialing with backoff.`;console.error(`[plane-link] ${a}`),process.env.BOSTRAT_NTFY_URL&&fetch(process.env.BOSTRAT_NTFY_URL,{method:"POST",headers:{Title:"bostrat: plane sync stalled",Tags:"rotating_light"},body:a}).catch(()=>{}),$O=t},onRecovered:async({downMs:t})=>{let n=Math.round(t/6e4);process.env.BOSTRAT_NTFY_URL&&n>=5&&fetch(process.env.BOSTRAT_NTFY_URL,{method:"POST",headers:{Title:"bostrat: plane sync recovered",Tags:"white_check_mark"},body:`Spine sync to the plane recovered after ${n} min; the backlog is delivered.`}).catch(()=>{}),$O=null},onConnected:()=>{GR()},onUpdateAvailable:async t=>{try{fb={latest:t.latest,current:t.current},await Gn({...t,policy:At()}),At()==="auto"&&await BO({to:t.latest,from:t.current})}catch(n){console.error(`[plane-link] update notice failed: ${n?.message||n}`)}},onUpdatePolicy:t=>M6(t).catch(()=>{}),onHelloRefused:async({current:t,min:n,latest:r,installKind:o,fix:s})=>{try{let a=r||n;if(await Gn({current:t,latest:a,min:n,installKind:o,required:!0,policy:At(),status:"available",reason:"refused"}),At()!=="off"&&a){let i=await lp({to:a,kind:nn,reason:"hard-floor"});i.ok?(pl.cancel(),await Gn({current:t,latest:a,min:n,installKind:o,required:!0,policy:At(),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:At}),console.log(`[bostrat-agent] plane link \u2192 ${process.env.BOSTRAT_PLANE_URL}`),Ns().catch(()=>{}),XE().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} runbooks to the plane`),()=>{}),r$().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} ticket links to the plane`),()=>{}),xE().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} mocks to the plane`),()=>{}),jE().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} flows to the plane`),()=>{}),FS().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} PR links to the plane`),()=>{}))});process.on("SIGTERM",()=>{try{Ga?.stop()}catch{}setTimeout(()=>process.exit(0),150)});function L6(){F6(),wd().catch(()=>{}),setInterval(()=>wd().catch(()=>{}),1e4)}function F6(){for(let e of["bostrat-view","bostrat-mock","bostrat-flow","bostrat-ticket","bostrat-circuit","bostrat-roadmap","bostrat-blueprint","bostrat-decision","bostrat-runbook","bostrat-loop","bostrat-followup","bostrat-ship","bostrat-status","bostrat-notify","bostrat-gmail","bostrat-changelog","gh"])try{let t=Te.resolve(CO,"..","bin",e),n=Te.join(process.env.HOME||"",".local","bin");if(!process.env.HOME||!yt.existsSync(t))continue;yt.mkdirSync(n,{recursive:!0});let r=Te.join(n,e);(yt.existsSync(r)?yt.readlinkSync(r):null)!==t&&(yt.rmSync(r,{force:!0}),yt.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 U6(){let e=!1,t=async()=>{if(!e){e=!0;try{let n=await he(),r=await M$({tracks:n});r.committed&&console.log(`[state-sync] committed (${r.staged} file(s) staged${r.pushed?", pushed":""})`)}catch{}finally{e=!1}}};setInterval(t,6e4),t()}function H6(){let e=null,t=async()=>{try{let n=Vs(),r=0,o=[],s=null,a=null;try{let u=await he(),d=await _y(u);r=d.fleet.unpricedTurns||0,o=d.fleet.unpricedModels||[],s=await R$(u,{days:7}),a=(await $y(u,{window:"7d"})).categorization}catch{}let i=[...n.problems,...a?.problems||[]];s&&!s.ok&&i.push(`${s.divergent} recent row(s) diverge from the table (implied-rate audit) \u2014 run \`npm run cost -- --audit\``);let c=o.filter(u=>u!=="unknown");c.length&&i.push(`${r} unpriced turn(s) \u2014 add rates for: ${c.join(", ")}`);let l=i.join(`
778
782
  `);if(!i.length){e!==""&&console.log(`[pricing] table ok \u2014 rates verified ${n.tableVerifiedAt??"never"}`),e="";return}for(let u of i)console.warn(`[pricing] \u26A0 ${u}`);l!==e&&process.env.BOSTRAT_NTFY_URL&&fetch(process.env.BOSTRAT_NTFY_URL,{method:"POST",headers:{Title:"bostrat: cost instrument needs attention",Tags:"warning"},body:i.join(`
779
- `).slice(0,900)}).catch(()=>{}),e=l}catch(n){console.warn(`[pricing] watch failed: ${n?.message||n}`)}};setInterval(t,1440*60*1e3),setTimeout(t,3e4)}var S6=Number(process.env.BOSTRAT_MEMORY_RECONCILE_MS)||5*6e4,T6=Number(process.env.BOSTRAT_MEMORY_RECONCILE_FIRST_MS)||5*6e4;function A6(){let e=async()=>{try{let n=await Vb();n.ran&&console.log(`[memory] one-time full backfill sweep: ${n.harvested} fact(s) harvested`);let o=(await we()).filter(a=>!De(a)&&a.kind!=="setup").flatMap(a=>[a.cwd,...(a.boxes||[]).map(i=>i.cwd)]).filter(Boolean),s=await zb([...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,S6).unref()},T6).unref()}function E6(){let e=!1;setInterval(async()=>{if(!e){e=!0;try{let t=await we();for(let n of t)De(n)||!n.boxes?.some(r=>r.state==="live")||(await Id(n.id).catch(()=>{}),await pd(n).catch(()=>{}))}catch{}finally{e=!1}}},4e3)}
783
+ `).slice(0,900)}).catch(()=>{}),e=l}catch(n){console.warn(`[pricing] watch failed: ${n?.message||n}`)}};setInterval(t,1440*60*1e3),setTimeout(t,3e4)}var W6=Number(process.env.BOSTRAT_MEMORY_RECONCILE_MS)||5*6e4,q6=Number(process.env.BOSTRAT_MEMORY_RECONCILE_FIRST_MS)||5*6e4;function K6(){let e=async()=>{try{let n=await uk();n.ran&&console.log(`[memory] one-time full backfill sweep: ${n.harvested} fact(s) harvested`);let o=(await he()).filter(a=>!je(a)&&a.kind!=="setup").flatMap(a=>[a.cwd,...(a.boxes||[]).map(i=>i.cwd)]).filter(Boolean),s=await lk([...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,W6).unref()},q6).unref()}function G6(){let e=!1;setInterval(async()=>{if(!e){e=!0;try{let t=await he();for(let n of t)je(n)||!n.boxes?.some(r=>r.state==="live")||(await Fd(n.id).catch(()=>{}),await yd(n).catch(()=>{}))}catch{}finally{e=!1}}},4e3)}